Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

VB.NET MVVM Toolkit Demo

5.00/5 (3 votes)
23 Oct 2023CPOL4 min read 8.9K   372  
How to get started using the MVVM Toolkit
There are many CodeProject articles about other MVVM frameworks, but almost nothing with WPF and the MVVM Toolkit. So I started to create this document.

Image 1

Introduction

This tip and the demo is about getting started using the MVVM Toolkit and some self-created interfaces / services for MessageBox and some dialogs.

Background

There are many CodeProject articles about other MVVM frameworks, but almost nothing with WPF and the MVVM Toolkit. So I started to create this document.

I will not describe and explain the complete demo project. The focus is on how to test some of the features.

MVVM Structure / Features

The MVVM Toolkit is from Microsoft and also some of the other used features are not my own: Sources as listed in the Credits / Reference section.

Here is a quick overview of the contents:

  • MVVM Toolkit and .NET 4.7
    • RelayCommand
    • OnPropertyChanged
    • ObservableRecipient (Messenger and ViewModelBase)
    • DependencyInjection (to run MsgBox and Dialogs as a service)
    • ObservableCollection (for Credits Listbox)
  • Ribbon Menu
  • Services / dialogs
  • Using ICommand to bind buttons to the ViewModel

Installation of the MVVM Toolkit

With the installation of the NuGet package of the MVVM Toolkit, it installs 6 or 7 other packages.

Introduction to the MVVM Toolkit - Windows Community Toolkit | Microsoft Docs

Image 2

For DependencyInjection, we need to install another NuGet package:

Image 3

And I made interfaces / services for MsgBox and some dialogs.

DependencyInjection manages to start the following dialogs independent from the viewmodels:

  • MsgBoxService
  • DialogVM
  • OpenFileDlgVM
  • SaveAsFileDlgVM
  • SearchDlgVM

This allows the usage of custom Messageboxes / dialogs as well as Unit Testing.

MainWindow Concept and Code

MainWindow hosts the Ribbon.

Below that, there is a Tabcontrol, the structure is like this:

Image 4

Application

Registering the services / viewmodels is in the Application code behind.

There is also code for Restore QuickAccessToolBar State when the application starts and saving QAT State when the App closes.

Mod_Public

Mod_Public includes Property sAppPath and Public Sub ErrHandler:

VB.NET
Public Property sAppPath As String
  
Public Sub ErrHandler(sErr As String)
 
    IO.File.AppendAllText(sAppPath & "\Log.txt", _
    String.Format("{0}{1}", Environment.NewLine, Now.ToString & "; " & sErr))
    Dim msgBoxService As IMsgBoxService = Ioc.[Default].GetService(Of IMsgBoxService)()
    msgBoxService.Show("Unexpected error:" & vbNewLine & _
    vbNewLine & sErr,,, Windows.MessageBoxImage.Error)
 
End Sub

MVVM Pattern - Details

From the WPF Ribbon’s point of view, the data structure / model is simple:

The Usercontrol has menu items / ribbon buttons which work together with the TextBox and other controls.

That is what we see in model class TextData.

Model class called TextData

Imports System.Windows.Controls.Ribbon

VB.NET
Public Class TextData
    Inherits ObservableRecipient
    Implements INotifyPropertyChanged
 
    Private _AppPath As String
    Private _text As String
    Private _NotifyTest As RibbonTextBox
 
    Private _readText As String
 
    Private _ActiveTextBox As TextBox
 
    Dim _MyRibbonWPF As Ribbon
    Dim _MyMainWindow As MainWindow
 
    Public Sub New()
        '
    End Sub
 
    Public Property MyMainWindow As MainWindow
        Get
            Return _MyMainWindow
        End Get
        Set(value As MainWindow)
            _MyMainWindow = value
        End Set
    End Property
 
    Public Property MyRibbonWPF() As Ribbon
        Get
            Return _MyRibbonWPF
        End Get
        Set(value As Ribbon)
            _MyRibbonWPF = value
        End Set
    End Property
 
    Public Property NotifyTestbox As RibbonTextBox
        Get
            Return _NotifyTest
        End Get
        Set(value As RibbonTextBox)
            _NotifyTest = value
        End Set
    End Property
 
    Public Property GetText As String
        Get
            Return _text
        End Get
        Set(value As String)
            _text = value
            OnPropertyChanged("GetText")
        End Set
    End Property
 
    Public Property ReadText As String
        Get
            Return _readText
        End Get
        Set(value As String)
            _readText = value
            GetText = _readText
            OnPropertyChanged("ReadText")
        End Set
    End Property 
 
    Public Property ActiveTextBox() As TextBox
        Get
            Return _ActiveTextBox
        End Get
        Set(value As TextBox)
            _ActiveTextBox = value
        End Set
    End Property
 
