重用WPF的绑定集合

时间:2011-08-08 16:29:34

标签: wpf mvvm observablecollection

我正在使用MVVM模式开发一个WPF应用程序,我learning。它使用EF4。我正在尝试使用类似的选项卡式文档界面风格;这些选项卡上的几个组合框具有相同的项目源(来自sql db)。由于这些数据几乎从不改变,因此在应用程序启动时创建一个存储库对象来获取它们似乎是一个好主意,并且只需为每个视图模型重用它们。无论出于何种原因,即使我在构造函数中使用new,列表也是连接的。

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

存储库对象先于其他任何东西进行初始化,只保存公共列表。视图只使用项目源绑定到ObservableCollection。我正在使用文章中的ViewModelBase类。这是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);
    }

编辑:我确信这是错误的做法,我还在努力。这是新的型号代码:

        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 question我在使用Rachels时遇到的问题表明静态存储库是不好的做法,因为它会在程序的生命周期中保持数据库连接处于打开状态。我确认连接仍处于打开状态,但看起来对于非静态类仍然是开放的。这是存储库代码:

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对象需要在任何需要它的代码中按属性手动重新创建属性。看起来这应该是一个很常见的事情,重新使用列表,我觉得它应该有一个解决方案。

1 个答案:

答案 0 :(得分:4)

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

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

修改

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

例如,

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

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

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