从 ListItem 内部触发外部 ICommands/Functions
Triggering External ICommands/Functions from inside a ListItem
我想知道从内部列表项中触发外部函数(或命令)的最佳方法是什么。
例如,我有一个 FooManager
对象,它包含一个名为 MyFoos
的 Foo
个对象的 ObservableCollection。 FooManager 还有一个名为 ProcessFoo(Foo foo)
.
的函数
<StackPanel DataContext="FooManager">
<ListView ItemsSource="{Binding MyFoos}" >
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Button Content="Do Something"
Command="{Binding Path=SomeFooCommand} />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
如何通过单击 "Do Something" 按钮触发 ProcessFoo(Foo foo) 函数(并传递 'clicked' Foo)?
我知道我可以使用代码隐藏来执行此操作,但我想知道最干净的 MVVM 方法是什么。 Foo 的 ViewModel 是否应该包含对其 FooManager 的引用,或者 ViewModel 相互引用是不好的做法吗?
我使用 Prism 的 DelegateCommand,我认为这是绑定到命令的最简单方法。它与许多其他命令选项非常通用。如果您有 visual studio,请转到工具 > NuGet 包管理器 > 管理包,在浏览中搜索 Prism 并安装 Prism.Core。或者您可以创建自己的 DelegateCommand 实现 ICommand 接口。 delegatecommand 的另一个选项在本文底部:https://www.codeproject.com/Articles/36545/WPF-MVVM-Model-View-View-Model-Simplified,它使用 wpf mvvm 工具包。这是棱镜的实现:
view.xaml:
<Button Command="{Binding FooCommand}" />
viewmodel.cs:
public DelegateCommand FooCommand { get; private set; }
FooCommand = new DelegateCommand(OnFoo, CanFoo);
private void OnFoo()
{
ProcessFoo(ListViewName.SelectedItems);
}
private bool CanFoo()
{
return someBooleanFunc();
}
您可能希望将 "FooCommand = new ..." 移动到 ViewModel 构造函数。
感谢@Clemens。在 FooManager class 中,添加一个以 Foo VM 作为参数的命令。然后,DataTemplate 中的 Button 可以通过在绑定中使用 RelativeSource
并将自身(空 {Binding}
)作为参数传递来触发它。
<StackPanel DataContext="FooManager">
<ListView ItemsSource="{Binding MyFoos}" >
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Button Content="Do Something"
Command="{Binding Path=DataContext.ProcessFoo, RelativeSource={RelativeSource AncenstorType=ListView}}
CommandParameter={Binding} />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
我想知道从内部列表项中触发外部函数(或命令)的最佳方法是什么。
例如,我有一个 FooManager
对象,它包含一个名为 MyFoos
的 Foo
个对象的 ObservableCollection。 FooManager 还有一个名为 ProcessFoo(Foo foo)
.
<StackPanel DataContext="FooManager">
<ListView ItemsSource="{Binding MyFoos}" >
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Button Content="Do Something"
Command="{Binding Path=SomeFooCommand} />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
如何通过单击 "Do Something" 按钮触发 ProcessFoo(Foo foo) 函数(并传递 'clicked' Foo)?
我知道我可以使用代码隐藏来执行此操作,但我想知道最干净的 MVVM 方法是什么。 Foo 的 ViewModel 是否应该包含对其 FooManager 的引用,或者 ViewModel 相互引用是不好的做法吗?
我使用 Prism 的 DelegateCommand,我认为这是绑定到命令的最简单方法。它与许多其他命令选项非常通用。如果您有 visual studio,请转到工具 > NuGet 包管理器 > 管理包,在浏览中搜索 Prism 并安装 Prism.Core。或者您可以创建自己的 DelegateCommand 实现 ICommand 接口。 delegatecommand 的另一个选项在本文底部:https://www.codeproject.com/Articles/36545/WPF-MVVM-Model-View-View-Model-Simplified,它使用 wpf mvvm 工具包。这是棱镜的实现:
view.xaml:
<Button Command="{Binding FooCommand}" />
viewmodel.cs:
public DelegateCommand FooCommand { get; private set; }
FooCommand = new DelegateCommand(OnFoo, CanFoo);
private void OnFoo()
{
ProcessFoo(ListViewName.SelectedItems);
}
private bool CanFoo()
{
return someBooleanFunc();
}
您可能希望将 "FooCommand = new ..." 移动到 ViewModel 构造函数。
感谢@Clemens。在 FooManager class 中,添加一个以 Foo VM 作为参数的命令。然后,DataTemplate 中的 Button 可以通过在绑定中使用 RelativeSource
并将自身(空 {Binding}
)作为参数传递来触发它。
<StackPanel DataContext="FooManager">
<ListView ItemsSource="{Binding MyFoos}" >
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Button Content="Do Something"
Command="{Binding Path=DataContext.ProcessFoo, RelativeSource={RelativeSource AncenstorType=ListView}}
CommandParameter={Binding} />
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>