65.9K
CodeProject 正在变化。 阅读更多。
Home

WinForm VB.NET 托管 WPF Ribbon - 第 2 部分 - 使用 ICommand 和 MVVM 模式

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2022 年 1 月 11 日

CPOL

2分钟阅读

viewsIcon

6865

downloadIcon

171

我的想法是在 WinForm VB.NET 项目中托管带有 Ribbon 的 WPF 用户控件,并尝试使用 MVVM 模式。

引言

这篇文章和演示受到 CodeProject 文章的启发,使用 ICommand 和 MVVM 模式,它根据 MVVM 模式创建和使用 ICommand

我将那里的代码作为我自己的类/接口的模板。

背景

我的第一篇文章,WinForm VB.NET 托管 WPF Ribbon 侧重于一些基本工作,以使演示正常运行。

但我对 WinForm 和 WPF 用户控件之间的接口/通信不太满意。

在这里,我们只会讨论第一篇文章中缺失的内容和/或新内容或已更改的内容。

Winform 概念和代码

托管 WPF 用户控件所需的项目引用

  • PresentationCore
  • PresentationFramework
  • WindowsBase
  • WindowsFormsIntegration

检测 ActiveTextBoxActiveRichTextBox 的代码如下所示

Private Sub TextBox_Enter(ByVal sender As System.Object, ByVal e As System.EventArgs) _
  Handles PlainTextBox.MouseClick,
    PlainTextBox.Enter, PlainTextBox.MouseEnter, PlainTextBox.TextChanged

    _textData.ActiveTextBox = CType(sender, TextBox)
    _textData.ActiveRichTextBox = Nothing

    MyRibbonUserControl.StackpanelRT1.Visibility = Windows.Visibility.Hidden
    MyRibbonUserControl.StackpanelRT2.Visibility = Windows.Visibility.Hidden
    MyRibbonUserControl.ribbonComboBoxColor.Visibility = Windows.Visibility.Hidden
    MyRibbonUserControl.FontsDlgRibbonButton.Visibility = Windows.Visibility.Hidden
    MyRibbonUserControl.GraphicAlignRibbonButton.Visibility = Windows.Visibility.Hidden

End Sub

Private Sub RichTextBox_Enter(ByVal sender As System.Object, ByVal e As System.EventArgs) _
  Handles WinformRichTextBox.MouseClick,
    WinformRichTextBox.Enter, WinformRichTextBox.MouseEnter, WinformRichTextBox.TextChanged,
    LogRichTextBox.MouseClick, LogRichTextBox.Enter, _
    LogRichTextBox.MouseEnter, LogRichTextBox.TextChanged

    _textData.ActiveRichTextBox = CType(sender, RichTextBox)
    _textData.ActiveTextBox = Nothing

    MyRibbonUserControl.StackpanelRT1.Visibility = Windows.Visibility.Visible
    MyRibbonUserControl.StackpanelRT2.Visibility = Windows.Visibility.Visible
    MyRibbonUserControl.ribbonComboBoxColor.Visibility = Windows.Visibility.Visible
    MyRibbonUserControl.FontsDlgRibbonButton.Visibility = Windows.Visibility.Visible
    MyRibbonUserControl.GraphicAlignRibbonButton.Visibility = Windows.Visibility.Visible

End Sub

使用 ICommand 和 MVVM 模式

从 WPF Ribbon 的角度来看,数据结构/模型很简单

Usercontrol 具有与 ActiveRichTextBoxActiveTextBox 协同工作的菜单项/Ribbon 按钮。 这就是我们在 模型TextData 中看到的内容。

一些菜单项/命令已移动到 TextDataViewModel,除了所有的 Richtext 格式化 Ribbon 按钮。

有两个新类,TextDataViewModelTextData

Imports System.Windows.Controls.Ribbon

