我通过绑定到IsSelected来跟踪MVVM设计中的ListView选择更改。我还需要通过启用IsSynchronizedWithCurrentItem来跟踪当前项目。
我发现当我有两个ListView绑定到同一个集合时,我得到 InvalidOperationException :“集合被修改;枚举操作可能无法执行。”它似乎是两个ListView之间的同步错误;一个是触发PropertyChanged事件而另一个是更新Selector?
我无法弄清楚除了放弃使用IsSynchronizedWithCurrentItem并自行管理之外如何解决这个问题。有什么想法吗?
感谢。
后面的ViewModel和代码:
public class Item : INotifyPropertyChanged
{
public string Name{ get; set; }
public bool IsSelected
{
get { return isSelected; }
set { isSelected = value; OnPropertyChanged("IsSelected"); }
}
private bool isSelected;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ViewModel
{
public ViewModel()
{
Items = new ObservableCollection<Item>()
{
new Item(){Name = "Foo"},
new Item(){Name = "Bar"}
};
}
public ObservableCollection<Item> Items { get; private set; }
}
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="100" Width="100">
<StackPanel>
<ListView DataContext="{Binding Items}" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True" SelectionMode="Single">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView DataContext="{Binding Items}" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True" SelectionMode="Single">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Window>
答案 0 :(得分:4)
我无法直接解决您的问题。但是,我确实有一个可行的解决方案。
您可以做的是在视图模型上引入名为“SelectedItem”的第二个属性,该属性将保存对ListView中所选项目的引用。此外,在View Model中,您可以监听PropertyChanged事件。如果关联的属性名称为IsSelected,则将SelectedItem属性更新为该事件的发送者(现在具有IsSelected的项= true)。然后,您可以将ListView的SelectedItem属性绑定到ViewModel类的同名属性。
修改后的ViewModel类的代码如下所示。
public class ViewModel : INotifyPropertyChanged
{
private Item _selectedItem;
public ViewModel()
{
Items = new ObservableCollection<Item>()
{
new Item {Name = "Foo"},
new Item {Name = "Bar"}
};
foreach ( Item anItem in Items )
{
anItem.PropertyChanged += OnItemIsSelectedChanged;
}
}
public ObservableCollection<Item> Items { get; private set; }
public Item SelectedItem
{
get { return _selectedItem; }
set
{
// only update if the value is difference, don't
// want to send false positives
if ( _selectedItem == value )
{
return;
}
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnItemIsSelectedChanged(object sender, PropertyChangedEventArgs e)
{
if ( e.PropertyName != "IsSelected" )
{
return;
}
SelectedItem = sender as Item;
}
private void OnPropertyChanged(string propertyName)
{
if ( PropertyChanged != null )
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
答案 1 :(得分:0)
当您绑定到列表框IsSelected
并使用SelectionMode='Single'
我发现更改了SelectionMode = 'Multiple'
然后只是向ViewModel添加了逻辑,以确保只有一个项目的IsSelected设置为true。