正确的 MVVM 模式 WPF 命令实现
Posted
技术标签:
【中文标题】正确的 MVVM 模式 WPF 命令实现【英文标题】:Correct MVVM pattern WPF Command implementation 【发布时间】:2017-12-06 17:44:18 【问题描述】:我正在尝试按照 MVVM 模式实现命令,但我被这个特定场景所困。
在 XAML 中,我将命令绑定到列内的按钮:
<dxg:GridColumn FieldName="Delete" Header="" UnboundType="Object" Width="20" FixedWidth="True">
<dxg:GridColumn.EditSettings>
<dxe:ButtonEditSettings AllowDefaultButton="False">
<dxe:ButtonEditSettings.Buttons>
<dxe:ButtonInfo GlyphKind="Cancel" Command="Binding DeleteRowCommand" CommandParameter="Binding ElementName=testView" />
</dxe:ButtonEditSettings.Buttons>
</dxe:ButtonEditSettings>
</dxg:GridColumn.EditSettings>
</dxg:GridColumn>
在我的 ViewModel 中,我声明了一个 DelegateCommand:
Private m_deleteRowCommand As DelegateCommand(Of Object)
Public Property DeleteRowCommand() As DelegateCommand(Of Object)
Get
Return m_deleteRowCommand
End Get
Private Set(ByVal value As DelegateCommand(Of Object))
m_deleteRowCommand = value
End Set
End Property
我在 ViewModel 的构造函数中初始化了命令:
DeleteRowCommand = New DelegateCommand(Of Object)(AddressOf DeleteRowCommandExecute)
最后我执行命令:
Private Sub DeleteRowCommandExecute(ByVal parameter As Object)
Dim sender As TableView = parameter
Dim row = sender.DataControl.CurrentItem
Dim index = sender.FocusedRowHandle
sender.DeleteRow(index)
End Sub
一切都按预期工作,但据我所知 ViewModel 应该对 View 一无所知,因此删除 ViewModel 内的行是不正确的。
遵循 MVVM 模式的最佳方法是什么?
更新: 从绑定到 Grid 的 ItemsSource 的 ObservableCollection 中删除项目效果很好,但是如果我需要从没有 ItemsSource 的 Grid 中删除像 StackPanel 这样的 UI 元素怎么办?
<Grid>
<StackPanel>
<Button Content="Delete" Height="25" Width="100" Command="Binding DeleteItemCommand"
CommandParameter="Binding RelativeSource=RelativeSource AncestorType=StackPanel" />
</StackPanel>
</Grid>
更新 2: 我的目标是拥有一个容器,我可以在其中动态添加项目(UserControl),并且我可以在运行时更改这些项目的顺序。 目前,我使用 Grid 作为容器,每次插入新项目时都会向其中添加新的 RowDefinition。 我使用 Grid.Row 属性来跟踪和更改项目的顺序。 这样我需要在后面的代码中执行所有删除操作,因为我必须从 Grid 中手动删除 RowDefinition。
【问题讨论】:
DataGrid
的ItemsSource
怎么设置?如果您正在使用例如ObservableCollection
你可以从你的```中删除该条目,你的视图将自动更新。
@MightyBadaboom ItemsSource 确实是一个 ObservableCollection,经过一些调整后,我只需从集合中删除相应的项目即可使其工作。但是,如果我需要从没有 ItemsSource 属性的 Grid 中删除 ui 元素,比如 StackPanel,该怎么办?
干得好,不需要更多帮助了吗?
@MightyBadaboom 我更新了问题。
你为什么在Grid
中使用StackPanel
,一列一行只是为了放置Button
? Grid
和 Stackpanel
不可见并且用于定位。当你不得不改变他们的可见性时,我猜你的方法不是最好的。例如,如果你真的需要,你可以使用IValueConverter
。
【参考方案1】:
从绑定到 Grid 的 ItemsSource 的 ObservableCollection 中删除项目效果很好,但是如果我需要从没有 ItemsSource 的 Grid 中删除 UI 元素(如 StackPanel)怎么办?
由于此代码纯粹是与视图相关的,它应该在视图的代码隐藏中实现(或在应用它的控件本身中)。视图模型不应该知道任何关于任何 UI 元素的信息,因此实现删除这些元素的命令是没有意义的。
MVVM 并不是要从视图中消除与 view 相关的代码。它是关于关注点的分离。因此,请保留与 UIElements
和 Panels
相关的所有内容。
【讨论】:
实际上,当我单击 StackPanel 内的按钮时,我需要从 Grid 中删除 StackPanel 并从 ViewModel 内的 ObservableCollection 中删除一个项目。 那么您应该使用绑定到源集合的 ItemsControl,然后将 StackPanel 添加到 ItemTemplate。 我更新了我的问题。然后您建议使用 ItemsControl 而不是 Grid?在这种情况下,为了更改项目的顺序,我应该向我的 UserControl 添加自定义索引属性吗? 只需将 ItemsControl 的 ItemsSource 属性绑定到 ObservableCollection以上是关于正确的 MVVM 模式 WPF 命令实现的主要内容,如果未能解决你的问题,请参考以下文章
使用 MVVM 从 WPF 中的 TextBox 进行正确的 DataGrid 搜索