2009-06-12 15 views
3

私はIsSelectedにバインドすることで、MVVMデザインのListView選択の変更を追跡しています。 IsSynchronizedWithCurrentItemを有効にすることによって現在のアイテムを追跡する必要もあります。MVVM:リストへのバインドIsSynchronizedWithCurrentItemのトラッキング中にIsSelected

は、私は私は2つのListViewコントロールが同じコレクションに結合していたとき、私はInvalidOperationExceptionがを得ることを見つける:「コレクションが変更された。列挙操作が実行されない可能性は、」2つのリストビューの間synchonizationエラーのようです。 1つはPropertyChangedイベントをトリガーし、もう1つはSelectorをおそらく更新していますか?

私はIsSynchronizedWithCurrentItemの使用を控え、それを自分で管理する以外に、この問題を回避する方法を理解できません。何か案は?

ありがとうございました。

のViewModelと背後にあるコード:私はあなたの問題の直接の修正を提供することはできません

<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> 

答えて

3

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。しかし、私はうまくいくソリューションを持っています。

ViewModelには、ListViewで選択されているItemへの参照を保持する「SelectedItem」という2つ目のプロパティを導入することができます。さらに、View ModelではPropertyChangedイベントをリッスンします。関連付けられたプロパティ名がIsSelectedの場合、SelectedItemプロパティをそのイベントの送信者(IsSelected = trueを持つItem)に更新します。次に、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)); 
     } 
    } 
} 
+0

はい、実際これは私が現在問題を回避する方法です。それを追加すると、コレクションの変更に伴いPropertyChangedの登録を追加/削除するアイテムのCollectionChangedイベントを監視する必要があります。 – Terrence

+1

@terrenceもしこれが働いていれば、昨年より良い方法を見つけることができたら、彼の答えを受け入れるべきですか? –

0

問題は、あなたがリストボックスのIsSelectedに結合したときに起こるとSelectionMode='Single'

を使用しているようだ、私はその後SelectionMode = 'Multiple'とを変更するだけで一つだけのアイテムがして今までにあったことを確実にするためのViewModelにロジックを追加したことがわかりましたIsSelectedがtrueに設定されています。

関連する問題