Using MVVM, how to pass SelectedItems of a XamDataGrid as parameter to the Command raised by the ContextMenu?
Solution 1
I had that working by improving Damian answer (which was not quite working).
Here's my solution:
First the Behaviour:
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();
}
}
And then its usage:
<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>
Of course you'll need to have a "SelectedDataItems" in your view model.
Edit: The SelectedDataItems
property in the view model has to be instantited first as an empty collection, otherwise it won't work.
Solution 2
For a single item, infragistics was kind enough to add a bindable DependencyProperty called 'ActiveDataItem', which is "the" selected item, if any. It even works two-way, i.e. you can reset the selection from within your ViewModel.
Unfortunately, AFAIK there is no similar thing for multi-selection. You will have to implement this on your own, iterating over the selected records, check if they are datarecords, get the record and dataitem etc...
Solution 3
Try binding your DataGrid's SelectedItem to a property in your viewmodel.
You can then access this property in your OpenTradeHistory()
method.
Solution 4
For binding to the selected items I chose to create a behavior using 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();
}
}
}
Some where in your view would have something like the following (I've ommitted the namespace mappings for brevity):
Now your problem with the command binding on a context menu thats something else... I'll revisit this
user290669
Updated on June 04, 2022Comments
-
user290669 almost 2 years
I'm trying to pass the item on XamDataGrid on which I do a mouse right click to open a ContextMenu, which raises a Command in my ViewModel. Somehow the method that the Command calls is not reachable in debug mode.
This is the snipped from the view
<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>
My code in the corresponding ViewModel for this View is as follows.
public WPF.ICommand ViewTradeHistory { get { if (_viewTradeHistory == null) { _viewTradeHistory = new DelegateCommand( (object SelectedItems) => { this.OpenTradeHistory(SelectedItems); }); } return _viewTradeHistory; } }
And lastly the actual method that gets called by the Command is as below
private void OpenTradeHistory(object records) { DataPresenterBase.SelectedItemHolder auditRecords = (DataPresenterBase.SelectedItemHolder)records; // Do something with the auditRecords now. }
I'm not sure what am I doing incorrectly here. Any help will be very much appreciated.
Thanks, Shravan
-
user290669 almost 14 yearsI'm not sure if Right click on the XamDataGrid row selects the record as a SelectedItem. And this doesn't really solve the issue as I'm trying to pass a parameter from the Command that handles the right click > context Menu on the XamDataGrid.
-
Amsakanna almost 14 years@saddaypally: What is meant by SelectedItems in this line
CommandParameter="{Binding Path=SelectedItems}">
? If those were the original Selected Items in the grid then why do you send them as a parameter, if right click doesn't select an item? -
user290669 almost 14 yearsThanks for coming back on this. I didn't find a SelectedItem property on XamDataGrid, all I found was this and I thought, I could use this and iterate over the items myself when I'm able to get a hold of it. I actually need to be able to pass the values from Row on which I right click on and open a ContextMenu Item to view details about that item from the Grid. does that make it clear? Any help, appreciated.
-
Antoine Jaussoin over 11 yearsThanks for this, it helped me a lot to get a working solution. Now it doesn't quite work as it is because you are, in the AssociatedObjectOnSelectedItemsChanged method, setting the SelectedDataItems reference to a new collection each time the selection changes, which breaks any binding. What I did instead is clear then add the items to that collection without changing its reference (see my answer)
-
Damian over 11 yearsGlad it helped you get on the right track. I thought I ripped this directly from working code, but since I don't have access to that code base anymore no way to tell. Anyways, good catch.
-
Sven over 9 yearsWhat a shame on Infragistics to not Support such a thing out-of-the-box. I'm currently evaluating their grid. Maybe I'll switch to another vendor.