【问题标题】:Triggering External ICommands/Functions from inside a ListItem从 ListItem 内部触发外部 ICommands/Functions
【发布时间】:2017-10-03 21:17:23
【问题描述】:

我想知道从内部列表项中触发外部函数(或命令)的最佳方法是什么。

例如,我有一个 FooManager 对象,它包含一个名为 MyFoosFoo 对象的 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>

如何通过单击“做某事”按钮来触发 ProcessFoo(Foo foo) 函数(并传递“点击”的 Foo)?

我意识到我可以使用代码隐藏来执行此操作,但我想知道最干净的 MVVM 方法是什么。 Foo 的 ViewModel 是否应该包含对其 FooManager 的引用,或者 ViewModel 相互引用是不好的做法?

【问题讨论】:

  • 绑定到ListView的DataContext:Command="{Binding Path=DataContext.SomeFooCommand, RelativeSource={RelativeSource AncestorType=ListView}}"
  • 在这种情况下,将 Foo 本身作为 CommandParameter 传递是否正确?
  • 在哪种意义上正确?如果命令需要访问当前项目,您当然可以将当前 Foo 实例作为命令参数传递。
  • 抱歉 - “正确”与“最佳实践”相同。感谢您的帮助@Clemens!

标签: c# wpf mvvm data-binding icommand


【解决方案1】:

感谢@Clemens。在 FooManager 类中,添加一个以 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>

【讨论】:

    【解决方案2】:

    我使用 Prism 的 DelegateCommand,我认为这是绑定命令的最简单方法。它与许多其他命令选项非常通用。如果您有 Visual Studio,请转到工具 > NuGet 包管理器 > Mange 包,在浏览中搜索 Prism 并安装 Prism.Core。或者您可以创建自己的 DelegateCommand 实现 ICommand 接口。 delegatecommand 的另一个选项在本文底部:https://www.codeproject.com/Articles/36545/WPF-MVVM-Model-View-View-Model-Simplified,它使用 wpf mvvm 工具包。下面是一个 prism 的实现:

    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 构造函数中。

    【讨论】:

    • 这看起来确实是 MVVM 的一个很好的实现。但是它并没有解决我绑定到控件数据上下文之外的命令的问题
    • 我在你的问题中并没有真正看到这一点。您要求最干净的 MVVM 方法,就是这样。我不确定不受限制地访问命令是否是一种“干净”的 MVVM 方法。我更新了我的答案,将 Start() 更改为您的 ProcessFoo() 方法,您可以将 Name 添加到 List 控件并传入 SelectedItems。
    猜你喜欢
    • 1970-01-01
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多