【问题标题】:Bind button in DataTemplate to command in the form's ViewModel将 DataTemplate 中的按钮绑定到表单的 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}}}" />

有人可以吗:

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

【问题讨论】:

    标签: c# wpf xaml data-binding mvvm


    【解决方案1】:

    是:

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

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

    我唯一推荐阅读的是Data Binding OverviewBinding 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

    【讨论】:

    猜你喜欢
    • 2020-05-28
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    • 2012-04-21
    • 2011-09-17
    • 2019-12-27
    • 2016-11-22
    • 1970-01-01
    相关资源
    最近更新 更多