【问题标题】:Binding a Button to a RelayCommand within an ItemsControl container将按钮绑定到 ItemsControl 容器中的 RelayCommand
【发布时间】:2013-09-18 13:31:34
【问题描述】:

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

视图模型(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>

连接DataContext的Xaml代码

IncidentAddressesTab.DataContext = new IncidentAddressesViewModel();

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

更新以包含绑定详细信息: 我实际上绑定到 TabItem。我更新了 XAML 以包含附加标记,并在 XAML 代码隐藏中添加了绑定代码。我不知道这是相关信息,否则我会在开始时添加它..(:

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

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

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

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

    更新>>>

    好的,再次查看您的代码后,我可以看到您是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 >>>

    好的,您已使用基本的DataContext 信息更新了问题……完美。现在我可以正确地回答你的问题而无需猜测......你知道如果你一开始就在那里添加它会容易得多吗?没关系......我们现在在这里。试试这个最后一个例子:

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

    重申...RelativeSource Binding 将查找可视化树,直到找到TabItem 控件。然后,它将查看该控件的DataContext 属性。最后,它将在对象(您的视图模型)中查找设置为DataContextDataContextZoomToAddressCommand 属性。

    【讨论】:

    • 我删除了我的 ItemsControl 下的 i:Interation.Triggers 部分并按照您说明的方式绑定它,并且 RelayCommand 属性断点现在没有命中,并且该方法没有被调用
    • 此外,在 Xaml 构造函数中设置的数据上下文位于 ItemsControl Parent (A TabItem) 上。我需要更改 RelativeSource 吗?
    • 我实际上将数据上下文绑定到更高级别。我希望我有更多时间使用 MVVM 在 WPF 中编程,但这是一种一次性项目。..
    • 老兄...你想要帮忙吗?你仍然没有告诉我你是如何连接你的视图模型的......“高一级”是什么意思?在您提供这些信息之前,我无法回答您的问题……这取决于您。
    • 我在原始问题中添加了如何连接视图模型。代码行是“IncidentAddressesTab.DataContext = new IncidentAddressesViewModel();” . IncidentAddressesTab 是 ItemsControl 元素的父级(高一级可能不是那里的最佳描述)。我当然确实需要帮助,并且正在尽我所能为您(以及其他任何人)提供尽可能多的信息。
    【解决方案2】:

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

    我添加了一个类:

    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>
    

    【讨论】:

    • 这不是做事的方式,你正在混合你的模型和你的视图模型(命令应该在哪里)。 @Sheridan 答案应标记为正确答案...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 2017-01-31
    • 1970-01-01
    相关资源
    最近更新 更多