简体   繁体   English

使用 MVVM 模式在 Telerik RadGridView 中查找选定项目

[英]finding selected items in Telerik RadGridView using MVVM pattern

I am using a Telerik RadGridView in my application and it has a GridViewSelectColumn item in it, which allows me to select various items in the grid.我在我的应用程序中使用 Telerik RadGridView,它有一个 GridViewSelectColumn 项目,它允许我在网格中 select 各种项目。 I have a button that operates on this selection, but am not sure how to get the list of selected items.我有一个操作此选择的按钮,但不确定如何获取所选项目的列表。 The problem is that I am using an MVVM pattern with Caliburn.Micro.问题是我在 Caliburn.Micro 中使用了 MVVM 模式。 Do I need to find the control in the view and traverse the list of selected items?是否需要在视图中找到控件并遍历选中项列表? That seems like a lot of work for a simple task.对于一个简单的任务来说,这似乎需要做很多工作。 I would appreciate any ideas.我会很感激任何想法。

The problem with Telerik's RadGridView is, that its SelectedItem collection is read-only, so you cannot bind two-way to SelectedItems. Telerik 的 RadGridView 的问题在于,它的 SelectedItem 集合是只读的,因此您不能将双向绑定到 SelectedItems。

A workaround for this is to use a custom Behavior to do the synchronization between RadGridView and your ViewModels SelectedItem collection解决方法是使用自定义行为在 RadGridView 和您的 ViewModels SelectedItem 集合之间进行同步

You may use this Behavior:您可以使用此行为:

// Behavior for synchronizing a RadDataGrid's SelectedItems collection with a SelectedItems collection of the ViewModel (the Network)
// The problem is, that RadDataGrid.SelectedItems is a read-only collection and therefore cannot be used for two-way binding.

class SelectedSyncBehavior
    : Behavior<RadGridView>
{
    bool _collectionChangedSuspended = false;

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;
    }

    /// <summary>
    /// Getter/Setter for DependencyProperty, bound to the DataContext's SelectedItems ObservableCollection
    /// </summary>
    public INotifyCollectionChanged SelectedItems
    {
        get { return (INotifyCollectionChanged)GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }

    /// <summary>
    /// Dependency Property "SelectedItems" is target of binding to DataContext's SelectedItems
    /// </summary>
    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(INotifyCollectionChanged), typeof(SelectedSyncBehavior), new PropertyMetadata(OnSelectedItemsPropertyChanged));

    /// <summary>
    /// PropertyChanged handler for DependencyProperty "SelectedItems"
    /// </summary>
    private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
    {
        INotifyCollectionChanged collection = args.NewValue as INotifyCollectionChanged;
        if (collection != null)
        {
            // Hook to the Network's SelectedItems
            collection.CollectionChanged += (target as SelectedSyncBehavior).ContextSelectedItems_CollectionChanged;
        }
    }

    /// <summary>
    /// Will be called, when the Network's SelectedItems collection changes
    /// </summary>
    void ContextSelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (_collectionChangedSuspended) return;    // Don't react recursively to CollectionChanged events

        _collectionChangedSuspended = true;

        // Select and unselect items in the grid
        if (e.NewItems != null)
            foreach (object item in e.NewItems)
                AssociatedObject.SelectedItems.Add(item);

        if (e.OldItems != null)
            foreach (object item in e.OldItems)
                AssociatedObject.SelectedItems.Remove(item);

        _collectionChangedSuspended = false;
    }

    /// <summary>
    /// Will be called when the GridView's SelectedItems collection changes
    /// </summary>
    void GridSelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (_collectionChangedSuspended) return;    // Don't react recursively to CollectionChanged events

        _collectionChangedSuspended = true;

        // Select and unselect items in the DataContext
        if (e.NewItems != null)
            foreach (object item in e.NewItems)
                (SelectedItems as IList).Add(item);

        if (e.OldItems != null)
            foreach (object item in e.OldItems)
                (SelectedItems as IList).Remove(item);

        _collectionChangedSuspended = false;
    }

}

Use this Behavior with RadGridViews like this:将此行为与 RadGridViews 一起使用,如下所示:

<i:Interaction.Behaviors>
   <behaviors:SelectedSyncBehavior SelectedItems="{Binding ViewModel.SelectedItems}" />
</i:Interaction.Behaviors>

Add a bool IsSelected to the item in your collection:将 bool IsSelected 添加到集合中的项目:

 public class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public bool IsSelected { get; set; }
    }

 private BindableCollection<Customer> _customers;
        public BindableCollection<Customer> Customers
        {
            get { return _customers; }
            set
            {
                _customers = value;
                NotifyOfPropertyChange(() => Customers);
            }
        }

sample code - bitbucket示例代码 - bitbucket

download 下载

Here is a cleaned up copy of @Knasterbax's class with explicit private modifiers and null propagation:这是@Knasterbax 的 class 的清理副本,带有显式私有修饰符和 null 传播:

