将Button绑定到ItemsControl容器中的RelayCommand

时间:2013-09-18 13:31:35

标签: c# wpf mvvm

在WPF应用程序中,我有一个ViewModel,它使用WrapPanel公开我通过ItemsControl容器显示为按钮的字符串集合。但是,我无法将ViewModel中的RelayCommand绑定到按钮上。

ViewModel(IncidentAddressesViewModel):

public IEnumerable<string> Addresses { get; set; }

public RelayCommand<string> ZoomToAddressCommand { get {
  if (this.zoomToAddressCommand == null) this.zoomToAddressComamnd = new RelayCommand<string>(this.ZoomToAddress);
  return this.zoomToAddressCommand;
}}

private void ZoomToAddress(string address) { MessageBox.Show (address); }

XAML:

<TabItem x:Name="IncidentAddressesTab">
  <ItemsControl ItemsSource="{Binding Addresses}">
    <i:Interaction.Triggers>
      <i:EventTrigger EventName="Command">
        <cmd:EventToCommand 
          Command="{Binding ZoomToAddressCommand}"
          CommandParameter="{Binding Text}"
         PassEventArgsToCommand="True" 
        />
      </i:EventTrigger>
    </i:Interaction.Triggers>

    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <WrapPanel Orientation="Vertical"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <Button Content="{Binding}" />
      </DataTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</TabItem>

Xaml Code Behind连接DataContext

IncidentAddressesTab.DataContext = new IncidentAddressesViewModel();

按钮显示地址。当我在ZoomToAddressCommand设置断点时,它会被击中一次,但是当我单击按钮时,ZoomToAddress方法永远不会被调用。

更新以包含绑定详细信息: 我实际上绑定到TabItem。我更新了XAML以包含附加标记,并在XAML Code Behind中添加了绑定代码。我不知道这是相关的信息,或者我会在开头添加它..(:

2 个答案:

答案 0 :(得分:4)

它不起作用,因为您尝试Bind CommandItemsControl而不是Button控件。你试过这个吗?:

<DataTemplate>
    <Button Content="{Binding}" Command="{Binding DataContext.ZoomToAddressCommand, 
        RelativeSource={RelativeSource AncestorType={x:Type 
        YourViewNamespace:YourViewName}}}" />
</DataTemplate>

我们在这里尝试做的是BindDataTemplate到我假设的视图模型设置为当前视图的DataContext。请将“YourViewNamespace:YourViewName”替换为XML命名空间和视图的实际名称。

更新&gt;&gt;&gt;

好的,在再次查看您的代码后,我可以看到您只是使用属性名称BindingAddresses集合。你说在DataContext上设置了ItemsControl,所以我假设你的意思是你的视图模型是在ItemsControl.DataContext属性上设置的。如果是这样,那么我们需要将Binding更改为Command,如下所示:

<DataTemplate>
    <Button Content="{Binding}" Command="{Binding DataContext.ZoomToAddressCommand, 
        RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
</DataTemplate>

如果您的视图模型未在ItemsControl.DataContext属性上设置,那么这将无效,您需要清楚地告诉我您是如何将视图模型连接到视图的。在我假设您的视图模型是绑定到包含视图的DataContextWindow的数据之前,通常已经完成...也许下次,您可以在您的问题中提供此信息以使其成为可能人们更容易回答它?

更新2&gt;&gt;&gt;

好的,您已经使用必要的DataContext信息更新了问题...完美。现在我可以在没有猜测的情况下正确回答你的问题...你知道如果你在第一时间添加它会有多容易吗?不管......我们现在在这里。试试这个最后的例子:

<DataTemplate>
    <Button Content="{Binding}" Command="{Binding DataContext.ZoomToAddressCommand, 
        RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}" />
</DataTemplate>

重申......此RelativeSource Binding将查找可视树,直到找到TabItem控件。然后,它将查看该控件的DataContext属性。最后,它会在对象(您的视图模型)中查找ZoomToAddressCommand属性,该属性设置为DataContext的{​​{1}} ......我们就是这样。

答案 1 :(得分:0)

我最终不得不稍微改变结构,

我添加了一个课程:

public class IncidentAddress {
  public string Address { get; set; }

  private RelayCommand zoomCommand; 
  public RelayCommand ZoomCommand {
    get {
      if (zoomCommand == null)
        zoomCommand = new RelayCommand(Zoom);
      return zoomCommand;
    }
  }

  public void Zoom() {
    MessageBox.Show(Address);
  }
}

在我的ViewModel中, 这样:

public IEnumerable<string> Addresses { get; set; }

更改为:

public IEnumerable<IncidentAddress> Addresses { get; set; }

我从ViewModel中删除了RelayCommand并将其保留在新类

XAML最终成了这样:

<TabItem x:Name="IncidentAddressesTab">
  <ItemsControl ItemsSource="{Binding Addresses}">
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <WrapPanel Orientation="Vertical"/>
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
      <DataTemplate>
        <Button Content="{Binding Address}" Command="{Binding ZoomCommand}" />
      </DataTemplate>
    </ItemsControl.ItemTemplate>
  </ItemsControl>
</TabItem>