【问题标题】:How to refresh a data-bound collection in c#?如何在 C# 中刷新数据绑定集合?
【发布时间】:2012-02-19 17:23:16
【问题描述】:

我正在编写一个简单的 wpf 应用程序,但我卡住了。我想实现,我有一个过滤器类,并且如果用户输入在过滤器类中更改了 id,则应刷新应用过滤器的列表。所有初始绑定都在工作。该列表与 CompanyId 一起正确显示。

xaml 中的数据绑定:

<ListBox Height="212" HorizontalAlignment="Left" Margin="211,31,0,0" Name="listBoxProducts" VerticalAlignment="Top" Width="267" ItemsSource="{Binding ElementName=this, Path=Products}" DisplayMemberPath="CompanyId" />  
<TextBox Height="28" HorizontalAlignment="Left" Margin="12,31,0,0" Name="textBoxCompanyId" VerticalAlignment="Top" Width="170" Text="{Binding ElementName=this, Path=Company.Id}" />

xaml 的代码隐藏:

private TestFactory _testFactory  = new TestFactory();

    private Company _company;
    public Company Company
    {
        get { return _company; }
    }

    private IProductList _products;
    public IProductList Products
    {
        get { return _products; }
    }


    public MainWindow()
    {
        _company = _testFactory.Company;
        _products = _testFactory.Products;

        InitializeComponent();
        _company.FilterChanged += _testFactory.FilterChanging;
    }

(虚拟)工厂类:

private IProductList _products;
    public IProductList Products 
    {
        get { return _products; }
    }

    private Company _company = new Company();
    public Company Company
    {
        get { return _company; }
    }

    public TestFactory()
    {
        _company = new Company() { Id = 2, Name = "Test Company" };
        GetProducts();
    }

    public void GetProducts()
    {
        var products = new List<Product>();
        products.Add(new Product() { ProductNumber = 1, CompanyId = 1, Name = "test product 1" });
        products.Add(new Product() { ProductNumber = 2, CompanyId = 1, Name = "test product 2" });
        products.Add(new Product() { ProductNumber = 3, CompanyId = 2, Name = "test product 3" });

        if (Company.Id != 2)
        {
            products = products.Where(p => p.CompanyId == Company.Id).ToList();
        }

        _products = new ProductList(products);
    }

    public void FilterChanging(object sender, EventArgs e)
    {
        GetProducts();
    }

ProductList 接口:

public interface IProductList : IList<Product>, INotifyCollectionChanged {}

产品列表类:

public class ProductList : IProductList
{
    private readonly IList<Product> _products;

    public ProductList() { }

    public ProductList(IList<Product> products)
    {
        _products = products;
    }


    public IEnumerator<Product> GetEnumerator()
    {
        return _products.GetEnumerator();
    }


    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }


    public void Add(Product item)
    {
        _products.Add(item);
        notifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
    }


    public void Clear()
    {
        _products.Clear();
        notifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }


    public bool Contains(Product item)
    {
        return _products.Contains(item);
    }


    public void CopyTo(Product[] array, int arrayIndex)
    {
        _products.CopyTo(array, arrayIndex);
    }


    public bool Remove(Product item)
    {
        var removed = _products.Remove(item);

        if (removed)
        {
            notifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
        }
        return removed;
    }


    public int Count
    {
        get { return _products.Count; }
    }


    public bool IsReadOnly
    {
        get { return _products.IsReadOnly; }
    }


    public int IndexOf(Product item)
    {
        return _products.IndexOf(item);
    }


    public void Insert(int index, Product item)
    {
        _products.Insert(index, item);
        notifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }


    public void RemoveAt(int index)
    {
        _products.RemoveAt(index);
        notifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }


    public Product this[int index]
    {
        get { return _products[index]; }
        set
        {
            _products[index] = value;
            notifyCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, _products[index]));
        }
    }


    public event NotifyCollectionChangedEventHandler CollectionChanged;
    private void notifyCollectionChanged(NotifyCollectionChangedEventArgs args)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, args);
        }
    }
}

公司类(过滤器类):

public class Company : INotifyPropertyChanged
{
    private int _id;
    public int Id
    {
        get { return _id; }
        set 
        {
            if (_id == value)
                return;

            _id = value;
            OnPropertyChanged("Id");

            OnFilterChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value)
                return;

            _name = value;
            OnPropertyChanged("Name");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    public event EventHandler FilterChanged;

    private void OnPropertyChanged(string name)
    {
        if (PropertyChanged == null)
            return;

        var eventArgs = new PropertyChangedEventArgs(name);
        PropertyChanged(this, eventArgs);
    }

    private void OnFilterChanged(NotifyCollectionChangedEventArgs e)
    {
        if (FilterChanged == null)
            return;

        FilterChanged(this, e);
    }
}

列表在工厂刷新,但视图没有变化。我可能做错了什么,也许我的整个方法不是最好的。也许我必须使用带有 valueconverter 的 ObservableCollection 类型?任何帮助将不胜感激。干杯!

【问题讨论】:

    标签: c# wpf data-binding inotifypropertychanged inotifycollectionchanged


    【解决方案1】:

    您也可以考虑在此用例中使用 ICollectionView。

    请参阅此post

    【讨论】:

    • 我宁愿避免这种方法,必须有更简单的方法来完成这项工作。
    【解决方案2】:

    使用ObservableCollection&lt;Product&gt; 而不是根据IList 创建自己的列表

    ObservableCollection 的目的是跟踪集合的变化,当集合发生变化时它会自动更新 UI。

    【讨论】:

    • 如果我想实现 ObservableCollection,是否需要 ValueConverter?
    • 我是否还需要一个订阅事件的函数来通知视图,集合中是否发生了一些变化?顺便说一句,我找到了解决问题的方法,但我仍然不确定,不管它是否正确。如果我像这样修改 GetProducts() 它的工作原理: ...if (_products != null) { _products.Clear(); products.Where(product => product.CompanyId == _company.Id).ToList().ForEach(product => _products.Add(product)); } 其他 { _products = 产品; } 你怎么看?
    • @JahManCan 不,你不知道 - ObservableCollections 会自动告诉视图它的集合是否已被修改。只需直接绑定到集合:&lt;DataGrid ItemsSource="{Binding MyObservableCollection}" ... /&gt;
    猜你喜欢
    • 2011-09-18
    • 2011-11-07
    • 1970-01-01
    • 2017-04-18
    • 2015-07-12
    • 2011-04-13
    • 2019-11-05
    • 2011-07-21
    • 2012-03-17
    相关资源
    最近更新 更多