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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12360560/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 22:59:24  来源:igfitidea点击:

Bind button in DataTemplate to command in the form's ViewModel

c#wpfxamldata-bindingmvvm

提问by Christian Specht

My problem is similar to the one described in this question:
WPF MVVM Button Control Binding in DataTemplate

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

Here is my XAML:

这是我的 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>

It's just a ListBox, bound to an ObservableCollection<string>named CommandSets(which is in the ViewModel).
This binding works (it displays a button for each item in the collection).

它只是一个ListBox, 绑定到一个ObservableCollection<string>命名的CommandSets(在 ViewModel 中)。
此绑定有效(它为集合中的每个项目显示一个按钮)。

Now I want to bind the button to a command (FireCommand), which is also in the ViewModel.
Here's the relevant part of the 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");
    }
}

The binding of this button does NOT work.
From what I've understood from the questionI linked above, the binding doesn't work because:
(correct me if I'm wrong)

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

  • The button is inside the ListBox, so it only "knows" the binding of the ListBox(the ObservableCollection, in this case), but not the binding of the main window
  • I'm trying to bind to a command in the main ViewModel of the main window (which the button doesn't "know")
  • 按钮在 内ListBox,所以它只“知道” ListBoxObservableCollection在本例中为 )的绑定,而不知道主窗口的绑定
  • 我正在尝试绑定到主窗口的主 ViewModel 中的命令(按钮不“知道”)

The command itself is definitely correct, because when I put the button outsidethe ListBox(see the XAML above for an example), the binding works and the command is executed.

命令本身是绝对正确的,因为当我把按钮之外ListBox(见上面的XAML的例子),结合工程和执行该命令。

Apparently, I "just" need to tell the button to bind to the main ViewModel of the form.
But I'm not able to figure out the right XAML syntax.

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

I tried several approaches that I found after some googling, but none of them worked for me:

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

<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}}}" />

Could someone please:

有人可以请:

  1. give me the proper XAML to bind the button inside the ListBoxto a command in the form's MainViewModel?
  2. point me to a link where this advanced binding stuff is explained in a way that a WPF/MVVM beginner can understand?
    I'm feeling like I'm just copying and pasting arcane XAML incantations, and so far I don't have any clue (and can't find any good documentation) how I would figure out by myself in which cases I'd need RelativeSourceor StaticResourceor whatever instead of a "normal" binding.
  1. 给我合适的 XAML 来将里面的按钮绑定ListBox到表单中的命令MainViewModel
  2. 将我指向一个链接,其中以 WPF/MVVM 初学者可以理解的方式解释了这种高级绑定内容?
    我觉得我只是在复制和粘贴神秘的 XAML 咒语,到目前为止我没有任何线索(并且找不到任何好的文档)我如何自己弄清楚在哪些情况下我需要RelativeSourceStaticResource或其他任何东西,而不是“正常”绑定。

采纳答案by H.B.

It's:

它的:

{Binding DataContext.FireCommand,
         RelativeSource={RelativeSource AncestorType=ListBox}}

No need to walk up to the root unless you actually change the DataContextalong the way, but as the ListBoxseems to bind to a property on the main VM this should be enough.

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

The only thing i recommend reading is the Data Binding Overview, and the Bindingclassdocumentation (including its properties).

我唯一推荐阅读的是数据绑定概述Binding文档(包括其属性)。



Also here is a short explanation on how bindings are constructed: A binding consists of a sourceand a Pathrelative to that source, by default the sourceis the current DataContext. Sources that can be set explicitly are: Source, ElementName& RelativeSource. Setting any of those will override the DataContextas source.

这里还有一个关于如何构建绑定的简短解释:绑定由一个source和一个Path相对于该source 的 source 组成,默认情况下,source是 current DataContext。可以明确设置的来源是:Source, ElementName& RelativeSource。设置其中任何一个都将覆盖DataContextas source

So if you use a sourcelike RelativeSourceand want to access something in the DataContexton that level the DataContextneeds to appear in the Path.

因此,如果您使用类似的RelativeSource并希望访问DataContext该级别中的某些内容,则DataContext需要出现在Path.

回答by smoovey

This may be considered unrelated by most, but this search is only 1 of 3 results that you'll find searching for data binding commands to controls inside a data template--as it relates to Xamarin Forms. So, maybe it'll help someone now-a-days.

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

Like me you may wonder how to bind commands inside a BindableLayout. Credit jesulink2514 for answering this at Xamarin Forums, where it's probably overlooked by many because of all the comments. Here's his solution, but I'm including the link below:

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

<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

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