使用CollectionViewSource时,更新Source时,将自动选择绑定ListBox中的第一项

时间:2014-04-30 16:41:03

标签: c# wpf listbox selecteditem

ListBox绑定到CollectionViewSource(用于视图过滤)时,重新绑定到Source属性时,ListBox会自动选择第一个项目(导致SelectedItem绑定同时也开火了。

我不希望列表中的第一项自动选择,也不希望SelectedItem的setter完全触发(因为我选择了一个项目时会调用其他逻辑)。 / p>

这是一个自包含的示例,将其放在一个空白的新WPF应用程序中以演示:

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;

namespace TestBinding
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var template = new DataTemplate();
            FrameworkElementFactory tbFactory = new FrameworkElementFactory(typeof(TextBlock));
            tbFactory.SetBinding(TextBlock.TextProperty, new Binding("Name"));
            template.VisualTree = tbFactory;

            var itemsA = new List<Item>
            {
                new Item { Name = "A Item 1" },
                new Item { Name = "A Item 2" },
                new Item { Name = "A Item 3" },
                new Item { Name = "A Item 4" },
                new Item { Name = "A Item 5" },
                new Item { Name = "A Item 6" },
            };
            var itemsB = new List<Item>
            {
                new Item { Name = "B Item 1" },
                new Item { Name = "B Item 2" },
                new Item { Name = "B Item 3" },
                new Item { Name = "B Item 4" },
            };
            var itemsC = new List<Item>
            {
                new Item { Name = "C Item 1" },
                new Item { Name = "C Item 2" },
                new Item { Name = "C Item 3" },
                new Item { Name = "C Item 4" },
                new Item { Name = "C Item 5" },
                new Item { Name = "C Item 6" },
                new Item { Name = "C Item 7" },
                new Item { Name = "C Item 8" },
            };

            var sp = new StackPanel();
            var b1 = new Button
            {
                Content = "Bind A"
            };
            b1.Click += (_, __) =>
            {
                Items = itemsA;
            };
            var b2 = new Button
            {
                Content = "Bind B"
            };
            b2.Click += (_, __) =>
            {
                Items = itemsB;
            };
            var b3 = new Button
            {
                Content = "Bind C"
            };
            b3.Click += (_, __) =>
            {
                Items = itemsC;
            };

            var list = new ListBox
            {
                ItemTemplate = template
            };

            list.SetBinding(ItemsControl.ItemsSourceProperty, new Binding("ItemFilter.View")
            {
                Source = this
            });
            list.SetBinding(Selector.SelectedItemProperty, new Binding("SelectedItem")
            {
                Source = this
            });

            sp.Children.Add(b1);
            sp.Children.Add(b2);
            sp.Children.Add(b3);
            sp.Children.Add(list);

            (Content as Grid).Children.Add(sp);

            ItemFilter = new CollectionViewSource();

            DataContext = this;
        }

        private List<Item> _Items;
        public List<Item> Items
        {
            get { return _Items; }
            set
            {
                _Items = value;
                ItemFilter.Source = _Items;
            }
        }

        #region Dependency Properties

        public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(Item), typeof(MainWindow), new PropertyMetadata(default(Item)));
        public Item SelectedItem
        {
            get { return (Item)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }

        public static readonly DependencyProperty ItemFilterProperty = DependencyProperty.Register("ItemFilter", typeof(CollectionViewSource), typeof(MainWindow), new PropertyMetadata(default(CollectionViewSource)));
        public CollectionViewSource ItemFilter
        {
            get { return (CollectionViewSource)GetValue(ItemFilterProperty); }
            set { SetValue(ItemFilterProperty, value); }
        }

        #endregion
    }

    public class Item : INotifyPropertyChanged
    {
        private string _Name;
        public string Name
        {
            get { return _Name; }
            set { NotifyPropertyChanged(ref _Name, value, "Name"); }
        }

        #region INPC

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged<T>(ref T item, T value, string name)
        {
            item = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        #endregion
    }
}

2 个答案:

答案 0 :(得分:1)

简短回答:你不能......更新数据源会自动更新显示,并自动将选择恢复回列表中的第一个。你唯一能做的就是记住内存中的选择,然后在更新绑定后重新选择它,但既然你说这不是你的选择,那么这是不可能的。

除非您不介意设置标记以跳过您的Select事件代码...

例如:

记住,
更新装订
将标志设置为“跳过代码”
从记忆中选择项目
将标志设置为“运行代码”

答案 1 :(得分:-1)

尝试collectviewsource.view.moveto(-1)。