【问题标题】:AttachedProperty vs behavior to get SelectedItems in the ViewModelAttachedProperty 与在 ViewModel 中获取 SelectedItems 的行为
【发布时间】:2018-11-17 20:20:52
【问题描述】:

我必须选择在 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中就是这样使用的,例如在Listbox中:

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 的最佳选择是什么。

谢谢。

【问题讨论】:

  • 为什么不将控件的 SelectedItems 属性绑定到视图模型属性?这就是 MVVM 的全部意义所在,并且比您展示的任何一个选项都简单得多(这对于要求来说都是多余的)
  • @AvrohomYisroel 这是不可能的,因为 SelectedItems 是只读的。因此,它是不可绑定的。正因为如此,每个人都在创造各种解决方法,比如问题中的两个解决方案。真的丑吗?是的。让我们感谢 Microsoft 从未修复此问题。

标签: c# wpf attached-properties attachedbehaviors


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-28
    • 2021-09-23
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-08
    相关资源
    最近更新 更多