Public Class TextData

    Private _ActiveTextBox As TextBox
    Private WithEvents _ActiveRichTextBox As RichTextBox
    Private _AppPath As String
    Dim _MyRibbonWPF As Ribbon
    Dim _MyRibbonUserCtl As UserControlRibbonWPF

    Public Sub New()
        '
    End Sub

    Public Property MyRibbonUserCtl() As UserControlRibbonWPF
        Get
            Return _MyRibbonUserCtl
        End Get
        Set(value As UserControlRibbonWPF)
            _MyRibbonUserCtl = 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 AppPath() As String
        Get
            Return _AppPath
        End Get
        Set(value As String)
            _AppPath = value
        End Set
    End Property

    Public Property ActiveTextBox() As TextBox
        Get
            Return _ActiveTextBox
        End Get
        Set(value As TextBox)
            _ActiveTextBox = value
        End Set
    End Property

    Public Property ActiveRichTextBox() As RichTextBox
        Get
            Return _ActiveRichTextBox
        End Get
        Set(value As RichTextBox)
            _ActiveRichTextBox = value
        End Set
    End Property

End Class

TextDataViewModel 的第一部分,包含属性、ICommand 和方法。

Imports System.ComponentModel
Imports System.Windows.Controls.Ribbon
Imports System.Windows.Input
Imports System.Windows.Media

Public Class TextDataViewModel

    Implements INotifyPropertyChanged

#Region " fields"

    Private WithEvents _ActiveTextBox As TextBox
    Private WithEvents _ActiveRichTextBox As RichTextBox
    Dim _MyRibbonWPF As Ribbon
    Dim _MyRibbonUserCtl As UserControlRibbonWPF
    Private _AppPath As String = Application.StartupPath

#End Region

#Region " constructors"

    Public Sub New()
        '
    End Sub

#End Region

#Region " properties"

    Public Property MyRibbonUserControl() As UserControlRibbonWPF
        Get
            Return _textData.MyRibbonUserCtl
        End Get
        Set(value As UserControlRibbonWPF)
            _textData.MyRibbonUserCtl = value
        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 ActiveRichTextBox() As RichTextBox
        Get
            Return _textData.ActiveRichTextBox
        End Get
        Set(value As RichTextBox)
            _textData.ActiveRichTextBox = value
            NotifyPropertyChanged()
        End Set
    End Property

    Public Property ActiveTextBox() As TextBox
        Get
            Return _textData.ActiveTextBox
        End Get
        Set(value As TextBox)
            _textData.ActiveTextBox = value
            NotifyPropertyChanged()
        End Set
    End Property

    Public Property AppPath() As String
        Get
            Return _textData.AppPath
        End Get
        Set(value As String)
            _textData.AppPath = value
            NotifyPropertyChanged()
        End Set
    End Property

    Public Event PropertyChanged As PropertyChangedEventHandler _
           Implements INotifyPropertyChanged.PropertyChanged

    Private Sub NotifyPropertyChanged(Optional propertyName As String = "")
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Dim _cmdSA As New Command(AddressOf SaveAsFileDlg)
    Dim _cmdO As New Command(AddressOf OpenFileDlg)
    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 _cmdCut As New Command(AddressOf Cut_Click)
    Dim _cmdC As New Command(AddressOf Copy_Click)
    Dim _cmdP As New Command(AddressOf Paste_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)

示例 - 对于一个 iCommand,我们需要

Public ReadOnly Property ExitApp As ICommand
    Get
        Return _cmdE
    End Get
End Property

Dim _cmdE As New Command(AddressOf Exit_Click) 

Private Sub Exit_Click()
    AppForm.Close()
End Sub

另一个名为 RichDataViewModel 的新类包含用于 Richtext 菜单命令/Ribbon 按钮的属性、ICommand 和方法。

WPF 用户控件概念和代码

对于 UserCtlRibbonWPF,我们需要以下内容才能使 ICommand 可用

<UserControl.DataContext>
        <local:TextDataViewModel/>
</UserControl.DataContext>

当我们向 viewmodel 添加一个新的 property 时,我们必须创建一个新的构建(F5 调试是不够的),才能在设计器/界面中看到它。

在设计器中,我们现在可以连接菜单命令和界面。

用户控件背后的代码

Imports System.Windows

Public Class UserControlRibbonWPF

    ' Property variables
    Private _RibbonSizeIsMinimized As Boolean

    ' Internal variables
    Private sAppPath As String

#Region " constructors"

    Public Sub New()

        InitializeComponent()
        sAppPath = _textData.AppPath

    End Sub

#End Region

#Region " ApplicationCommands"

    ' now using iCommand

#End Region

#Region " RibbonControls"

    ' now using viewmodel and iCommand

#End Region