// Behavior for synchronizing Telerik RadDataGrid's SelectedItems collection 
//  with a SelectedItems collection of the ViewModel.   
public class SelectedSyncBehavior : Behavior<RadGridView>
{
    private bool collectionChangedSuspended;
    public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems",
        typeof(INotifyCollectionChanged), typeof(SelectedSyncBehavior), new PropertyMetadata(OnSelectedItemsPropertyChanged));

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItems_CollectionChanged;
    }

    public INotifyCollectionChanged SelectedItems
    {
        get { return (INotifyCollectionChanged)GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }

    private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
    {
        var collection = args.NewValue as INotifyCollectionChanged;
        if (collection == null) return;
        var selectedSyncBehavior = target as SelectedSyncBehavior;
        if (selectedSyncBehavior != null) collection.CollectionChanged += selectedSyncBehavior.ContextSelectedItems_CollectionChanged;
    }

    private void ContextSelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (collectionChangedSuspended) return;    // Don't react recursively to CollectionChanged events

        collectionChangedSuspended = true;

        if (e.NewItems != null)
            foreach (var item in e.NewItems)
                AssociatedObject.SelectedItems.Add(item);

        if (e.OldItems != null)
            foreach (var item in e.OldItems)
                AssociatedObject.SelectedItems.Remove(item);

        collectionChangedSuspended = false;
    }

    private void GridSelectedItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (collectionChangedSuspended) return;    // Don't react recursively to CollectionChanged events

        collectionChangedSuspended = true;

        if (e.NewItems != null)
            foreach (var item in e.NewItems)
            {
                var list = SelectedItems as IList;
                list?.Add(item);
            }

        if (e.OldItems != null)
            foreach (var item in e.OldItems)
            {
                var list = SelectedItems as IList;
                list?.Remove(item);
            }

        collectionChangedSuspended = false;
    }

}

Here's a cleanup version of the answer above.这是上面答案的清理版本。 This removes underscores, adds qualifiers, accessors, braces, etc.这将删除下划线、添加限定符、访问器、大括号等。

public class SelectedItemsBehavior : Behavior<RadGridView>
{
    private bool collectionChangedSuspended;

    /// <summary>
    /// Called after the behavior is attached to an AssociatedObject.
    /// </summary>
    /// <remarks>
    /// Override this to hook up functionality to the AssociatedObject.
    /// </remarks>
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.SelectedItems.CollectionChanged += this.GridSelectedItemsCollectionChanged;
    }

    /// <summary>
    /// Getter/Setter for DependencyProperty, bound to the DataContext's SelectedItems ObservableCollection
    /// </summary>
    public INotifyCollectionChanged SelectedItems
    {
        get => (INotifyCollectionChanged)this.GetValue(SelectedItemsProperty);
        set => this.SetValue(SelectedItemsProperty, value);
    }

    /// <summary>
    /// Dependency Property "SelectedItems" is target of binding to DataContext's SelectedItems
    /// </summary>
    public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.Register("SelectedItems", typeof(INotifyCollectionChanged), typeof(SelectedItemsBehavior), new PropertyMetadata(OnSelectedItemsPropertyChanged));

    /// <summary>
    /// PropertyChanged handler for DependencyProperty "SelectedItems"
    /// </summary>
    private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
    {
        INotifyCollectionChanged collection = args.NewValue as INotifyCollectionChanged;
        if (collection != null)
        {
            collection.CollectionChanged += ((SelectedItemsBehavior)target).ContextSelectedItemsCollectionChanged;
        }
    }

    /// <summary>
    /// Will be called, when the Network's SelectedItems collection changes
    /// </summary>
    private void ContextSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (this.collectionChangedSuspended)
        {
            return; 
        }

        this.collectionChangedSuspended = true;

        if (e.NewItems != null)
        {
            foreach (object item in e.NewItems)
            {
                this.AssociatedObject.SelectedItems.Add(item);
            }
        }

        if (e.OldItems != null)
        {
            foreach (object item in e.OldItems)
            {
                this.AssociatedObject.SelectedItems.Remove(item);
            }
        }

        this.collectionChangedSuspended = false;
    }

    /// <summary>
    /// Will be called when the GridView's SelectedItems collection changes
    /// </summary>
    private void GridSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (this.collectionChangedSuspended)
        {
            return;
        }

        this.collectionChangedSuspended = true;

        if (e.NewItems != null)
        {
            foreach (object item in e.NewItems)
            {
                ((IList)this.SelectedItems).Add(item);
            }
        }

        if (e.OldItems != null)
        {
            foreach (object item in e.OldItems)
            {
                ((IList)this.SelectedItems).Remove(item);
            }
        }

        this.collectionChangedSuspended = false;
    }
}

There are a situation where you cannot add boolean (ObseravbleCollection for example.存在无法添加 boolean 的情况(例如 ObseravbleCollection。

Please take a look at this solution.请看一下这个解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM