【问题标题】:Reusing Binding Collections for WPF为 WPF 重用绑定集合
【发布时间】:2011-10-22 13:15:51
【问题描述】:

我正在使用 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 = "" });

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

【问题讨论】:

  • 加载静态列表一次,然后关闭连接有什么问题?列表的静态类不是存储库,因为它不用于添加/编辑/删除项目,它只是一个包含一些静态列表的类。
  • 因为似乎即使使用using 块,与数据库的连接仍保持打开状态。除非有明确的方法让 EF 关闭其连接,否则这不是一个好习惯。
  • 过去,我为我的 DataContext 使用了 using 块并将 context.Entities.ToList() 返回到静态列表。这会将实体与上下文断开连接并关闭连接。所以我的静态类会说CustomerList = DAL.GetCustomers();,而我的DAL 类上的静态GetCustomers() 方法类似于List&lt;Customers&gt; list; using (var context as new MyEntities) { list = context.Customers.ToList(); } return list;

标签: wpf mvvm observablecollection


【解决方案1】:

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

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

编辑

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

例如,

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

这将使用静态类 Lists 上的 ObservableCollection&lt;Customer&gt; CustomerList 属性填充 ComboBox,并将 SelectedItem 绑定到 Model.Customer 属性

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

【讨论】:

  • 创建来自 EF 的对象的新副本的最佳方法是什么?
  • @Tyrsius 最简单的方法是创建一个新对象并将其属性设置为与复制的对象相等。为什么你还想要副本?
  • 我不想链接列表。每个选项卡都是独立的,因此在一个选项卡上进行选择不应导致所有其他组合框显示相同的选择。
  • SelectedItem 是选择的数据对象,它是 ComboBox 的 ItemSource 集合的任何类型。 SelectedValue 是您的 SelectedItem 的 Value 是什么(通过 SelectedValuePath 属性设置),SelectedIndex 是所选项目的整数索引。
  • 绑定{Binding Source={x:Static local:Lists.CustomerList}} 意味着它正在local 中定义的命名空间中查找名为Lists 的静态类,该类具有名为CustomerList 的静态属性。您必须自己在 XAML 页面顶部使用 xmlns:local="clr-namespace:MyNamespace" 定义 local
猜你喜欢
  • 2017-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 2011-01-03
  • 2014-10-19
  • 2011-06-27
  • 2012-07-03
相关资源
最近更新 更多