【问题标题】:Using MVVM, how to pass SelectedItems of a XamDataGrid as parameter to the Command raised by the ContextMenu?使用 MVVM,如何将 XamDataGrid 的 SelectedItems 作为参数传递给 ContextMenu 引发的命令?
【发布时间】:2010-06-09 06:41:53
【问题描述】:

我正在尝试传递 XamDataGrid 上的项目,我在该项目上单击鼠标右键以打开一个 ContextMenu,这会在我的 ViewModel 中引发一个命令。不知何故,命令调用的方法在调试模式下无法访问。

这是从视图中截取的

<ig:XamDataGrid DataSource="{Binding DrdResults}" Height="700" Width="600">
  <ig:XamDataGrid.ContextMenu>
    <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Mode=Self},
                               Path=PlacementTarget.DataContext}"
                 AllowDrop="True" Name="cmAudit">
      <MenuItem Header="View History" 
                Command="{Binding ViewTradeHistory}"
                CommandParameter="{Binding Path=SelectedItems}">
      </MenuItem>
    </ContextMenu>
  </ig:XamDataGrid.ContextMenu>
  <ig:XamDataGrid.FieldSettings>
    <ig:FieldSettings AllowFixing="NearOrFar"
                      AllowEdit="False" 
                      Width="auto" Height="auto"  />
  </ig:XamDataGrid.FieldSettings>
</ig:XamDataGrid>

我在这个View对应的ViewModel中的代码如下。

public WPF.ICommand ViewTradeHistory
{
  get
  {
    if (_viewTradeHistory == null)
    {
      _viewTradeHistory = new DelegateCommand(
      (object SelectedItems) =>
      {
        this.OpenTradeHistory(SelectedItems); 
      });
    }
    return _viewTradeHistory;
  }
}

最后被命令调用的实际方法如下

private void OpenTradeHistory(object records)
{
  DataPresenterBase.SelectedItemHolder auditRecords
    = (DataPresenterBase.SelectedItemHolder)records;
  // Do something with the auditRecords now.
}

我不确定我在这里做错了什么。任何帮助将不胜感激。

谢谢, 沙文

