将DataTemplate中的按钮绑定到窗体的ViewModel中

时间:2012-09-10 22:55:57

标签: c# wpf xaml data-binding mvvm

我的问题类似于这个问题中描述的问题:
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,绑定到名为ObservableCollection<string>的{​​{1}}(位于ViewModel中)。
此绑定有效(它显示集合中每个项目的按钮)。

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

FireCommand

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

  • 该按钮位于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"); } } 内,因此它只“知道”ListBox(本例中为ListBox)的绑定,而不是主窗口的绑定
  • 我正在尝试绑定主窗口的主ViewModel中的命令(按钮不“知道”)

命令本身肯定是正确的,因为当我将按钮放在之外的ObservableCollection时(参见上面的XAML示例),绑定工作并执行命令。

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

我尝试了几种谷歌搜索后找到的方法,但没有一种方法适合我:

ListBox

有人可以请:

  1. 给我正确的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}}}" /> 内的按钮绑定到ListBox形式的命令?
  2. 指向一个链接,其中以WPF / MVVM初学者可以理解的方式解释这个高级绑定内容?
    我觉得我只是在复制和粘贴神秘的XAML咒语,到目前为止我没有任何线索(也找不到任何好的文档)我怎么会自己弄清楚在哪种情况下我需要MainViewModelRelativeSource或其他任何内容,而非“正常”绑定。

2 个答案:

答案 0 :(得分:59)

这是:

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

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

我建议阅读的唯一内容是Data Binding OverviewBinding class文档(包括其属性)。


此处还有关于如何构造绑定的简短说明:绑定包含 Path 相对于源< / em>,默认情况下, source 是当前的DataContext。可以明确设置的来源是:SourceElementName&amp; RelativeSource。设置其中任何一项都会将DataContext覆盖为来源

因此,如果您使用来源,例如RelativeSource,并希望访问该级别DataContext中的某些内容,那么DataContext需要出现在 Path

答案 1 :(得分:0)

大多数人可能认为这无关紧要,但是此搜索只是3个结果中的1个,您会发现搜索到数据绑定命令的数据模板中的控件-因为它与Xamarin Forms有关。因此,也许现在会对某人有所帮助。

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

  CreateMap<Folder, FolderDetail>()
                .ForMember(dst => dst.Children, opt => opt.MapFrom(src => GetFolderChildItems(src)));

 private IEnumerable<FolderChildItem> GetFolderChildItems(Folder src)
        {
            var folderChildren = src.SubFolders.Select(folder => new FolderChildItem()
            {
                Id = folder.Id,
                ModifiedDate = folder.ModifiedDate,
                Name = folder.Name,
                Type = "Folder",
                Children = GetFolderChildItems(folder)

            }).ToList();

            var fileChildren = src.Files.Select(file => new FolderChildItem()
            {
                Id = file.Id,
                ModifiedDate = file.ModifiedDate,
                Name = file.Name,
                Type = file.Type

            }).ToList();


            var childItems = folderChildren.Concat(fileChildren);

            return childItems;
        }

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