MIa*_*sca 20 prism mvvm silverlight-3.0
我在使用棱镜的SL3应用程序中有一个多选列表框,我需要在我的viewmodel中包含列表框中当前所选项目的集合.
viewmodel对视图一无所知,因此它无权访问列表框控件.此外,我需要能够从viewmodel清除列表框中的选定项目.
不知道如何解决这个问题
谢谢迈克尔
Bri*_*sio 40
因此,假设您有一个具有以下属性的ViewModel:
public ObservableCollection<string> AllItems { get; private set; }
public ObservableCollection<string> SelectedItems { get; private set; }
Run Code Online (Sandbox Code Playgroud)
首先将AllItems集合绑定到ListBox:
<ListBox x:Name="MyListBox" ItemsSource="{Binding AllItems}" SelectionMode="Multiple" />
Run Code Online (Sandbox Code Playgroud)
问题是ListBox上的SelectedItems属性不是DependencyProperty.这非常糟糕,因为您无法将其绑定到ViewModel中的某些内容.
第一种方法是将此逻辑放在代码隐藏中,以调整ViewModel:
public MainPage()
{
InitializeComponent();
MyListBox.SelectionChanged += ListBoxSelectionChanged;
}
private static void ListBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = sender as ListBox;
if(listBox == null) return;
var viewModel = listBox.DataContext as MainVM;
if(viewModel == null) return;
viewModel.SelectedItems.Clear();
foreach (string item in listBox.SelectedItems)
{
viewModel.SelectedItems.Add(item);
}
}
Run Code Online (Sandbox Code Playgroud)
这种方法可行,但实在太难看了.我首选的方法是将此行为提取为"附加行为".如果这样做,您可以完全消除代码隐藏并在XAML中进行设置.奖励是这个"附加行为"现在可以在任何ListBox中重复使用:
<ListBox ItemsSource="{Binding AllItems}" Demo:SelectedItems.Items="{Binding SelectedItems}" SelectionMode="Multiple" />
Run Code Online (Sandbox Code Playgroud)
以下是附加行为的代码:
public static class SelectedItems
{
private static readonly DependencyProperty SelectedItemsBehaviorProperty =
DependencyProperty.RegisterAttached(
"SelectedItemsBehavior",
typeof(SelectedItemsBehavior),
typeof(ListBox),
null);
public static readonly DependencyProperty ItemsProperty = DependencyProperty.RegisterAttached(
"Items",
typeof(IList),
typeof(SelectedItems),
new PropertyMetadata(null, ItemsPropertyChanged));
public static void SetItems(ListBox listBox, IList list) { listBox.SetValue(ItemsProperty, list); }
public static IList GetItems(ListBox listBox) { return listBox.GetValue(ItemsProperty) as IList; }
private static void ItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as ListBox;
if (target != null)
{
GetOrCreateBehavior(target, e.NewValue as IList);
}
}
private static SelectedItemsBehavior GetOrCreateBehavior(ListBox target, IList list)
{
var behavior = target.GetValue(SelectedItemsBehaviorProperty) as SelectedItemsBehavior;
if (behavior == null)
{
behavior = new SelectedItemsBehavior(target, list);
target.SetValue(SelectedItemsBehaviorProperty, behavior);
}
return behavior;
}
}
public class SelectedItemsBehavior
{
private readonly ListBox _listBox;
private readonly IList _boundList;
public SelectedItemsBehavior(ListBox listBox, IList boundList)
{
_boundList = boundList;
_listBox = listBox;
_listBox.SelectionChanged += OnSelectionChanged;
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
_boundList.Clear();
foreach (var item in _listBox.SelectedItems)
{
_boundList.Add(item);
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
我希望有真正的双向绑定,以便ListBox选择反映底层ViewModel的SelectedItems集合中包含的项目.这允许我通过ViewModel层中的逻辑来控制选择.
以下是我对SelectedItemsBehavior类的修改.如果ViewModel属性实现INotifyCollectionChanged(例如,由ObservableCollection <T>类型实现),它们将ListBox.SelectedItems集合与基础ViewModel属性同步.
public static class SelectedItems
{
private static readonly DependencyProperty SelectedItemsBehaviorProperty =
DependencyProperty.RegisterAttached(
"SelectedItemsBehavior",
typeof(SelectedItemsBehavior),
typeof(ListBox),
null);
public static readonly DependencyProperty ItemsProperty = DependencyProperty.RegisterAttached(
"Items",
typeof(IList),
typeof(SelectedItems),
new PropertyMetadata(null, ItemsPropertyChanged));
public static void SetItems(ListBox listBox, IList list) { listBox.SetValue(ItemsProperty, list); }
public static IList GetItems(ListBox listBox) { return listBox.GetValue(ItemsProperty) as IList; }
private static void ItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as ListBox;
if (target != null)
{
AttachBehavior(target, e.NewValue as IList);
}
}
private static void AttachBehavior(ListBox target, IList list)
{
var behavior = target.GetValue(SelectedItemsBehaviorProperty) as SelectedItemsBehavior;
if (behavior == null)
{
behavior = new SelectedItemsBehavior(target, list);
target.SetValue(SelectedItemsBehaviorProperty, behavior);
}
}
}
public class SelectedItemsBehavior
{
private readonly ListBox _listBox;
private readonly IList _boundList;
public SelectedItemsBehavior(ListBox listBox, IList boundList)
{
_boundList = boundList;
_listBox = listBox;
_listBox.Loaded += OnLoaded;
_listBox.DataContextChanged += OnDataContextChanged;
_listBox.SelectionChanged += OnSelectionChanged;
// Try to attach to INotifyCollectionChanged.CollectionChanged event.
var notifyCollectionChanged = boundList as INotifyCollectionChanged;
if (notifyCollectionChanged != null)
{
notifyCollectionChanged.CollectionChanged += OnCollectionChanged;
}
}
void UpdateListBoxSelection()
{
// Temporarily detach from ListBox.SelectionChanged event
_listBox.SelectionChanged -= OnSelectionChanged;
// Synchronize selected ListBox items with bound list
_listBox.SelectedItems.Clear();
foreach (var item in _boundList)
{
// References in _boundList might not be the same as in _listBox.Items
var i = _listBox.Items.IndexOf(item);
if (i >= 0)
{
_listBox.SelectedItems.Add(_listBox.Items[i]);
}
}
// Re-attach to ListBox.SelectionChanged event
_listBox.SelectionChanged += OnSelectionChanged;
}
void OnLoaded(object sender, RoutedEventArgs e)
{
// Init ListBox selection
UpdateListBoxSelection();
}
void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// Update ListBox selection
UpdateListBoxSelection();
}
void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Update ListBox selection
UpdateListBoxSelection();
}
void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Temporarily deattach from INotifyCollectionChanged.CollectionChanged event.
var notifyCollectionChanged = _boundList as INotifyCollectionChanged;
if (notifyCollectionChanged != null)
{
notifyCollectionChanged.CollectionChanged -= OnCollectionChanged;
}
// Synchronize bound list with selected ListBox items
_boundList.Clear();
foreach (var item in _listBox.SelectedItems)
{
_boundList.Add(item);
}
// Re-attach to INotifyCollectionChanged.CollectionChanged event.
if (notifyCollectionChanged != null)
{
notifyCollectionChanged.CollectionChanged += OnCollectionChanged;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22936 次 |
| 最近记录: |