AttachedProperty 与在 ViewModel 中获取 SelectedItems 的行为
AttachedProperty vs behavior to get SelectedItems in the ViewModel
我必须选择在 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 的最佳选择是什么。
谢谢。
在 WPF 中实现附加行为基本上有两种不同的方法。您可以创建附加的 属性 并对其应用 PropertyChangedCallback
以在依赖项 属性 的值时对其附加的 DependencyObject
执行某些操作或扩展它所附加的 DependencyObject
变化。
另一种方法是创建一个从 System.Windows.Interactivity.Behavior<T>
派生的 class。这通常称为 "Blend" 行为,与创建带有回调的附加 属性 相比,它提供了一种更好的封装行为功能的方法。 Blend 行为也更容易设计友好,因为它们可以通过 Blend 中的拖放功能轻松附加到 UI 中的视觉元素,并且它们还提供了一种使用 OnAttached
和 OnDetaching
方法。主要缺点是您不能在样式设置器中应用这些行为。
因此,如果您需要能够在 Style
中附加您的行为,请使用附加的 属性。否则我宁愿使用混合行为。如果您有兴趣,这里有一个如何绑定到可用的只读属性的示例 on this blog。
我必须选择在 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 的最佳选择是什么。
谢谢。
在 WPF 中实现附加行为基本上有两种不同的方法。您可以创建附加的 属性 并对其应用 PropertyChangedCallback
以在依赖项 属性 的值时对其附加的 DependencyObject
执行某些操作或扩展它所附加的 DependencyObject
变化。
另一种方法是创建一个从 System.Windows.Interactivity.Behavior<T>
派生的 class。这通常称为 "Blend" 行为,与创建带有回调的附加 属性 相比,它提供了一种更好的封装行为功能的方法。 Blend 行为也更容易设计友好,因为它们可以通过 Blend 中的拖放功能轻松附加到 UI 中的视觉元素,并且它们还提供了一种使用 OnAttached
和 OnDetaching
方法。主要缺点是您不能在样式设置器中应用这些行为。
因此,如果您需要能够在 Style
中附加您的行为,请使用附加的 属性。否则我宁愿使用混合行为。如果您有兴趣,这里有一个如何绑定到可用的只读属性的示例 on this blog。