c# - 在 MVVM (WPF) 应用程序中更改 ListView 上的筛选器后如何滚动到 View ?

标签 c# wpf listview mvvm filter

我在 VM 中有一个 ObservableCollection,它显示在 ListView 的 View 中。当所选项目更改时,SelectionChanged 事件会很好地触发。下面是我如何配置 ListView:

<ListView Grid.Row="3" Margin="5" AlternationCount="2" Name="_lvSettings" 
          IsSynchronizedWithCurrentItem="True"
          ItemsSource="{Binding Path=CollectionView}" 
          SelectedIndex="{Binding Path=SelectedSettingIndex}"
          SelectionChanged="OnSelectionChanged"  >
    <ListView.View>
        <GridView>
            <GridViewColumn Width="170" 
                            Header="{Binding Path=ShowAllDisplay}"
                            x:Name="_colSettings"  
                            DisplayMemberBinding="{Binding Path=Setting}"/>
            <GridViewColumn Header="Old Value" Width="150" 
                            DisplayMemberBinding="{Binding Path=OldVal}"/>
            <GridViewColumn Header="New Value" 
                            DisplayMemberBinding="{Binding Path=NewVal}" />
        </GridView>
    </ListView.View>
</ListView>

我遇到的问题是当我更改集合上的过滤器时。所选项目保持不变,这很好,但是 ListView 更改为从第一个项目显示,并且经常选择项目不在 View 中(但仍然是所选项目)。

在 VM 中,我有属性“SelectedSettingIndex”,它在更改时抛出 PropertyChanged 事件。即使我自己在过滤器更改时从 VM 手动引发事件(base.OnPropertyChanged("SelectedSettingIndex");),事件似乎也没有真正引发,因为属性并没有真正改变。在这种情况下,必须有一种方法可以调用 ScrollIntoView 或类似的东西,但我无法找出正确的事件或触发器来这样做。我缺少什么?

编辑

这是对我所关心的问题的描述,希望更好:

1) 我在 VM 中使用 CollectionViewSource 来过滤数据。

2) 有一个按钮供用户在过滤器之间切换。

3) 假设 ListView 在任何给定时间都有空间最多显示 10 个项目。

4) 用户在 ListView 中索引为 50 的筛选 View 中选择项目“A”。

5) 然后用户单击按钮关闭过滤。

预期结果:ListView 填充了未过滤的列表,项目“A”保持选中状态,ListView 被“滚动”,使得项目“A”仍然可见。

实际结果:ListView 中填充了未过滤的列表,项目“A”保持选中状态,ListView“滚动”到顶部并显示前 10 个项目。项目“A”不在 View 中。

最佳答案

如果您使用的是 MVVM,那么您需要确保已将绑定(bind)设置为 viewModel 中的选定项,并且还使用 Mode=TwoWay 设置了绑定(bind)。 ...为了在 Selection 上滚动,我们必须在 ListView 上使用一个行为(避免代码隐藏)

您必须添加对 System.Windows.Interactivity 的引用使用 Behavior<T> class

行为

public class ScrollIntoViewForListView : Behavior<ListView>
{
    /// <summary>
    ///  When Beahvior is attached
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.SelectionChanged += AssociatedObject_SelectionChanged;
    }

    /// <summary>
    /// On Selection Changed
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void AssociatedObject_SelectionChanged(object sender,
                                           SelectionChangedEventArgs e)
    {
        if (sender is ListView)
        {
            ListView listview = (sender as ListView);
            if (listview.SelectedItem != null)
            {
                listview.Dispatcher.BeginInvoke(
                    (Action) (() =>
                                  {
                                      listview.UpdateLayout();
                                      if (listview.SelectedItem !=
                                          null)
                                          listview.ScrollIntoView(
                                              listview.SelectedItem);
                                  }));
            }
        }
    }
    /// <summary>
    /// When behavior is detached
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.SelectionChanged -=
            AssociatedObject_SelectionChanged;

    }
}

用法

将别名添加到 XAML作为xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

然后在你的Control DisplayMemberBinding="{Binding Path=Setting}"/>

现在当在 ViewModel 中设置“MySelectedItem”属性时反射(reflect)更改时,列表将滚动。

变更通知

在 viewModel 中应该调用 INotifyProperty 在你已经绑定(bind)到你的 xaml 的属性的 setter 中更改,以便 viewModel 中的更改可以反射(reflect)到 View ...

在 MVVM 中使用 SelectionChanged 事件

同样在 MVVM 中,您不必使用“SelectionChnaged 事件”,因为您可以调用 MySelectedItem 属性的 Setter 中的函数,或者您可以使用 EventToCommand显式事件调用类..

过滤

Google 使用 ColletionViewSource 来实现排序、过滤等功能

希望对你有帮助

关于c# - 在 MVVM (WPF) 应用程序中更改 ListView 上的筛选器后如何滚动到 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10135850/

相关文章:

c# - 根据属性比较两个 List<Control> 之前/之后

c# - 属性路由区别?

WPF:工具栏中的嵌套菜单项

wpf - 在 WPF/XAML 中使用 CMYK 颜色

c# - 在解决方案中发现 WCF 服务

c# - 如何保留在使用 List.Clear() 之前已经创建的列表

wpf - 如何在双向绑定(bind)组合框 (WPF) 上调用异步操作

WPF listview 删除生成的额外列

android - 从 Android 的 ListView 中删除项目

android - 滚动 ListView 以显示页脚