#Region " Properties"

    Public Property RibbonSizeIsMinimized() As Boolean
        Get
            Return _RibbonSizeIsMinimized
        End Get
        Set(ByVal value As Boolean)
            _RibbonSizeIsMinimized = value
        End Set
    End Property

#End Region

#Region " RibbonEvents"

    Private Sub RibbonWPF_MouseDoubleClick_
    (sender As Object, e As Windows.RoutedEventArgs) Handles RibbonWPF.MouseDoubleClick

        If RibbonWPF.IsMinimized = True Then
            _RibbonSizeIsMinimized = True
            AppForm.UserControlWPFisMinimized = True
        Else
            _RibbonSizeIsMinimized = False
            AppForm.UserControlWPFisMinimized = False
        End If

    End Sub

    Private Sub UserControlRibbonWPF_ContextMenuClosing_
            (sender As Object, e As EventArgs) Handles Me.ContextMenuClosing

        AppForm.UserControlWPFisMinimized = RibbonWPF.IsMinimized
        RibbonSizeIsMinimized = RibbonWPF.IsMinimized

    End Sub

#End Region

#Region " Form Events"

    Private Sub UserControlRibbonWPF_Loaded(sender As Object, e As RoutedEventArgs) _
            Handles Me.Loaded

        Try

            _textData.MyRibbonUserCtl = Me
            _textData.MyRibbonWPF = RibbonWPF

        Catch ex As Exception
            IO.File.AppendAllText(sAppPath & "\Log.txt", _
            String.Format("{0}{1}", Environment.NewLine, _
            Now.ToString & "; " & ex.ToString()))
        End Try

    End Sub

#End Region

#Region " RibbonSettings"

    ' moved to viewmodel

#End Region

End Class

模块 Mod_Public

Public _textData As New TextData
Public cTextDataVM As New TextDataViewModel

应用程序菜单的修改后的 XAML 代码

<Ribbon.ApplicationMenu>
            <RibbonApplicationMenu CanAddToQuickAccessToolBarDirectly="True">
                <RibbonApplicationMenuItem x:Name="AppCmdNew" Header="New" 
                 Command="{Binding NewFile, Mode=OneWay}" IsCheckable="False" 
                 ImageSource="Images/newdocument32.png" 
                 QuickAccessToolBarImageSource="Images/newdocument32.png" 
                 CanAddToQuickAccessToolBarDirectly="False" />
                <RibbonApplicationMenuItem x:Name="AppCmdOpen" Header="Open" 
                 Command="{Binding OpenFile, Mode=OneWay}" IsCheckable="False" 
                 ImageSource="Images/open16.png" 
                 QuickAccessToolBarImageSource="Images/open16.png" 
                 CanAddToQuickAccessToolBarDirectly="False" />
                <RibbonApplicationMenuItem x:Name="AppCmdSaveAs" 
                 Header="Save As" Command="{Binding SaveFileAs, Mode=OneWay}" 
                 IsCheckable="False" ImageSource="Images/save16.png" 
                 QuickAccessToolBarImageSource="Images/save16.png" 
                 CanAddToQuickAccessToolBarDirectly="False" />
                <RibbonApplicationMenuItem x:Name="AppCmdPrint" Header="Print" 
                 Command="{Binding Print, Mode=OneWay}" IsCheckable="False" 
                 ImageSource="Images/print.png" 
                 QuickAccessToolBarImageSource="Images/print.png" 
                 CanAddToQuickAccessToolBarDirectly="False" />
                <RibbonApplicationMenuItem x:Name="AppCmdClose" 
                 Header="Close App" Command="{Binding ExitApp, Mode=OneWay}" 
                 ImageSource="Images/close.png" 
                 QuickAccessToolBarImageSource="Images/close.png" 
                 CanAddToQuickAccessToolBarDirectly="False" />
            </RibbonApplicationMenu>
        </Ribbon.ApplicationMenu>

结论

我希望这个演示表明,升级 Winforms 应用程序并使用 WPF Ribbon 是可行的,而无需对 WinForm 上的数据结构进行太多更改。

我认为使用命令绑定和上述讨论的命令接口,这将非常有效。

最后说明

我期待任何形式的反馈 - 问题、建议等。

历史

  • 2022 年 1 月 11 日 - 初始提交
© . All rights reserved.