我的问题与这个问题描述的类似:
WPF MVVM中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>
这只是一个绑定到 ViewModel 中名为 CommandSets 的 ObservableCollection<string> 的 ListBox
(它会显示集合中每个项目的按钮)。
现在我想将按钮绑定到 ViewModel 中的一个命令(FireCommand
)。以下是 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");
}
}
这个按钮的绑定无法正常工作。从我在上面链接的问题中所理解的来看,绑定不起作用是因为:
(如果我错了,请纠正我)
- 按钮位于
ListBox
内部,因此只“知道”ListBox
的绑定(在此情况下为ObservableCollection
),而不知道主窗口的绑定 - 我试图将其绑定到主窗口的主ViewModel中的命令(该按钮不“知道”这个命令)
命令本身肯定是正确的,因为当我将按钮放在ListBox
之外(请参见上面的XAML示例)时,绑定会生效并且命令会执行。
显然,“只需要”告诉按钮绑定到表单的主ViewModel。
但我无法弄清楚正确的XAML语法。
我尝试了一些在Google上找到的方法,但它们都对我不起作用:
<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
中的按钮与表单MainViewModel
中命令绑定的正确XAML代码? - 能否指导一个WPF/MVVM初学者理解高级绑定操作的相关信息?
我感觉我只是在复制和粘贴晦涩难懂的XAML代码,而且迄今为止我不知道(也找不到好的文档)在哪些情况下我需要使用RelativeSource
或StaticResource
甚至其他替代"正常"绑定的方式。
UserControl
中设置了x:Name="root"
,它也可以与{Binding DataContext.FireCommand, ElementName=root}
一起使用。我认为这样稍微更加优雅一些。 - Informagic{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.FireCommand}
进行工作,希望这能帮助到某些人。 - Peter-Yu