当 List 是 CollectionViewSource 的 Source 时,如何模仿 List 的 ObservableCollection 的行为?

发布于 2024-08-09 07:54:30 字数 2711 浏览 7 评论 0 原文

下面的代码的工作原理如下:显示一个表单,其中包含已排序的名称列表。单击该按钮时,新名称将添加到列表中文本框中适当排序的位置。当双击列表中的某个项目时,它会带有前缀“AAA”,这会触发它被放置在列表的顶部。 当我将 ObservableCollection 更改为 List 时,这种行为当然会消失。但是我要怎么模仿呢???我尝试实现 INotifyPropertyChanged,我在列表框的 BindingExpression 上调用了 UpdateTarget() 方法,但都无济于事...

我有以下 XAML:

<Window x:Class="CollectionViewSpike.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
    <TextBox Name="NewNameBox" Text="{Binding NewName, UpdateSourceTrigger=PropertyChanged}"/>
    <Button Click="Button_Click"">Add</Button>
    <ListBox Name="listbox" ItemsSource="{Binding MyCollectionViewSource.View}"
             MouseDoubleClick="listbox_MouseDoubleClick"/>
</StackPanel>

背后的代码:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace CollectionViewSpike
{
   public partial class Window1: Window
   {
    public ObservableCollection<string> Names { get; set; }

    public static DependencyProperty NewNameProperty = DependencyProperty.Register("NewName", typeof (string),
                                                                           typeof (Window1),
                                                                           new PropertyMetadata(string.Empty));

    public string NewName
    {
        get { return (string) GetValue(NewNameProperty); }

        set{ SetValue(NewNameProperty,value);}
    }

    public Window1()
    {
        InitializeComponent();
        var names = new string[] { "onno", "friso","andre"};
        Names = new ObservableCollection<string>(names);
        collectionViewSource = new CollectionViewSource { Source = Names };
        collectionViewSource.SortDescriptions.Add(
                     new SortDescription("", ListSortDirection.Ascending));
        DataContext = this;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        NewName = NewName ?? "???";
        Names.Add(NewName);
        NewName = string.Empty;
    }

    private CollectionViewSource collectionViewSource;
    public CollectionViewSource MyCollectionViewSource
    {
        get { return collectionViewSource; }
        private set { collectionViewSource = value;}
    }

    private void listbox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        var user = (string)listbox.SelectedItem;
        int index = Names.IndexOf(user);
        Names[index]="AAA"+Names[index];
    }
}

}

The code below works as follows: a form is shown with a list of sorted names. When the button is clicked a new name is added to the list at the appropriate sorted position from the textbox . When an item of the list is doubleclicked it is prefixed with "AAA", which triggers it to be placed on top of the list.
When I change the ObservableCollection to a List this behaviour disappears of course. But how can I mimick it??? I tried implementing INotifyPropertyChanged, I called the UpdateTarget() method on the listbox's BindingExpression, all to no avail...

I have the following XAML:

<Window x:Class="CollectionViewSpike.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
    <TextBox Name="NewNameBox" Text="{Binding NewName, UpdateSourceTrigger=PropertyChanged}"/>
    <Button Click="Button_Click"">Add</Button>
    <ListBox Name="listbox" ItemsSource="{Binding MyCollectionViewSource.View}"
             MouseDoubleClick="listbox_MouseDoubleClick"/>
</StackPanel>

The code behind:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;

namespace CollectionViewSpike
{
   public partial class Window1: Window
   {
    public ObservableCollection<string> Names { get; set; }

    public static DependencyProperty NewNameProperty = DependencyProperty.Register("NewName", typeof (string),
                                                                           typeof (Window1),
                                                                           new PropertyMetadata(string.Empty));

    public string NewName
    {
        get { return (string) GetValue(NewNameProperty); }

        set{ SetValue(NewNameProperty,value);}
    }

    public Window1()
    {
        InitializeComponent();
        var names = new string[] { "onno", "friso","andre"};
        Names = new ObservableCollection<string>(names);
        collectionViewSource = new CollectionViewSource { Source = Names };
        collectionViewSource.SortDescriptions.Add(
                     new SortDescription("", ListSortDirection.Ascending));
        DataContext = this;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        NewName = NewName ?? "???";
        Names.Add(NewName);
        NewName = string.Empty;
    }

    private CollectionViewSource collectionViewSource;
    public CollectionViewSource MyCollectionViewSource
    {
        get { return collectionViewSource; }
        private set { collectionViewSource = value;}
    }

    private void listbox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        var user = (string)listbox.SelectedItem;
        int index = Names.IndexOf(user);
        Names[index]="AAA"+Names[index];
    }
}

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

留一抹残留的笑 2024-08-16 07:54:30

我不知道为什么你不直接使用 ObservableCollection - 这就是它的用途。但是,无论如何,您可能还必须实现 INotifyCollectionChanged 以使绑定知道内容或顺序已更改。

ObservableCollection 的 msdn 参考

I'm not sure why you wouldn't just use an ObservableCollection - that's what its for. But, anyway, you probably also have to implement INotifyCollectionChanged to let the binding know that the contents or ordering changed.

msdn reference for ObservableCollection

贱贱哒 2024-08-16 07:54:30

找到了。将 MyCollectionViewSource.View.Refresh() 添加到更改底层不可观察的枚举> 的方法中
假设 Observable>名称现在是一个列表>;姓名:

   private void Button_Click(object sender, RoutedEventArgs e)
    {
        NewName = NewName ?? "???";
        Names.Add(NewName);
        NewName = string.Empty;
        MyCollectionViewSource.View.Refresh();
    }

   private void listbox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        var user = (string)listbox.SelectedItem;
        int index = Names.IndexOf(user);
        Names[index]="AAA"+Names[index];
        MyCollectionViewSource.View.Refresh();
    } 

Found it. Add MyCollectionViewSource.View.Refresh() to a method that changes the underlying non observable enumerable<T>
Supposing that the Observable<string> Names is now a List<string> Names:

   private void Button_Click(object sender, RoutedEventArgs e)
    {
        NewName = NewName ?? "???";
        Names.Add(NewName);
        NewName = string.Empty;
        MyCollectionViewSource.View.Refresh();
    }

   private void listbox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        var user = (string)listbox.SelectedItem;
        int index = Names.IndexOf(user);
        Names[index]="AAA"+Names[index];
        MyCollectionViewSource.View.Refresh();
    } 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文