поиск выбранных элементов в Telerik RadGridView с использованием шаблона MVVM

Я использую Telerik RadGridView в своем приложении, и в нем есть элемент GridViewSelectColumn, который позволяет мне выбирать различные элементы в сетке. У меня есть кнопка, которая работает с этим выбором, но я не знаю, как получить список выбранных элементов. Проблема в том, что я использую шаблон MVVM с Caliburn.Micro. Нужно ли мне найти элемент управления в представлении и просмотреть список выбранных элементов? Кажется, что много работы для простой задачи. Буду признателен за любые идеи.


person dna86    schedule 29.06.2011    source источник


Ответы (5)


Проблема с RadGridView от Telerik заключается в том, что его коллекция SelectedItem доступна только для чтения, поэтому вы не можете выполнить двустороннюю привязку к SelectedItems.

Обходным путем для этого является использование пользовательского поведения для синхронизации между RadGridView и вашей коллекцией SelectedItem ViewModels.

Вы можете использовать это поведение:

// 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;
    }

}

Используйте это поведение с RadGridViews следующим образом:

<i:Interaction.Behaviors>
   <behaviors:SelectedSyncBehavior SelectedItems="{Binding ViewModel.SelectedItems}" />
</i:Interaction.Behaviors>
person Knasterbax    schedule 25.02.2014
comment
это должен быть выбранный ответ! В блогах телерика, похоже, не было полного решения, найденного здесь. - person Michael; 17.11.2014
comment
Не забудьте создать экземпляр свойства коллекции SelectedItems, к которому привязано, потратил 15 минут на это... - person Dean Kuga; 18.10.2017

Добавьте 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);
            }
        }

пример кода — битбакет

скачать

person Derek Beattie    schedule 30.06.2011
comment
Я знаю, что это было давно, но я пытаюсь заставить это работать. Не могли бы вы показать XAML, пожалуйста, так как я не могу заставить работать привязку. В качестве альтернативы вы могли бы сделать источник доступным для загрузки без необходимости проходить через битбакет, поскольку я не могу получить его там. - person Dave; 29.07.2014
comment
@Dave добавил загрузку репо - person Derek Beattie; 29.07.2014
comment
Спасибо, Дерек. Кажется, я что-то недопонимаю. Я вижу, что у вас есть свойство IsSelected в Customer, но я не могу найти привязку к нему в XAML. - person Dave; 31.07.2014
comment
@Dave Дэйв, я полагаю, что это обрабатывается системой управления Telerik и автоматически сгенерированными столбцами. Свойство bool IsSelected будет отображаться как флажок. - person Derek Beattie; 04.08.2014

Вот очищенная копия класса @Knasterbax с явными приватными модификаторами и нулевым распространением:

// 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;
    }

}
person Dean Kuga    schedule 17.10.2017

Вот очищенная версия ответа выше. Это удаляет символы подчеркивания, добавляет квалификаторы, аксессоры, фигурные скобки и т. д.

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;
    }
}
person LawMan    schedule 13.12.2017

Бывают ситуации, когда вы не можете добавить логическое значение (например, ObseravbleCollection.

Пожалуйста, взгляните на это решение.

person Jviaches    schedule 28.10.2012
comment
У кого-нибудь этот пост в блоге работает? Я попробовал, и RadGridView, похоже, даже не имеет свойства SelectedItems... - person GP24; 01.08.2013