【问题标题】:WPF ListView's SelectedItems Count Changes When ItemsPanel is Changed更改 ItemsPanel 时 WPF ListView 的 SelectedItems 计数更改
【发布时间】:2015-12-05 04:15:53
【问题描述】:

动态更改 ItemsPanel 时,ListView 的 SelectedItems 似乎有问题。我在 ListView 上实现了 MVVM,它的 ItemsSource 绑定到模型集合。该模型有 2 个属性,DisplayName(string) 和 Selected(bool)。并且列表视图的 DataContext 包含一个 ViewMode(bool) 属性。

设置是 ListViewItem 的 IsSelected 属性绑定到 Model 的 Selected 属性,当我通过单击按钮更改 ViewMode 时,ListView 的 ItemsPanel 会发生变化。

问题是当ListView中有选中项,ViewMode发生改变时,ListView的SelectedItems计数会增加,即使选中项没有改变。

注意:在我的设置中,ListView 中只有一项,但每次更改 ViewMode 时,SelectedItems 计数都会增加。

这是用于测试问题的应用程序的 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 和 Model 类的代码。如您所见,它非常简单。

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));
        }
    }
}

奇怪的是,尽管 Models 集合中只有 1 项,但 ListView.SelectedItems.Count 会增加。

谢谢

【问题讨论】:

  • 您的 XAML 是正确的,显示您的 SelectedItems.Count 的文本块正在做它应该做的事情。我认为问题一定在于您如何绑定到您的 Selected(bool) 属性。

标签: wpf listview mvvm data-binding


【解决方案1】:

我认为您在 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;
           }); 
       }
    }

这将绕过您的错误并正确正确绑定列表。

【讨论】:

  • 我想这确实是一个错误。我做了类似于你的建议的事情,但是我没有将模型设置为 null,而是将所有模型的 Selected 属性设置为 false。我可以在哪里报告此问题以便解决?
猜你喜欢
  • 1970-01-01
  • 2014-01-26
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-18
相关资源
最近更新 更多