我想在我的 ListBox 中以编程方式选择多个项目。因此,为了尽可能使mvvm友好,我创建了一个从ListBox继承的自定义控件。在这个自定义控件中,我创建了一个依赖属性,允许更改项目选项。以下是 OnPropertyChanged 部分的代码:
private static void OnSetSelectionToPropertyChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
InitializableListBox list = d as InitializableListBox;
Dictionary<int, string> toSelect = e.NewValue as Dictionary<int, string>;
if (toSelect == null)
return;
list.SetSelectedItems(toSelect);
}
选择效果很好,但此解决方案不会引发OnSelectionChanged
事件
所以我也尝试了:
private static void OnSetSelectionToPropertyChanged
(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
InitializableListBox list = d as InitializableListBox;
Dictionary<int, string> toSelect = e.NewValue as Dictionary<int, string>;
if (toSelect == null)
return;
SelectionChangedEventArgs e_selChanged;
List<Object> removed = new List<object>();
List<Object> added = new List<object>();
//Clear the SelectedItems list
while(list.SelectedItems.Count > 0)
{
removed.Add(list.SelectedItems[0]);
list.SelectedItems.RemoveAt(0);
}
//Add each selected items
foreach (var item in toSelect)
{
list.SelectedItems.Add(item);
added.Add(list.SelectedItems[list.SelectedItems.Count - 1]);
}
//Raise the SelectionChanged event
e_selChanged = new SelectionChangedEventArgs(SelectionChangedEvent,removed,added);
list.OnSelectionChanged(e_selChanged);
}
但这并不好。我想我并没有以正确的方式处理这个事件,所以如果你能帮助我,那就太棒了。
提前致谢。
我找到了另一个解决方案(实际上更多的是黑客攻击)而不是@NETscape。我认为它不是更好,但似乎工作得很好,而且它可能更容易。
诀窍是创建一个依赖属性,允许您访问SelectedItems
属性(在普通ListBox
上只读取且不可绑定)。这是我的自定义ListBox的代码:
public class InitializableListBox : ListBox
{
public InitializableListBox()
{
SelectionChanged += CustomSelectionChanged;
}
private void CustomSelectionChanged(object sender, SelectionChangedEventArgs e)
{
InitializableListBox s = sender as InitializableListBox;
if (s == null)
return;
s.CustomSelectedItems = s.SelectedItems;
}
#region CustomSelectedItems DependyProperty
public static DependencyProperty CustomSelectedItemsProperty =
DependencyProperty.RegisterAttached("CustomSelectedItems",
typeof(System.Collections.IList),typeof(InitializableListBox),
new PropertyMetadata(null, OnCustomSelectedItemsPropertyChanged));
public System.Collections.IList CustomSelectedItems
{
get
{
return (System.Collections.IList)GetValue(CustomSelectedItemsProperty);
}
set
{
SetValue(CustomSelectedItemsProperty, value);
}
}
private static void OnCustomSelectedItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
InitializableListBox list = d as InitializableListBox;
System.Collections.IList toSelect = e.NewValue as System.Collections.IList;
if (toSelect == null)
return;
list.SetSelectedItems(toSelect);
}
#endregion
}
答案 0 :(得分:1)
请参阅this
如果将ItemsSource设置为集合,并且集合实现INPC
中的对象,则可以设置Style
上的ListViewItem
以使用绑定对象IsSelected
属性。
请参阅this回答了解我的意思。
假设您有ItemsSource="{Binding Items}"
,那么您可以执行以下操作:
Items.Where(item => item.IsSelected == true);
返回所选项目列表。
您也可以Items[0].IsSelected = true;
以编程方式选择项目。
简而言之,您不必使用自定义控件在ListView上实现多个选择。
修改强>
我在实施Telerik的RadGridView
时遇到了虚拟化问题。我用一种行为来解决这个问题,似乎有效:
public class RadGridViewExt : Behavior<RadGridView>
{
private RadGridView Grid
{
get
{
return AssociatedObject as RadGridView;
}
}
public INotifyCollectionChanged SelectedItems
{
get { return (INotifyCollectionChanged)GetValue(SelectedItemsProperty); }
set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(INotifyCollectionChanged), typeof(RadGridViewExt), new PropertyMetadata(OnSelectedItemsPropertyChanged));
private static void OnSelectedItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
var collection = args.NewValue as INotifyCollectionChanged;
if (collection != null)
{
collection.CollectionChanged += ((RadGridViewExt)target).ContextSelectedItemsCollectionChanged;
}
}
protected override void OnAttached()
{
base.OnAttached();
Grid.SelectedItems.CollectionChanged += GridSelectedItemsCollectionChanged;
}
void ContextSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UnsubscribeFromEvents();
Transfer(SelectedItems as IList, AssociatedObject.SelectedItems);
SubscribeToEvents();
}
void GridSelectedItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
UnsubscribeFromEvents();
Transfer(AssociatedObject.SelectedItems, SelectedItems as IList);
SubscribeToEvents();
}
private void SubscribeToEvents()
{
AssociatedObject.SelectedItems.CollectionChanged += GridSelectedItemsCollectionChanged;
if (SelectedItems != null)
{
SelectedItems.CollectionChanged += ContextSelectedItemsCollectionChanged;
}
}
private void UnsubscribeFromEvents()
{
AssociatedObject.SelectedItems.CollectionChanged -= GridSelectedItemsCollectionChanged;
if (SelectedItems != null)
{
SelectedItems.CollectionChanged -= ContextSelectedItemsCollectionChanged;
}
}
public static void Transfer(IList source, IList target)
{
if (source == null || target == null)
return;
target.Clear();
foreach (var o in source)
{
target.Add(o);
}
}
}
RadGridView内部控件:
<i:Interaction.Behaviors>
<local:RadGridViewExt SelectedItems="{Binding SelectedItems}" />
</i:Interaction.Behaviors>
,其中
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
并记得添加对Interactivity assembly的引用。
答案 1 :(得分:0)
ListBox有一个名为SelectionMode
的属性。您可以将其设置为Multiple
以启用多项选择。
<ListBox x:Name="MyListBox" SelectionMode="Multiple"/>
您可以使用SelectedItems
属性获取之后的所有选定项目。