【问题讨论】:

    标签: c# wpf mvvm contextmenu xamdatagrid


    【解决方案1】:

    我通过改进 Damian 的答案来解决这个问题(这不是很有效)。

    这是我的解决方案:

    首先是行为:

    public class DataGridExtender : Behavior<XamDataGrid>
    {
        public readonly static DependencyProperty SelectedDataItemsProperty
            = DependencyProperty.Register(
                "SelectedDataItems",
                typeof(ICollection<object>),
                typeof(DataGridExtender),
                new PropertyMetadata());
    
        public ICollection<object> SelectedDataItems
        {
            get { return (ICollection<object>)GetValue(SelectedDataItemsProperty); }
            set { SetValue(SelectedDataItemsProperty, value); }
        }
    
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.SelectedItemsChanged += AssociatedObjectOnSelectedItemsChanged;
            AssociatedObjectOnSelectedItemsChanged(AssociatedObject, null);
        }
    
        protected override void OnDetaching()
        {
            AssociatedObject.SelectedItemsChanged -= AssociatedObjectOnSelectedItemsChanged;
            base.OnDetaching();
        }
    
        private void AssociatedObjectOnSelectedItemsChanged(object sender, Infragistics.Windows.DataPresenter.Events.SelectedItemsChangedEventArgs e)
        {
            if (SelectedDataItems != null)
            {
                SelectedDataItems.Clear();
                foreach (var selectedDataItem in GetSelectedDataItems())
                {
                    SelectedDataItems.Add(selectedDataItem);
                }
            }
        }
    
        private IEnumerable<object> GetSelectedDataItems()
        {
            var selectedItems = from rec in AssociatedObject.SelectedItems.Records.OfType<DataRecord>() select rec.DataItem;
            return selectedItems.ToList().AsReadOnly();
        }
    }
    

    然后是它的用法:

    <igDP:XamDataGrid>
    [...]
    
    <i:Interaction.Behaviors>
        <Behaviours:DataGridExtender SelectedDataItems="{Binding SelectedDataItems, Mode=TwoWay}"></Behaviours:DataGridExtender>
    </i:Interaction.Behaviors>
    
    [...]
    
    <igDP:XamDataGrid.FieldLayoutSettings>
        [...]
    </igDP:XamDataGrid.FieldLayoutSettings>
    
    <igDP:XamDataGrid.FieldLayouts>
        <igDP:FieldLayout>
            [...]
        </igDP:FieldLayout>
    </igDP:XamDataGrid.FieldLayouts>
    

    当然,您的视图模型中需要有一个“SelectedDataItems”。

    编辑:必须先将视图模型中的SelectedDataItems 属性实例化为空集合,否则将不起作用。

    【讨论】:

    • Infragistics 不支持这种开箱即用的东西真是太可惜了。我目前正在评估他们的网格。也许我会切换到另一个供应商。
    【解决方案2】:

    对于单个项目,infragistics 非常友好地添加了一个名为“ActiveDataItem”的可绑定 DependencyProperty,如果有的话,它是“选中的”项目。 它甚至可以双向工作,即您可以在 ViewModel 中重置选择。

    不幸的是,AFAIK 没有类似的多选内容。 您必须自己实现,遍历选定的记录,检查它们是否是数据记录,获取记录和数据项等...

    【讨论】:

      【解决方案3】:

      尝试将 DataGrid 的 SelectedItem 绑定到视图模型中的属性。

      然后您可以在 OpenTradeHistory() 方法中访问此属性。

      【讨论】:

      • 我不确定右键单击 XamDataGrid 行是否会将记录选择为 SelectedItem。这并不能真正解决问题,因为我试图从处理 XamDataGrid 上的右键单击 > 上下文菜单的命令中传递一个参数。
      • @saddaypally:这行中的 SelectedItems 是什么意思 CommandParameter="{Binding Path=SelectedItems}"&gt; ?如果这些是网格中的原始选定项目,那么如果右键单击未选择项目,为什么要将它们作为参数发送?
      • 感谢您回来讨论这个问题。我没有在 XamDataGrid 上找到 SelectedItem 属性,我发现的只是这个,我想,我可以使用它并在我能够掌握它时自己迭代这些项目。实际上,我需要能够从行中传递值,在该行上我右键单击并打开一个 ContextMenu 项目以从网格中查看有关该项目的详细信息。这说明清楚了吗?任何帮助,不胜感激。
      【解决方案4】:

      为了绑定到所选项目,我选择使用 System.Interactivity 创建行为:

      using System.Collections.Generic;
      using System.Collections.ObjectModel;
      using System.Linq;
      using System.Windows;
      using System.Windows.Interactivity;
      using Infragistics.Windows.DataPresenter;
      
      namespace Sample {
          public class DataGridExtender : Behavior<XamDataGrid> {
              public readonly static DependencyProperty SelectedDataItemsProperty
                  = DependencyProperty.Register(
                      "SelectedDataItems"
                      , typeof(ICollection<object>)
                      , typeof(OzDataGridExtender)
                      , new PropertyMetadata(null));
      
              public ICollection<object> SelectedDataItems {
                  get { return (ICollection<object>)GetValue(SelectedDataItemsProperty); }
                  set { SetValue(SelectedDataItemsProperty, value); }
              }
      
              protected override void OnAttached() {
                  base.OnAttached();
                  AssociatedObject.SelectedItemsChanged += AssociatedObjectOnSelectedItemsChanged;
                  AssociatedObjectOnSelectedItemsChanged(AssociatedObject, null);
              }
      
              protected override void OnDetaching() {
                  AssociatedObject.SelectedItemsChanged -= AssociatedObjectOnSelectedItemsChanged;
                  base.OnDetaching();
              }
      
              private void AssociatedObjectOnSelectedItemsChanged(object sender, Infragistics.Windows.DataPresenter.Events.SelectedItemsChangedEventArgs e) {
                  SelectedDataItems = GetSelectedDataItems();
                  //AssociatedObject.SetValue(SelectedDataItemsPropertyKey, SelectedDataItems);
              }
      
              private ICollection<object> GetSelectedDataItems() {
                  var selectedItems = from rec in AssociatedObject.SelectedItems.Records.OfType<DataRecord>()
                                      select rec.DataItem;
                  return selectedItems.ToList().AsReadOnly();
              }
          }
      }
      

      在您看来,某些地方可能会出现以下内容(为简洁起见,我省略了命名空间映射):

      现在你在上下文菜单上的命令绑定的问题是别的东西......我会重新审视这个

      【讨论】:

      • 感谢您,这对我获得有效的解决方案帮助很大。现在它不能正常工作,因为您在 AssociatedObjectOnSelectedItemsChanged 方法中,每次选择更改时都会将 SelectedDataItems 引用设置为新集合,这会破坏任何绑定。我所做的很清楚,然后将项目添加到该集合而不更改其引用(请参阅我的答案)
      • 很高兴它帮助您走上正轨。我以为我是直接从工作代码中撕下来的,但是由于我无法再访问该代码库,因此无法分辨。无论如何,很好的收获。
      猜你喜欢
      • 1970-01-01
      • 2016-10-30
      • 2011-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-12
      • 1970-01-01
      相关资源
      最近更新 更多