将 DataTemplate 中的按钮绑定到表单的 ViewModel 中的命令

Posted

技术标签:

【中文标题】将 DataTemplate 中的按钮绑定到表单的 ViewModel 中的命令【英文标题】:Bind button in DataTemplate to command in the form's ViewModel 【发布时间】:2012-09-03 20:14:24 【问题描述】:

我的问题与这个问题中描述的类似:WPF MVVM Button Control Binding in DataTemplate

这是我的 XAML:

<Window x:Class="MissileSharp.Launcher.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MissileSharp Launcher" Height="350" Width="525">
    <Grid>
        <!-- when I put the button here (outside the list), the binding works -->
        <!--<Button Content="test" Command="Binding Path=FireCommand" />-->
        <ListBox ItemsSource="Binding CommandSets">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <!-- I need the button here (inside the list), and here the binding does NOT work -->
                    <Button Content="Binding" Command="Binding Path=FireCommand" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

它只是一个 ListBox,绑定到一个名为 CommandSetsObservableCollection&lt;string&gt;(在 ViewModel 中)。 此绑定有效(它为集合中的每个项目显示一个按钮)。

现在我想将按钮绑定到命令 (FireCommand),该命令也在 ViewModel 中。 这是 ViewModel 的相关部分:

public class MainWindowViewModel : INotifyPropertyChanged

    public ICommand FireCommand  get; set; 
    public ObservableCollection<string> CommandSets  get; set; 

    public MainWindowViewModel()
    
        this.FireCommand = new RelayCommand(new Action<object>(this.FireMissile));
    

    private void FireMissile(Object obj)
    
        System.Windows.MessageBox.Show("fire");
    

此按钮的绑定不起作用。 根据我从上面链接的question 中了解到的情况,绑定不起作用,因为:(如果我错了,请纠正我)

按钮位于ListBox 内,因此它只“知道”ListBox 的绑定(在本例中为ObservableCollection),而不是主窗口的绑定 我正在尝试绑定到主窗口的主 ViewModel 中的命令(按钮不“知道”)

命令本身绝对正确,因为当我将按钮放在ListBox 之外(请参阅上面的XAML 示例),绑定有效并且命令被执行。

显然,我“只是”需要告诉按钮绑定到表单的主 ViewModel。 但我无法找出正确的 XAML 语法。

我尝试了几种在谷歌搜索后发现的方法,但没有一个对我有用:

<Button Content="Binding" Command="Binding RelativeSource=RelativeSource Window, Path=DataContext.FireCommand" />

<Button Content="Binding" Command="Binding Path=FireCommand, Source=StaticResource MainWindow" />

<Button Content="Binding" Command="Binding Path=FireCommand, RelativeSource=RelativeSource AncestorType=x:Type Window" />

有人可以吗:

    给我正确的 XAML 以将 ListBox 中的按钮绑定到表单的 MainViewModel 中的命令? 指向一个链接,其中以 WPF/MVVM 初学者可以理解的方式解释了这种高级绑定内容?我觉得我只是在复制和粘贴神秘的 XAML 咒语,并且到目前为止,我没有任何线索(也找不到任何好的文档)我将如何自己弄清楚在哪些情况下我需要 RelativeSourceStaticResource 或其他任何东西而不是“正常”绑定。

【问题讨论】:

【参考方案1】:

是:

Binding DataContext.FireCommand,
         RelativeSource=RelativeSource AncestorType=ListBox

除非您实际上更改了DataContext,否则无需走到根目录,但由于ListBox 似乎绑定到主VM 上的属性,这应该足够了。

我唯一推荐阅读的是Data Binding Overview 和Binding class 文档(包括其属性)。


这里还有一个关于如何构造绑定的简短说明:绑定由 source 和相对于该 sourcePath 组成>,默认情况下 source 是当前的DataContext。可以显式设置的来源是:SourceElementNameRelativeSource。设置其中任何一个都将覆盖DataContext 作为

因此,如果您使用像RelativeSource 这样的 并希望在该级别访问DataContext 中的某些内容,则DataContext 需要出现在Path em>。

【讨论】:

很好的答案,这有帮助。谢谢! 谢谢——四个小时的调试终于结束了!顺便说一句,它也适用于Binding DataContext.FireCommand, ElementName=root,假设您为UserControl 设置了x:Name="root"。我认为这稍微优雅一些​​。 @Informagic:除非您的 IDE 可以在重命名元素时更新绑定,否则我建议使用相对源绑定。如果您过度使用名称引用并绑定到“很远”的元素,名称引用也会使理解标记变得困难。 在我的场景中,与Binding RelativeSource=RelativeSource FindAncestor, AncestorType=x:Type ListBox, Path=DataContext.FireCommand合作希望这可以帮助某人。 @Peter-Yu:在大多数情况下是等价的。您只需直接设置Path 属性。在我的回答中,路径被传递给 Binding 构造函数,该构造函数在内部设置 Path 属性。 (虽然有一些实现细节在使用构造函数时可能会导致问题。)【参考方案2】:

这可能被大多数人认为是不相关的,但此搜索只是 3 个结果中的一个,您会发现这些结果用于搜索数据模板内的控件的数据绑定命令 - 因为它与 Xamarin Forms 相关。所以,也许它现在对某人有帮助。

像我一样,您可能想知道如何在 BindableLayout 中绑定命令。感谢 jesulink2514 在 Xamarin 论坛上回答这个问题,由于所有的 cmets,它可能被许多人忽略了。这是他的解决方案,但我包括以下链接:

<ContenPage x:Name="MainPage">
<ListView Grid.Row="1"
              ItemsSource="Binding Customers"
              VerticalOptions="Fill"
              x:Name="ListviewCustomer">
      <ListView.ItemTemplate>
        <DataTemplate>
      <Label Text="Binding Property"/>
          <Button Command="Binding BindingContext.ItemCommand, Source=x:Reference MainPage" 
                         CommandParameter="Binding .">Click me</Button>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
</ContentPage>

https://forums.xamarin.com/discussion/comment/217355/#Comment_217355

【讨论】:

作为附加资源,此链接中的代码适用于我的情况:syncfusion.com/kb/11029/…

以上是关于将 DataTemplate 中的按钮绑定到表单的 ViewModel 中的命令的主要内容,如果未能解决你的问题,请参考以下文章

UWP 数据绑定:如何将按钮命令设置为 DataTemplate 中的父 DataContext

如何将 ObservableCollection 绑定到 DataTemplate 中的文本框?

绑定到 DataTemplate 中的视图模型属性

将 DataTemplate 中的图像绑定到 System.Drawing.Image

如何将 DataTemplate 数据类型绑定到接口?

C#:WPF MVVM 中的按钮绑定