2009-06-12 6 views
3

IsSelected에 바인딩하여 MVVM 디자인에서 ListView 선택 변경 내용을 추적하고 있습니다. IsSynchronizedWithCurrentItem을 활성화하여 현재 항목을 추적해야합니다.MVVM : 목록에 바인딩 IsSynchronizedWithCurrentItem을 추적하는 동안 IsSelected

가 나는 두 ListView에이 같은 컬렉션에 바인딩이있을 때 나는 InvalidOperationException이를 얻을 것을 발견 : . "컬렉션이 변경되었다 열거 작업이 실행되지 않을 수 있습니다는"두 가지의 ListView 사이의 개시 또는 종료 이벤트들이 발생 오류 것 같다; 하나는 PropertyChanged 이벤트를 트리거하는 반면 다른 하나는 Selector를 업데이트 할 것입니다.

저는 IsSynchronizedWithCurrentItem을 계속 사용하고 직접 관리하는 것 이외의 다른 방법을 생각해 낼 수 없습니다. 어떤 아이디어?

감사합니다.

뷰 모델 뒤에 코드 :

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> 

답변

3

내가 당신의 문제에 대한 직접 수정 프로그램을 제공 할 수 있습니다. 그러나, 나는 작동 할 해결책이있다.

ViewView에서 ListView에서 선택한 항목에 대한 참조를 보유하는 'SelectedItem'이라는 두 번째 속성을 소개 할 수 있습니다. 또한 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)); 
     } 
    } 
} 
+0

예, 실제로이 문제를 해결하기 위해 노력하고 있습니다. 나는 저를 위해 그것을 추가 할 것이고, CollectionChanged 이벤트를 모니터링하여 ItemsChanged 등록을 추가/제거 할 필요가 있습니다. – Terrence

+1

@terrence 작년에 더 나은 방법을 찾았다면 어떻게 대답 할 수 있겠습니까? –

0

문제는 당신이 바인딩 할 때 발생하는 것 같다 목록 상자의 IsSelectedSelectionMode='Single'

내가 SelectionMode = 'Multiple'와 뷰 모델에 다음 방금 추가 로직을 변경하면 함께 어느 하나의 항목 만 있다는 것을 보장하는 것을 발견 사용 IsSelected를 true로 설정합니다.