Как привязать команду к событию ItemSelectionChanged в ListView?

#c# #.net #wpf #mvvm #command

#c# #.net #wpf #mvvm #команда

Вопрос:

Возможно ли выполнить привязку команды к ItemSelectionChanged в ListView? Как? Если это невозможно, есть ли другой способ вызвать команду при изменении выбора в представлении списка?

Комментарии:

1. Вы не можете привязать SelectedItems к свойству?

2. @Derek: я думаю, это тоже ответ

3. Я получил это сообщение: Ошибка 1 Свойство ‘SelectedItems’ доступно только для чтения и не может быть установлено из разметки.

4. Я не понимаю, почему кто-то должен отклонять это.

Ответ №1:

Да — платформа MVVM-light поддерживает привязку команд к маршрутизируемым событиям. Смотрите http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx

 <Rectangle Fill="White"
           Stroke="Black"
           Width="200"
           Height="100">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <cmd:EventToCommand Command="{Binding TestCommand,
                                          Mode=OneWay}"
               CommandParameter="{Binding Text,
                                  ElementName=MyTextBox,
                                  Mode=OneWay}"
               MustToggleIsEnabledValue="True" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Rectangle>
  

Ответ №2:

сначала я использую в своем проекте команду, в которой SelectedItems a передается в качестве параметра. недостатком этого подхода является то, что пользователь должен нажать командную кнопку, чтобы начать действие, но в большинстве случаев это соответствует моим требованиям.

для достижения того, чего вы хотите, есть что-то вроде опубликованного erash — использовать своего рода поведение EventToCommand, подобное поведению mvvm-light.

другой способ — создать прикрепленное поведение для привязки к выбранным элементам в вашей viewmodel. вы должны адаптировать следующий код к ListView или создать что-то более общее 🙂

 <DataGrid AttachedProperties:DatagridService.SelectedItemsSource="{Binding SelectedItems, Mode=OneWay}" />
  

ViewModel:

 public ObservableCollection<object> SelectedItems//init collection just ONCE!
    {
        get
        {
            if (this.selectedItems == null)
            {
                this.selectedItems = new ObservableCollection<object>();
                this.selectedItems.CollectionChanged  =
                    new System.Collections.Specialized.NotifyCollectionChangedEventHandler(SelectedItemsCollectionChanged);
            }
            return this.selectedItems;
        }

    }

    private void SelectedItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        //this is called when ever the selecteditems changed
    }
  

Прикрепленное поведение:

 public static class DatagridService
{
    #region SelectedItemSource

    #region Attached Property Declaration

    /// <summary>
    /// Identifies the ListBoxExtension.SelectedItemsSource attached property.
    /// </summary>
    public static readonly DependencyProperty SelectedItemsSourceProperty =
       DependencyProperty.RegisterAttached(
          "SelectedItemsSource",
          typeof(IList),
          typeof(DatagridService),
          new PropertyMetadata(
              null,
              new PropertyChangedCallback(OnSelectedItemsSourceChanged)));

    #endregion

    #region Attached Property Accessors

    /// <summary>
    /// Gets the IList that contains the values that should be selected.
    /// </summary>
    /// <param name="element">The ListBox to check.</param>
    public static IList GetSelectedItemsSource(DependencyObject element)
    {
        if (element == null)
            throw new ArgumentNullException("element");

        return (IList)element.GetValue(SelectedItemsSourceProperty);
    }

    /// <summary>
    /// Sets the IList that contains the values that should be selected.
    /// </summary>
    /// <param name="element">The ListBox being set.</param>
    /// <param name="value">The value of the property.</param>
    public static void SetSelectedItemsSource(DependencyObject element, IList value)
    {
        if (element == null)
            throw new ArgumentNullException("element");

        element.SetValue(SelectedItemsSourceProperty, value);
    }

    #endregion

    #region IsResynchingProperty

    // Used to set a flag on the ListBox to avoid reentry of SelectionChanged due to
    // a full syncronisation pass
    private static readonly DependencyPropertyKey IsResynchingPropertyKey =
       DependencyProperty.RegisterAttachedReadOnly(
            "IsResynching",
            typeof(bool),
            typeof(DatagridService),
            new PropertyMetadata(false));

    #endregion

    #region Private Static Methods

    private static void OnSelectedItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DataGrid grd = d as DataGrid;
        if (grd == null)
            throw new InvalidOperationException("The DataGridExtension.SelectedItemsSource attached "  
               "property can only be applied to DataGrid controls.");

        grd.SelectionChanged -= new SelectionChangedEventHandler(OnDataGridSelectionChanged);

        if (e.NewValue != null)
        {
            ListenForChanges(grd);
        }

        BindingExpression bexp = grd.GetBindingExpression(SelectedItemsSourceProperty);
        if (bexp != null)
            bexp.UpdateSource();

    }

    private static void ListenForChanges(DataGrid grd)
    {
        // Wait until the element is initialised
        if (!grd.IsInitialized)
        {
            EventHandler callback = null;
            callback = delegate
            {
                grd.Initialized -= callback;
                ListenForChanges(grd);
            };
            grd.Initialized  = callback;
            return;
        }

        grd.SelectionChanged  = new SelectionChangedEventHandler(OnDataGridSelectionChanged);
        ResynchList(grd);
    }

    private static void OnDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        DataGrid grd = sender as DataGrid;
        if (grd != null)
        {
            bool isResynching = (bool)grd.GetValue(IsResynchingPropertyKey.DependencyProperty);
            if (isResynching)
                return;

            IList list = GetSelectedItemsSource(grd);

            if (list != null)
            {
                foreach (object obj in e.RemovedItems)
                {
                    if (list.Contains(obj))
                        list.Remove(obj);
                }
                foreach (object obj in e.AddedItems)
                {

                    if (!list.Contains(obj))
                        list.Add(obj);
                }
            }
        }
    }

    private static void ResynchList(DataGrid grd)
    {
        if (grd != null)
        {
            grd.SetValue(IsResynchingPropertyKey, true);
            IList list = GetSelectedItemsSource(grd);

            if (grd.SelectionMode == DataGridSelectionMode.Single)
            {
                grd.SelectedItem = null;
                if (list != null)
                {
                    if (list.Count > 1)
                    {
                        // There is more than one item selected, but the listbox is in Single selection mode
                        throw new InvalidOperationException("DataGrid is in Single selection mode, but was given more than one selected value.");
                    }

                    if (list.Count == 1)
                        grd.SelectedItem = list[0];
                }
            }
            else
            {
                grd.SelectedItems.Clear();
                if (list != null)
                {
                    foreach (object obj in grd.Items)
                        if (list.Contains(obj))
                            grd.SelectedItems.Add(obj);
                }
            }

            grd.SetValue(IsResynchingPropertyKey, false);
        }
    }

    #endregion

    #endregion
}