如何将Command绑定到ListView的ItemSelectionChanged事件?

时间:2011-05-25 02:44:51

标签: c# .net wpf mvvm command

是否可以将命令绑定到ListView的ItemSelectionChanged?怎么样?如果不可能,还有另一种方法可以在列表视图的选择发生变化时调用命令吗?

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分:0)

首先,我在我的项目中使用一个命令,其中selectedItems作为参数传递。这种方法的缺点是用户必须点击命令按钮才能启动操作,但这在大多数情况下都符合我的要求。

在实现你想要的东西的过程中就像发布了一个类似的东西 - 使用像mvvm-light这样的一种EventToCommand行为。

另一种方法是创建一个附加行为以绑定到viewmodel中的selecteditems。你必须将以下代码擅长ListView或创建更通用的东西:)

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

视图模型:

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
}