AttachedProperty与行为的关系,以在ViewModel中获取SelectedItems

时间:2018-11-17 20:20:53

标签: c# wpf attached-properties attachedbehaviors

我必须选择在ViewModel中获取SelectedItems。

附加属性如下:

public class ListBoxSelectedItemsAttachedProperty
    {
        #region SelectedItems
        ///
        /// SelectedItems Attached Dependency Property
        ///
        public static readonly DependencyProperty SelectedItemsProperty =
        DependencyProperty.RegisterAttached("SelectedItems", typeof(IList),
        typeof(ListBoxSelectedItemsAttachedProperty),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        new PropertyChangedCallback(OnSelectedItemsChanged)));

        public static IList GetSelectedItems(DependencyObject d)
        {
            return (IList)d.GetValue(SelectedItemsProperty);
        }

        public static void SetSelectedItems(DependencyObject d, IList value)
        {
            d.SetValue(SelectedItemsProperty, value);
        }

        private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListBox miLb = (ListBox)d;
            miLb.SelectionChanged += listBox_SelectionChanged;
        }

        private static void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListBox miLg = (ListBox)sender;
            //Get list box's selected items.
            IEnumerable miDgSelectedItems = miLg.SelectedItems;
            //Get list from model
            IList ModelSelectedItems = GetSelectedItems(miLg);

            //Update the model
            ModelSelectedItems.Clear();

            if (miLg.SelectedItems != null)
            {
                foreach (var item in miLg.SelectedItems)
                    ModelSelectedItems.Add(item);
            }
            SetSelectedItems(miLg, ModelSelectedItems);
        }
        #endregion
    }

在axml中,它是以这种方式使用的,例如在列表框中:

Behaviors:ListBoxSelectedItemsAttachedProperty.SelectedItems="{Binding MyPropertyInViewModel}"

附加的行为:

public class SelectedItemsBehavior : Behavior<MultiSelector>
    {
        protected override void OnAttached()
        {
            AssociatedObject.SelectionChanged += AssociatedObjectSelectionChanged;
        }
        protected override void OnDetaching()
        {
            AssociatedObject.SelectionChanged -= AssociatedObjectSelectionChanged;
        }

        void AssociatedObjectSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            List<object> selectedItemList = AssociatedObject.SelectedItems.Cast<object>().ToList();
            ObservableCollection<object> selectedItems = new ObservableCollection<object>(selectedItemList);
            SelectedItems = selectedItems;
        }
        public ObservableCollection<object> SelectedItems
        {
            get { return (ObservableCollection<object>)GetValue(SelectedItemsProperty); }
            set { SetValue(SelectedItemsProperty, value); }
        }
        public static readonly DependencyProperty SelectedItemsProperty =
            DependencyProperty.Register("SelectedItems"
                , typeof(ObservableCollection<object>)
                , typeof(SelectedItemsBehavior)
                ,
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    }

并且在axml中以这种方式使用,例如在DataGrid中:

<i:Interaction.Behaviors>
    <Behaviors:SelectedItemsBehavior SelectedItems="{Binding MyPropertyInViewModel}" />
</i:Interaction.Behaviors>

但是我真的不知道附加属性和附加行为之间的区别,以及在ViewModel中获取SelectedItems的最佳选择是什么。

谢谢。

1 个答案:

答案 0 :(得分:1)

在WPF中,基本上有两种不同的方式来实现附加行为。当依赖项属性的值更改时,您可以创建一个附加属性,并对其应用PropertyChangedCallback,以对其执行一些操作,或者扩展附加属性DependencyObject

另一种方法是创建一个从System.Windows.Interactivity.Behavior<T>派生的类。与创建带有回调的附加属性相比,这通常称为“混合”行为,它提供了封装行为功能的更好方法。 Blend行为也更易于设计,因为它们可以通过Blend中的拖放功能轻松地附加到UI中的可视元素,并且它们还提供了一种简单明了的方法来使用OnAttached附加和释放事件处理程序和OnDetaching方法。主要缺点是您不能在样式设置器中应用这些行为。

因此,如果您需要能够将自己的行为附加在Style中,请使用附加属性。否则,我宁愿使用混合行为。有一个示例,您可以根据需要绑定到on this blog的只读属性。