WinForm VB.NET 托管 WPF Ribbon - 第 2 部分 - 使用 ICommand 和 MVVM 模式
我的想法是在 WinForm VB.NET 项目中托管带有 Ribbon 的 WPF 用户控件,并尝试使用 MVVM 模式。
引言
这篇文章和演示受到 CodeProject 文章的启发,使用 ICommand 和 MVVM 模式,它根据 MVVM 模式创建和使用 ICommand
。
我将那里的代码作为我自己的类/接口的模板。
背景
我的第一篇文章,WinForm VB.NET 托管 WPF Ribbon 侧重于一些基本工作,以使演示正常运行。
但我对 WinForm 和 WPF 用户控件之间的接口/通信不太满意。
在这里,我们只会讨论第一篇文章中缺失的内容和/或新内容或已更改的内容。
Winform 概念和代码
托管 WPF 用户控件所需的项目引用
PresentationCore
PresentationFramework
WindowsBase
WindowsFormsIntegration
检测 ActiveTextBox
和 ActiveRichTextBox
的代码如下所示
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
具有与 ActiveRichTextBox
或 ActiveTextBox
协同工作的菜单项/Ribbon 按钮。 这就是我们在 模型 类 TextData
中看到的内容。
一些菜单项/命令已移动到 TextDataViewModel
,除了所有的 Richtext
格式化 Ribbon 按钮。
有两个新类,TextDataViewModel
和 TextData
。
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 日 - 初始提交