2015-09-09 4 views
0

Кажется, проблема с SelectedItems ListView при динамическом изменении ItemsPanel. Я реализовал MVVM в ListView, чей ItemSource привязан к коллекции моделей. Модель имеет 2 свойства, DisplayName (строка) и Selected (bool). И DataContext для списка содержит свойство ViewMode (bool).Элементы списка избранных элементов списка ListView ListView при изменении ItemsPanel

Настройка заключается в том, что свойство IsSelected объекта ListViewItem привязано к свойству Selected и изменениям ItemsPanel ListView, когда я изменил ViewMode, нажав кнопку.

Проблема заключается в том, что при выборе выбранного элемента в ListView и изменении режима ViewMode количество выбранных элементов ListView увеличивается, даже если выбранные элементы не изменяются.

Примечание: В моей настройке в ListView есть только 1 элемент, но счетчик SelectedItems увеличивается каждый раз, когда я менял ViewMode.

Для проверки проблемы существует xaml часть приложения. Я думаю, вы, специалисты, можете сделать часть ViewModel/Model.

<Window x:Class="WpfApplication5.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" 
     Width="525" 
     Height="350"> 
    <StackPanel> 
     <Button Command="{Binding ChangeViewModeCommand}" 
       Content="Change ViewMode" /> 
     <ListView x:Name="list" ItemsSource="{Binding Models}"> 
      <ListView.ItemContainerStyle> 
       <Style TargetType="ListViewItem"> 
        <Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=TwoWay}" /> 
        <Setter Property="Content" Value="{Binding DisplayName}" /> 
       </Style> 
      </ListView.ItemContainerStyle> 
      <ListView.Style> 
       <!-- Default ItemsPanel --> 
       <Style TargetType="ListView"> 
        <Setter Property="ItemsPanel"> 
         <Setter.Value> 
          <ItemsPanelTemplate> 
           <StackPanel /> 
          </ItemsPanelTemplate> 
         </Setter.Value> 
        </Setter> 

        <Style.Triggers> 
         <!-- Change ItemsPanel --> 
         <DataTrigger Binding="{Binding ViewMode}" Value="true"> 
          <Setter Property="ItemsPanel"> 
           <Setter.Value> 
            <ItemsPanelTemplate> 
             <WrapPanel /> 
            </ItemsPanelTemplate> 
           </Setter.Value> 
          </Setter> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </ListView.Style> 
     </ListView> 
     <TextBlock Text="{Binding Path=SelectedItems.Count, ElementName=list, StringFormat=Selected Items Count:{0}}" /> 
    </StackPanel> 
</Window> 

Редактировать
Я добавляю код для ViewModel и класса модели. Как вы можете видеть, это так же просто, как и получается.

public class ViewModel : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     public ObservableCollection<Model> Models { get; private set; } 

     private bool viewMode; 
     public bool ViewMode 
     { 
      get { return viewMode; } 
      set 
      { 
       if (viewMode != value) 
       { 
        viewMode = value; 
        OnPropertyChanged("ViewMode"); 
       } 
      } 
     } 

     public ICommand ChangeViewModeCommand 
     { 
      get { return new DelegateCommand(() => ViewMode = ViewMode ? false : true); } 
     } 

     public ViewModel() 
     { 
      Models = new ObservableCollection<Model>(); 
      Models.Add(new Model() { DisplayName = "Model1" }); 
     } 

     private void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 

Модель класса

public class Model : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private bool isSelected; 
    public bool Selected 
    { 
     get { return isSelected; } 
     set 
     { 
      isSelected = value; OnPropertyChanged("Selected"); 
     } 
    } 

    private string display; 
    public string DisplayName 
    { 
     get { return display; } 
     set { display = value; OnPropertyChanged("Display"); } 
    } 


    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Что странно, что Eventhough есть только один элемент в коллекции моделей, ListView.SelectedItems.Count увеличивается.

Благодаря

+0

Ваш XAML правильный, текстовый блок, показывающий вашу 'SelectedItems.Count', делает то, что должен.Я бы предположил, что проблема заключается в том, как вы привязываетесь к свойству 'Selected (bool)'. – Cadogi

ответ

0

Я думаю, что вы нашли ошибку в реализации Microsoft в ListView. После того, как вы определили свойство в своем триггере данных.

<Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=TwoWay}" /> 

Когда ListView разрушает вид и подмену панели она не очищает свой внутренний кэш выбранных элементов. После того как представление будет перестроено, новые ListViewItems получат вашу привязку и вставляют ее в список SelectedItems. Таким образом, вы будете продолжать увеличиваться, когда вы переворачиваете свои панели. Если вы не заметили, если вы нажмете на элементы после их повторной визуализации, ListView удалит элементы, по одному для каждого щелчка, пока он не будет корректно работать снова.

Я бы предположил, что если вы хотите узнать количество выбранных элементов, не имея дело с этой проблемной областью, я бы предложил конвертер, привязанный к вашим моделям, который просто посчитал бы их.

У меня очень хакерская работа, если вы просто хотите, чтобы она правильно сгенерировалась. Вам нужно будет вручную заменить список и отключить привязку, чтобы компенсировать эту ошибку. Это очень уродливый и неправильный способ обращения с ним, но вы можете это сделать.

public ICommand ChangeViewModeCommand 
    { 
     get 
     { 
      return new DelegateCommand(() => 
      { 
      ViewMode = ViewMode ? false : true; 
      //this is crap that you shouldn't have to do 
      var m = Models; 
      Models = null; 
      OnPropertyChanged("Models"); 
      Models = m; 
      OnPropertyChanged("Models"); 
      return viewMode; 
      }); 
     } 
    } 

Это позволит обойти вашу ошибку и правильно связать список правильно.

+0

Я думаю, это действительно ошибка. Я сделал что-то похожее на ваше предложение, но вместо того, чтобы устанавливать Модели в null, я установил для свойства выбранной модели значение false. Где я могу сообщить об этой проблеме, чтобы ее можно было исправить? – ajravago

Смежные вопросы