重用WPF的绑定集合 [英] Reusing Binding Collections for WPF

查看:82
本文介绍了重用WPF的绑定集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用MVVM patterm开发WPF应用,我

I am working on a WPF app using the MVVM patterm, which I am learning. It uses EF4. I am trying to use a similar tabbed document interface style; several combo boxes on these tabs have the same items sources (from a sql db). Since this data almost never changes, it seemed like a good idea to make a repository object to get them when the app starts, and just reuse them for each viewmodel. For whatever reason though, even though I use new in the constructors, the lists are connected.

如果我在一个选项卡上设置了一个绑定组合框,它将在另一个选项卡上设置(或在创建新选项卡时设置).我不希望这种情况发生,但我不知道为什么.

If I set a bound combo box on one tab, it gets set on another (or set when a new tab is created). I don't want this to happen, but I don't know why does.

存储库对象首先进行初始化,并且仅保存公共列表.视图仅使用将项目源绑定到ObservableCollection上.我正在使用本文中的ViewModelBase类.这是Viewmodel和模型代码.

The repository object is initialized before anything else, and just holds public lists. The views simply use items source binding onto the ObservableCollection. I am using the ViewModelBase class from the article. Here is the Viewmodel and model code.

ViewModel

ViewModel

TicketModel _ticket;

    public TicketViewModel(TableRepository repository)
    {
        _ticket = new TicketModel(repository);
    }

    public ObservableCollection<Customer> CustomerList
    {
        get { return _ticket.CustomerList; }
        set
        {
            if (value == _ticket.CustomerList)
                return;

            _ticket.CustomerList = value;

            //base.OnPropertyChanged("CustomerList");
        }
    }

型号

public ObservableCollection<Customer> CustomerList { get; set; }

    public TicketModel(TableRepository repository)
    {
        CustomerList = new ObservableCollection<Customer>(repository.Customers);
    }

编辑:我确定这样做是错误的方式,我仍在努力.这是新的模型代码:

I am sure this is the wrong way to do this, I am still working on it. Here is the new model code:

        public TicketModel(TableRepository repository)
    {
        CustomerList = new ObservableCollection<Customer>((from x in repository.Customers
                                                           select
                                                               new Customer
                                                               {
                                                                   CM_CUSTOMER_ID = x.CM_CUSTOMER_ID,
                                                                   CM_FULL_NAME = x.CM_FULL_NAME,
                                                                   CM_COMPANY_ID = x.CM_COMPANY_ID
                                                               }).ToList());
    }

这会引起一个新问题.每当您更改标签时,组合框上的选择都会被清除.

This causes a new problem. Whenever you change tabs, the selection on the combo box is cleared.

更多 此问题我遇到何时使用Rachels答案表明静态存储库是一种不好的做法,因为它会使数据库连接在程序有效期内保持打开状态.我确认连接保持打开状态,但是看起来非静态类也保持打开状态.这是存储库代码:

MORE EDITS: This question I ran into when uses Rachels answer indicates that a static repository is bad practice because it leaves the DB connection open for the life of the program. I confirmed a connection remains open, but it looks like one remains open for non-static classes too. Here is the repository code:

using (BT8_Entity db = new BT8_Entity())
        {
            _companies = (from x in db.Companies where x.CO_INACTIVE == 0 select x).ToList();
            _customers = (from x in db.Customers where x.CM_INACTIVE == 0 orderby x.CM_FULL_NAME select x).ToList();
            _locations = (from x in db.Locations where x.LC_INACTIVE == 0 select x).ToList();
            _departments = (from x in db.Departments where x.DP_INACTIVE == 0 select x).ToList();
            _users = (from x in db.Users where x.US_INACTIVE == 0 select x).ToList();
        }

        _companies.Add(new Company { CO_COMPANY_ID = 0, CO_COMPANY_NAME = "" });
        _companies.OrderBy(x => x.CO_COMPANY_NAME);

        _departments.Add(new Department { DP_DEPARTMENT_ID = 0, DP_DEPARTMENT_NAME = "" });
        _locations.Add(new Location { LC_LOCATION_ID = 0, LC_LOCATION_NAME = "" });

但是,现在我回到上面的丑陋代码,这似乎不是复制集合的好方法,因为需要按需要在任何需要它的代码中逐个属性手动重新创建Customer对象.重复使用列表,这似乎应该是很常见的事情,我觉得应该有解决方案.

However, now I am back to the ugly code above which does not seem a good solution to copying the collection, as the Customer object needs to be manually recreated property by property in any code that needs its. It seems like this should be a very common thing to do, re-using lists, I feel like it should have a solution.

推荐答案

自定义对象(例如Customer)通过引用而不是值进行传递.因此,即使您正在创建一个新的ObservableCollection,它仍然充满了存储库中存在的Customer对象.要创建一个真正的新集合,您需要为该集合的每个Customer对象创建一个新副本.

Custom objects, such as Customer get passed around by reference, not value. So even though you're creating a new ObservableCollection, it is still filled with the Customer objects that exist in your Repository. To make a truly new collection you'll need to create a new copy of each Customer object for your collection.

如果要创建CustomerList的多个副本是因为要根据需要过滤集合,则可以使用CollectionViewSource而不是ObservableCollection.这样,您就可以返回集合的过滤视图,而不是整个集合本身.

If you are creating multiple copies of the CustomerList because you want to filter the collection depending on your needs, you can use a CollectionViewSource instead of an ObservableCollection. This allows you to return a filtered view of a collection instead of the full collection itself.

编辑

如果没有,您是否考虑过为ComboBox项使用静态列表,而只是将SelectedItem存储在模型中?

If not, have you considered using a static list for your ComboBox items, and just storing the SelectedItem in your model?

例如,

<ComboBox ItemsSource="{Binding Source={x:Static local:Lists.CustomerList}}"
          SelectedItem="{Binding Customer}" />

这将使用在静态类Lists上找到的ObservableCollection<Customer> CustomerList属性填充ComboBox,并将SelectedItem绑定到Model.Customer属性

This would fill the ComboBox with the ObservableCollection<Customer> CustomerList property that is found on the Static class Lists, and would bind the SelectedItem to the Model.Customer property

如果SelectedItem没有直接引用ComboBox的ItemsSource中的项目,则需要覆盖item类的Equals(),以使两个值相同(如果它们的值相同)相同.否则,它将比较两个对象的哈希码,并确定两个对象不相等,即使它们包含的数据相同.另外,您也可以在ComboBox上绑定SelectedValueSelectedValuePath属性,而不是SelectedItem.

If the SelectedItem does not directly reference an item in the ComboBox's ItemsSource, you need to overwrite the Equals() of the item class to make the two values equal the same if their values are the same. Otherwise, it will compare the hash code of the two objects and decide that the two objects are not equal, even if the data they contain are the same. As an alternative, you can also bind SelectedValue and SelectedValuePath properties on the ComboBox instead of SelectedItem.

这篇关于重用WPF的绑定集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