我正在使用带有Caliburn Micro和严格的MVVM模式的.NET Framework 4.7.2创建WPF网络扫描应用程序。我已经经历了所有与此类似的问题,但尚未找到解决方案。我不使用代码隐藏,因此我正在尝试做所有MVVM样式。
“我的列表框”最初是空的,并且向其中添加了项,直到完成扫描为止。此后,我尝试在ListBox中选择1个或多个项目,即使在视觉上可以选择多个项目,但我发现的问题是我无法使用SelectedItem属性将ListBox视图中的SelectedItem绑定。即我的ViewModel中的SelectedItem属性不会更新,并保持为null。
我希望我的SelectedItems集合随着选择更多项目而增加。
我尝试了以下方法:
Binding the IsSelected property of ListBoxItem to DataContext of Itemssource
到目前为止,这些方法还没有奏效。
示例模型:
public class ExampleModel
{
protected int _id;
protected string _name;
public ExampleModel()
{
}
public ExampleModel(int _id, string _name)
{
this.Id = _id;
this.Name = _name;
}
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
return this.Name == Name && this.Id == Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
ViewModel示例:
public class ExampleViewModel : Screen
{
private IEventAggregator _events;
public ExampleViewModel(IEventAggregator events)
{
// Initialize collection
BindableCollection<ExampleModel> SelectedItems = new BindableCollection<ExampleModel>();
_events = events;
}
private BindableCollection<ExampleModel> _selectedItems;
public BindableCollection<ExampleModel> SelectedItems
{
get { return _selectedItems; }
set
{
// SelectedItems remains NULL
_selectedItems = value;
NotifyOfPropertyChange(() => Items);
}
}
private ExampleModel _selectedItem;
public ExampleModel SelectedItem
{
get { return _selectedItem; }
set
{
// CODE NOT UPDATING SELECTED ITEM VALUE!
_selectedItem = value;
NotifyOfPropertyChange(() => SelectedItem);
NotifyOfPropertyChange(() => SelectedItems);
}
}
// Initialize list
private HashSet<ExampleModel> _exampleList = new HashSet<ExampleModel>();
public HashSet<ExampleModel> ExampleList
{
get { return _exampleList; }
set { _exampleList = value; }
}
private async Task AddItem(ExampleModel item)
{
// A task to asyncrhonously add unique items to list
await Task.Run(() =>
_exampleList.Add(item));
Items = new BindableCollection<ExampleModel>(_exampleList);
NotifyOfPropertyChange(() => Items);
}
private BindableCollection<ExampleModel> _items;
public BindableCollection<ExampleModel> Items
{
get { return _items; }
set
{
_items = value;
NotifyOfPropertyChange(() => Items);
}
}
// Begin adding items to list
public async void Add()
{
for (int i = 0; i<10; i++)
{
// do something
var item = new ExampleModel
{
Id = i + 1,
Name = i.ToString()
};
await AddItem(item);
}
}
// Button to start process
public void Start()
{
Add();
}
}
示例视图:
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Item"
HorizontalContentAlignment="Stretch"
ScrollViewer.IsDeferredScrollingEnabled="True"
Margin="8 0 0 0"
Grid.Column="1"
ItemsSource="{Binding Path= Items}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
SelectionMode="Multiple"
b:SelectedItemsBehavior.SelectedItems="{Binding SelectedItems, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- Id -->
<TextBlock
Text="{Binding Id}"
Grid.Row="0"
Grid.Column="0"
/>
<!-- Name -->
<TextBlock
Text="{Binding Name}"
Grid.Row="0"
Grid.Column="1"
Margin="10"
/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
Selected Items Behavior类:
公共类SelectedItemsBehavior {
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.RegisterAttached("SelectedItems",
typeof(INotifyCollectionChanged), typeof(SelectedItemsBehavior),
new PropertyMetadata(default(IList), OnSelectedItemsChanged));
public static void SetSelectedItems(DependencyObject d, INotifyCollectionChanged value)
{
d.SetValue(SelectedItemsProperty, value);
}
public static IList GetSelectedItems(DependencyObject element)
{
return (IList)element.GetValue(SelectedItemsProperty);
}
private static void OnSelectedItemsChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
IList selectedItems = null;
void CollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs args)
{
if (args.OldItems != null)
foreach (var item in args.OldItems)
if (selectedItems.Contains(item))
selectedItems.Remove(item);
if (args.NewItems != null)
foreach (var item in args.NewItems)
if (!selectedItems.Contains(item))
selectedItems.Add(item);
};
if (d is MultiSelector multiSelector)
{
selectedItems = multiSelector.SelectedItems;
multiSelector.SelectionChanged += OnSelectionChanged;
}
if (d is ListBox listBox)
{
selectedItems = listBox.SelectedItems;
listBox.SelectionMode = SelectionMode.Multiple;
listBox.SelectionChanged += OnSelectionChanged;
}
if (selectedItems == null) return;
if (e.OldValue is INotifyCollectionChanged)
(e.OldValue as INotifyCollectionChanged).CollectionChanged
-= CollectionChangedEventHandler;
if (e.NewValue is INotifyCollectionChanged)
(e.NewValue as INotifyCollectionChanged).CollectionChanged
+= CollectionChangedEventHandler;
}
private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var s = sender as DependencyObject;
if (!GetIsBusy(s))
{
SetIsBusy(s, true);
var list = GetSelectedItems((DependencyObject)sender);
foreach (var item in e.RemovedItems)
if (list.Contains(item)) list.Remove(item);
foreach (var item in e.AddedItems)
if (!list.Contains(item)) list.Add(item);
SetIsBusy(s, false);
}
}
private static readonly DependencyProperty IsBusyProperty =
DependencyProperty.RegisterAttached("IsBusy", typeof(bool),
typeof(SelectedItemsBehavior), new PropertyMetadata(default(bool)));
private static void SetIsBusy(DependencyObject element, bool value)
{
element.SetValue(IsBusyProperty, value);
}
private static bool GetIsBusy(DependencyObject element)
{
return (bool)element.GetValue(IsBusyProperty);
}
}
我希望可以填充SelectedItems集合,但输出仍为null。 我希望选择任何项目时,SelectedItem的值都会更新,但会为空。