End Class

ViewModel class called TestingViewModel

The class called TestingViewModel contains properties, ICommands and methods for the testing of some MVVM features.

It contains also code for the ObservableCollection(Of Credits), which is used for the Listview with the References / Credits for this article.

Putting Things Together

DependencyInjection or ServiceInjection

As already mentioned, there is some code for this in code behind of the Application.

Save File Dialog Example with ISaveAsFileDlgVM

It uses interface ISaveAsFileDlgVM and service / viewmodel SaveAsFileDlgVM.

VB.NET
Dim cmdSAFD As New RelayCommand(AddressOf SaveAsFileDialog)
SaveAsFileDlgCommand = cmdSAFD
VB.NET
Private Sub SaveAsFileDialog()
 
    Dim dialog As ISaveAsFileDlgVM = Ioc.[Default].GetService(Of ISaveAsFileDlgVM)()
    dialog.SaveAsFileDlg(_textData.GetText)
 
End Sub

And, very important, Command="{Binding SaveAsFileDlgCommand}" in the XAML file.

XML
<RibbonButton x:Name="SaveAs" Content="RibbonButton" HorizontalAlignment="Left" 
                Height="Auto" Margin="94,24,-162,-70" VerticalAlignment="Top" 
                Width="80" Label=" Save As" KeyTip="S" 
                AutomationProperties.AccessKey="S" 
                AutomationProperties.AcceleratorKey="S" 
                SmallImageSource="Images/save16.png" 
                CanAddToQuickAccessToolBarDirectly="False" 
                ToolTipTitle="Save As" Command="{Binding SaveAsFileDlgCommand}"/>

From the Ribbon, you can start and test other dialogs or the messagebox with:

  • Open Dialog
  • Search (only a dummy dialog)
  • OpenFileDialog
  • Tab Help > Info

Messenger Test

It is important to add Inherits ObservableRecipient, this and other details are described in ObservableObject - Windows Community Toolkit | Microsoft Docs.

„View specific messages should be registered In the Loaded Event Of a view And deregistered In the Unloaded Event To prevent memory leaks And problems multiple callback registrations“.

We send a msg from Class OpenFileDlgVM:

VB.NET
Public Class OpenFileDlgVM
    Inherits ObservableRecipient
    Implements IOpenFileDlgVM
 
    Private msg As String
 
    Public Sub New()
        '
    End Sub
 
    Public Function OpenFileDlg() As String Implements IOpenFileDlgVM.OpenFileDlg
 
        Dim dialog As FileDialog = New OpenFileDialog()
 
        Try
            dialog.Filter = "All Files(*.*)|*.*|RTF Files (*.rtf)|*.rtf"
            dialog.FilterIndex = 1
            dialog.Title = "Open File"
            dialog.DefaultExt = "rtf"
 
            dialog.ShowDialog()
 
            If dialog.FileName = "" Then Exit Function
 
            Dim strExt As String
            strExt = System.IO.Path.GetExtension(dialog.FileName)
            strExt = strExt.ToUpper()
 
            Dim currentFile As String = dialog.FileName
 
            msg = "OpenFileDlg TEST Msg" 'ReadTextLines(dialog.FileName)
            SetStatus("TestingViewModel", msg)
 
            Return currentFile
 
        Catch ex As Exception
 
            IO.File.AppendAllText(sAppPath & "\Log.txt", String.Format("{0}{1}", _
            Environment.NewLine, Now.ToString & "; " & ex.ToString()))
            Dim MsgCmd As RelayCommand(Of String) = New RelayCommand(Of [String])_
            (Function(m) MessageBox.Show("Unexpected error:" & vbNewLine & _
                                          vbNewLine & ex.ToString))
            MsgCmd.Execute("")
        End Try
 
    End Function
 
    Public Sub SetStatus(r As String, m As String)
 
        Try
            Dim s = Messenger.Send(New DialogMessage(m))
 
        Catch ex As Exception
            SetStatus("OpenFileDlgVM", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
 
    End Sub
 
End Class
 
Public Class DialogMessage
    Public Sub New(status As String)
        NewStatus = status
    End Sub
 
    Public Property NewStatus As String
End Class

to another viewmodel, what is only possible if the message is registered:

VB.NET
Imports Microsoft.Toolkit.Mvvm.Messaging
 
Public Class TestingViewModel
    Inherits ObservableRecipient
VB.NET
Public Sub New()

     Try
...
         Messenger.Register(Of DialogMessage)(Me, Sub(r, m) r.DialogMessage = m.NewStatus)
...

Protected Overrides Sub Finalize()
    Messenger.Unregister(Of DialogMessage)(Me)
    MyBase.Finalize()
End Sub

On closing the viewmodel, we have to unregister the message.

The message appears on StatusBar and the Ribbon.

PropertyChanged Test

If you edit the upper one on the textboxes manually, you can see that the lower one‘s content is changed immediately.

This is caused by UpdateSourceTrigger=PropertyChanged in the XAML file.

Image 5

EventTrigger

Requirements: Microsoft.Xaml.Behaviors.Wpf (NuGet package):

XML
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
...
<Window.DataContext>
        <local:TestingViewModel/>
    </Window.DataContext>
                
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="Closing">
            <b:InvokeCommandAction Command="{Binding ExitApp, Mode=OneWay}"/>
        </b:EventTrigger>
        <b:EventTrigger EventName="Loaded">
            <b:InvokeCommandAction Command="{Binding Apploaded, Mode=OneWay}"/>
        </b:EventTrigger>
    </b:Interaction.Triggers>

This is used for the code to control the QuickAccessToolbar.

ObservableCollection

It is part of viewmodel TestingViewModel and used for the listbox with Credits / References.

VB.NET
Public Class TestingViewModel
    Inherits ObservableRecipient
    Implements INotifyPropertyChanged
 
#Region " fields"
 
    Private _credit As New ObservableCollection(Of Credits)
    Private _textData As New TextData
 
    Private msg As String
    Private _text As String
    Private _dialogMessage As String
    Private _OnPropertyChangedTest As String
 
#End Region
 
#Region " constructors"
 
    Public Sub New()
 
        Try
            MyMainWindow = Windows.Application.Current.MainWindow
 
            Messenger.Register(Of DialogMessage)(Me, Sub(r, m) r.DialogMessage = m.NewStatus)
            Messenger.Register(Of StatusMessage)_
                              (Me, Sub(r, m) r.StatusBarMessage = m.NewStatus)
 
            _credit = New ObservableCollection(Of Credits)() From {
            New Credits() With {
                .Item = "MVVM Toolkit",
                .Note = "Microsoft",
                .Link = "https://docs.microsoft.com/en-us/windows/_
                         communitytoolkit/mvvm/introduction"
            },
            New Credits() With {
                .Item = "MVVMLight",
                .Note = "GalaSoft",
                .Link = "https://www.codeproject.com/Articles/768427/The-big-MVVM-Template"
            },
            New Credits() With {
                .Item = "ICommand with MVVM pattern",
                .Note = "CPOL",
                .Link = "https://www.codeproject.com/Articles/863671/
                         Using-ICommand-with-MVVM-pattern"
            },
            New Credits() With {
                .Item = "C# WPF WYSIWYG HTML Editor - CodeProject",
                .Note = "CPOL",
                .Link = "https://www.codeproject.com/Tips/870549/_
                         Csharp-WPF-WYSIWYG-HTML-Editor"
            }
        }
 
            Dim cmdSearch As New RelayCommand(AddressOf SearchDialog)
            SearchDlgCommand = cmdSearch
 
            Dim cmdOFD As New RelayCommand(AddressOf OpenFileDialog)
            OpenFileDlgCommand = cmdOFD
 
            Dim cmdSAFD As New RelayCommand(AddressOf SaveAsFileDialog)
            SaveAsFileDlgCommand = cmdSAFD
 
            Dim cmdI As New RelayCommand(AddressOf OpenUserInput)
            OpenUserInputCommand = cmdI
 
            GetCredits = _credit
            SaveXml_Click()
 
        Catch ex As Exception
            IO.File.AppendAllText(sAppPath & "\Log.txt", _
            String.Format("{0}{1}", Environment.NewLine, _
            Now.ToString & "; " & ex.ToString()))
            Dim msgBoxService As IMsgBoxService = Ioc.[Default].GetService(Of IMsgBoxService)()
            msgBoxService.Show("Unexpected error:" & vbNewLine & _
            vbNewLine & ex.ToString,,, Windows.MessageBoxImage.Error)
        End Try
 
    End Sub
 
#End Region 
 
#Region " properties"
 
    Dim _cmdN As New Command(AddressOf New_Click)
    Dim _cmdE As New Command(AddressOf Exit_Click)
    Dim _cmdD As New Command(AddressOf Print_Click)
    Dim _cmdI As New Command(AddressOf Info_Click)
 
    Dim _cmdBG As New Command(AddressOf BackgroundGreenRibbonButton_Click)
    Dim _cmdBW As New Command(AddressOf BackgroundWhiteRibbonButton_Click)
    Dim _cmdQAT As New Command(AddressOf RestoreQAT_Click)
 
    Dim _cmdMsg As New Command(AddressOf SendMsgRibbonButton_Click)
    Dim _cmdErr As New Command(AddressOf GetErrorButton_Click)
    Dim _cmdClear As New Command(AddressOf ClearListboxButton_Click)
    Dim _cmdLog As New Command(AddressOf ReadLog_Click)
    Dim _cmdReadXml As New Command(AddressOf ReadXml_Click)
    Dim _cmdSaveXml As New Command(AddressOf SaveXml_Click)
 
    Dim _cmdL As New Command(AddressOf App_Loaded)
 
    Public Property SearchDlgCommand() As ICommand
    Public Property OpenUserInputCommand() As ICommand
    Public Property RibbonToFormCommand() As ICommand
    Public Property OpenFileDlgCommand() As ICommand
    Public Property SaveAsFileDlgCommand() As ICommand
    Public Property PrintFileDlgCommand() As ICommand
 
    Public Property MyMainWindow As MainWindow
        Get
            Return _textData.MyMainWindow
        End Get
        Set(value As MainWindow)
            _textData.MyMainWindow = value
            If MyMainWindow.RibbonWPF Is Nothing Then MyRibbonWPF = MyMainWindow.RibbonWPF
        End Set
    End Property
 
    Public Property MyRibbonWPF As Ribbon
        Get
            Return _textData.MyRibbonWPF
        End Get
        Set(value As Ribbon)
            _textData.MyRibbonWPF = value
        End Set
    End Property
 
    Public Property ActiveTextBox() As TextBox
        Get
            Return _textData.ActiveTextBox
        End Get
        Set(value As TextBox)
            _textData.ActiveTextBox = value
            OnPropertyChanged("ActiveTextBox")
        End Set
    End Property
 
    Public Property GetText As String
        Get
            Return _text
        End Get
        Set(value As String)
            _text = value
            _textData.GetText = value
            OnPropertyChanged("GetText")
        End Set
    End Property
 
    Public Property OnPropertyChangedTest As String
        Get
            Return _OnPropertyChangedTest
        End Get
        Set(value As String)
            _OnPropertyChangedTest = value
            OnPropertyChanged("OnPropertyChangedTest")
        End Set
    End Property
 
    Public Property NotifyTestbox As RibbonTextBox
        Get
            Return _textData.NotifyTestbox
        End Get
        Set(value As RibbonTextBox)
            _textData.NotifyTestbox = value
            OnPropertyChanged("NotifyTestbox")
        End Set
    End Property
 
    Public Property GetCredits As ObservableCollection(Of Credits)
        Get
            Return _credit
        End Get
        Set(value As ObservableCollection(Of Credits))
            _credit = value
            OnPropertyChanged("GetCredits")
        End Set
    End Property
 
    Public ReadOnly Property SaveXml As ICommand
        Get
            Return _cmdSaveXml
        End Get
    End Property
 
    Public ReadOnly Property ReadXml As ICommand
        Get
            Return _cmdReadXml
        End Get
    End Property
 
    Public ReadOnly Property ReadLog As ICommand
        Get
            Return _cmdLog
        End Get
    End Property
 
    Public ReadOnly Property SendMsg As ICommand
        Get
            Return _cmdMsg
        End Get
    End Property
 
    Public ReadOnly Property GetError As ICommand
        Get
            Return _cmdErr
        End Get
    End Property
 
    Public ReadOnly Property ClearListbox As ICommand
        Get
            Return _cmdClear
        End Get
    End Property
 
    Public ReadOnly Property GreenBackground() As ICommand
        Get
            Return _cmdBG
        End Get
    End Property
 
    Public ReadOnly Property WhiteBackground() As ICommand
        Get
            Return _cmdBW
        End Get
    End Property
 
    Public ReadOnly Property RestoreQAT() As ICommand
        Get
            Return _cmdQAT
        End Get
    End Property
 
    Public ReadOnly Property Info As ICommand
        Get
            Return _cmdI
        End Get
    End Property
 
    Public ReadOnly Property NewFile As ICommand
        Get
            Return _cmdN
        End Get
    End Property
 
    Public ReadOnly Property ExitApp As ICommand
        Get
            Return _cmdE
        End Get
    End Property
 
    Public ReadOnly Property Apploaded As ICommand
        Get
            Return _cmdL
        End Get
    End Property
 
    Public ReadOnly Property Print As ICommand
        Get
            Return _cmdD
        End Get
    End Property
  
#End Region 
 
#Region " Dialogs"
 
    Private Sub SearchDialog()
 
        Dim dialog As ISearchDlgVM = Ioc.[Default].GetService(Of ISearchDlgVM)()
        dialog.SearchDlg()
    End Sub
 
    Private Sub OpenFileDialog()
 
        Dim dialog As IOpenFileDlgVM = Ioc.[Default].GetService(Of IOpenFileDlgVM)()
        Dim sPath As String = dialog.OpenFileDlg()
        If Len(sPath) > 1 Then GetText = ReadTextLines(sPath)
 
    End Sub
 
    Private Sub SaveAsFileDialog()
 
        Dim dialog As ISaveAsFileDlgVM = Ioc.[Default].GetService(Of ISaveAsFileDlgVM)()
        dialog.SaveAsFileDlg(_textData.GetText)
 
    End Sub
 
    Private Sub OpenUserInput()
 
        Dim dialog As IDialog = Ioc.[Default].GetService(Of IDialog)()
        dialog.ShowMyDialog()
 
    End Sub
 
#End Region 
 
#Region " methods"
 
    Private Sub RestoreQAT_Click()
 
        Try
            If MyMainWindow.RibbonWPF IsNot Nothing Then
                MyRibbonWPF = MyMainWindow.RibbonWPF
            End If
 
            If MyMainWindow.AppCmdNewQAT.IsLoaded = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Add(MyMainWindow.AppCmdNewQAT)
            End If
            If MyMainWindow.AppCmdOpenQAT.IsLoaded = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Add(MyMainWindow.AppCmdOpenQAT)
            End If
            If MyMainWindow.AppCmdSaveAsQAT.IsLoaded = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Add(MyMainWindow.AppCmdSaveAsQAT)
            End If
            If MyMainWindow.AppCmdCloseQAT.IsLoaded = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Add(MyMainWindow.AppCmdCloseQAT)
            End If
 
        Catch ex As Exception
            IO.File.AppendAllText(sAppPath & "\_Log.txt", _
            String.Format("{0}{1}", Environment.NewLine, _
            Now.ToString & "; " & ex.ToString()))
            Dim msgBoxService As IMsgBoxService = Ioc.[Default].GetService(Of IMsgBoxService)()
            msgBoxService.Show("Unexpected error:" & vbNewLine & _
            vbNewLine & ex.ToString,,, Windows.MessageBoxImage.Error)
        End Try
 
    End Sub
 
    Private Sub ClearListboxButton_Click()
        Try
            _credit = GetCredits
 
            ' Remove first line
            '_credit.RemoveAt(0)
 
            ' Remove all
            GetCredits.Clear()
 
        Catch ex As Exception
            SetStatus("TestingViewModel", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
    End Sub
 
    Private Sub SaveXml_Click()
        Try
            'Save to XML
            Dim xs As New XmlSerializer(GetType(ObservableCollection(Of Credits)))
            Using wr As New StreamWriter(sAppPath + "\MyCredits.xml")
                xs.Serialize(wr, _credit)
            End Using
 
        Catch ex As Exception
            SetStatus("TestingViewModel", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
    End Sub
 
    Private Sub ReadXml_Click()
        Try
            GetCredits.Clear()
            'read xml
            Dim xs As New XmlSerializer(GetType(ObservableCollection(Of Credits)))
            Using rd As New StreamReader(sAppPath + "\MyCredits.xml")
                GetCredits = TryCast(xs.Deserialize(rd), ObservableCollection(Of Credits))
            End Using
 
        Catch ex As Exception
            SetStatus("TestingViewModel", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
    End Sub
 
    Private Sub ReadLog_Click()
        Try
 
            GetText = ReadTextLines(sAppPath & "\Log.txt")
 
        Catch ex As Exception
            SetStatus("TestingViewModel", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
    End Sub
 
    Private Sub Info_Click()
        msg = "Demo created by Jo_vb.net, v1.0, Feb. 2022, License CPOL."
        Dim msgBoxService As IMsgBoxService = Ioc.[Default].GetService(Of IMsgBoxService)()
        msgBoxService.Show(vbNewLine & msg, "Info")
    End Sub
 
    Private Sub New_Click()
        Try
            GetText = vbNullString
        Catch ex As Exception
            IO.File.AppendAllText(sAppPath & "\_Log.txt", _
            String.Format("{0}{1}", Environment.NewLine, _
            Now.ToString & "; " & ex.ToString()))
            Dim msgBoxService As IMsgBoxService = _
                              Ioc.[Default].GetService(Of IMsgBoxService)()
            msgBoxService.Show("Unexpected error:" & vbNewLine & _
            vbNewLine & ex.ToString,,, Windows.MessageBoxImage.Error)
        End Try
 
    End Sub 
 
    Private Sub BackgroundGreenRibbonButton_Click()
        If MyMainWindow.RibbonWPF IsNot Nothing Then
            MyRibbonWPF = MyMainWindow.RibbonWPF
        End If
        MyRibbonWPF.Background = New SolidColorBrush(Color.FromRgb(120, 190, 96))
    End Sub
 
    Private Sub BackgroundWhiteRibbonButton_Click()
        If MyMainWindow.RibbonWPF IsNot Nothing Then
            MyRibbonWPF = MyMainWindow.RibbonWPF
        End If
        MyRibbonWPF.Background = New SolidColorBrush(Color.FromRgb(255, 255, 255))
    End Sub
 
    Private Sub Print_Click()
 
        msg = "Print Dialog dummy" & vbNewLine _
        & "You could try using" & _
        vbNewLine & "https://www.codeproject.com/Tips/829368/A-Simple-RTF-Print-Form"
        Dim msgBoxService As IMsgBoxService = Ioc.[Default].GetService(Of IMsgBoxService)()
        msgBoxService.Show(vbNewLine & msg, "Info")
 
        ' Print RichTextBox content
        ' https://www.codeproject.com/Tips/829368/A-Simple-RTF-Print-Form
    End Sub
 
    Private Sub App_Loaded()
        Try
            If MyMainWindow.RibbonWPF IsNot Nothing Then
                MyRibbonWPF = MyMainWindow.RibbonWPF
            End If
 
            If My.Settings.AppCmdNewQAT_Visible = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Remove(MyMainWindow.AppCmdNewQAT)
            End If
 
            If My.Settings.AppCmdOpenQAT_Visible = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Remove(MyMainWindow.AppCmdOpenQAT)
            End If
            If My.Settings.AppCmdSaveAsQAT_Visible = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Remove(MyMainWindow.AppCmdSaveAsQAT)
            End If
            If My.Settings.AppCmdCloseQAT_Visible = False Then
                MyRibbonWPF.QuickAccessToolBar.Items.Remove(MyMainWindow.AppCmdCloseQAT)
            End If
 
        Catch ex As Exception
            IO.File.AppendAllText(sAppPath & "\Log.txt", _
            String.Format("{0}{1}", Environment.NewLine, _
            Now.ToString & "; " & ex.ToString()))
            Dim msgBoxService As IMsgBoxService = _
                              Ioc.[Default].GetService(Of IMsgBoxService)()
            msgBoxService.Show("Unexpected error:" & _
            vbNewLine & vbNewLine & ex.ToString,,, Windows.MessageBoxImage.Error)
        End Try
 
    End Sub
 
    Private Sub Exit_Click()
 
        Try
            With MyMainWindow
                If .AppCmdNewQAT.IsLoaded = False Then
                    My.Settings.AppCmdNewQAT_Visible = False
                ElseIf .AppCmdNewQAT.IsLoaded = True Then
                    My.Settings.AppCmdNewQAT_Visible = True
                End If
 
                If .AppCmdOpenQAT.IsLoaded = False Then
                    My.Settings.AppCmdOpenQAT_Visible = False
                ElseIf .AppCmdOpenQAT.IsLoaded = True Then
                    My.Settings.AppCmdOpenQAT_Visible = True
                End If
 
                If .AppCmdSaveAsQAT.IsLoaded = False Then
                    My.Settings.AppCmdSaveAsQAT_Visible = False
                ElseIf .AppCmdSaveAsQAT.IsLoaded = True Then
                    My.Settings.AppCmdSaveAsQAT_Visible = True
                End If
 
                If .AppCmdCloseQAT.IsLoaded = False Then
                    My.Settings.AppCmdCloseQAT_Visible = False
                ElseIf .AppCmdCloseQAT.IsLoaded = True Then
                    My.Settings.AppCmdCloseQAT_Visible = True
                End If
            End With
 
            My.Settings.Save()
 
        Catch ex As Exception
            IO.File.AppendAllText(sAppPath & "\Log.txt", _
            String.Format("{0}{1}", Environment.NewLine, _
            Now.ToString & "; " & ex.ToString()))
        End Try
        Application.Current.Shutdown()
    End Sub
 
    Private Sub GetErrorButton_Click()
        Try
            Ioc.[Default].ConfigureServices(New ServiceCollection().AddSingleton_
            (Of IMsgBoxService, MsgBoxService)().AddSingleton(Of IMsgBoxService)_
            (New MsgBoxService()).BuildServiceProvider)
 
        Catch ex As Exception
            SetStatus("TestingViewModel", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
    End Sub
 
    Private Sub SendMsgRibbonButton_Click()
 
        Try
 
            ' DataExchange / Messenger
            Dim msg = "Test Msg..."
            SetStatus("TestingViewModel", msg)
 
        Catch ex As Exception
            SetStatus("TestingViewModel", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
 
    End Sub
 
    Public Sub SetStatus(ByVal r As String, ByVal m As String)
 
        Try
            Messenger.Send(New DialogMessage(m))
 
        Catch ex As Exception
            SetStatus("TestingViewModel", ex.ToString)
            ErrHandler(ex.ToString)
        End Try
 
    End Sub
 
#End Region 
 
#Region " Dialog Code"
 
    ' Used to bind any incoming dialog messages to the viewmodel.
 
    Public Property DialogMessage As String
        Get
            Return _dialogMessage
        End Get
        Set(value As String)
            'MsgBox("DialogMessage SET: " & value)
            If Equals(value, _dialogMessage) Then Return
            _dialogMessage = value
            GetText = value
            OnPropertyChanged("DialogMessage")
        End Set
    End Property
 
    Private _statusBarMessage As String
    Public Property StatusBarMessage As String
        Get
            Return _statusBarMessage
        End Get
        Set(ByVal value As String)
            If Equals(value, _statusBarMessage) Then Return
            _statusBarMessage = value
            OnPropertyChanged("StatusBarMessage")
        End Set
    End Property
 
    Protected Overrides Sub Finalize()
        Messenger.Unregister(Of StatusMessage)(Me)
        Messenger.Unregister(Of DialogMessage)(Me)
        MyBase.Finalize()
    End Sub
 
#End Region
 
End Class
 
Public Class StatusMessage
    Public Sub New(ByVal status As String)
        NewStatus = status
    End Sub
 
    Public Property NewStatus As String
End Class
 
Public Class Credits
    Public Property Item As String
    Public Property Note As String
    Public Property Link As String
 
End Class

...

Test with the ObservableCollection

Click on Clear Listbox, then delete the credits.

Read XML to Listbox restores the references.

Image 6

Another Test: Click on Read Log imports the log file to the textbox.

Image 7

Conclusion

This is only a rough demo – it is not production ready.

But I think the MVVM Toolkit allows you a variety of extensions.

Final Note

I am very interested in feedback of any kind - problems, suggestions and other.

Credits / Reference

History

  • 7th February, 2022 - Initial submission
  • 23rd October, 2023 - Version 2.1 - Because Microsoft.ToolKit.Mvvm has been deprecated, we now must use this alternate package: CommunityToolkit.Mvvm

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)