【问题标题】:DataBinding() not working with Distinct() (Entity Framework)DataBinding() 不适用于 Distinct()(实体框架)
【发布时间】:2016-04-19 11:12:14
【问题描述】:

我想创建一个从数据库读取数据然后通过 UI 显示的应用程序。然后用户可以添加/删除/更新字段并将其保存到数据库中,非常标准,对吧?

我有两张表:Motors 和Measures。 Motors 表有很多字段,其中之一是“公司”。当然,同一家公司可以有多个电机,所以我想过滤这些公司并在组合框中只获取不同的公司。

我还在玩语言和 VS,所以我做了一个简单的 UI 版本,用户可以在其中添加新电机,实际上,用户可以添加公司字段,因为我是尝试添加新公司并查看它是否在组合框中自动更新。

为此,我使用 Entity Framework 和来自 msdn 的本教程进行数据绑定:

https://msdn.microsoft.com/en-us/data/jj682076.aspx

问题是,当我添加一个新电机(与一家新公司)时,如果我过滤不同的电机,它不会更新,我的意思是,以下代码 确实 工作并自动更新包含所有公司的组合框:

        private void MainForm_Load(object sender, EventArgs e)
    {
        _context = new MotorsContext();
        _context.Motors.Load();

        this.companyBindingSource.DataSource = _context.companies.ToBindingList();
        companyBindingSource.ListChanged += CompanyBindingSource_ListChanged;
    }

而以下不是

private void MainForm_Load(object sender, EventArgs e)
{
    _context = new MotorsContext();
    _context.Motors.Load();

    this.companyBindingSource.DataSource = _context.Motors.Local.ToBindingList().Select(x => x.company).Distinct();
    companyBindingSource.ListChanged += CompanyBindingSource_ListChanged;
}

我创建了一个 ListChanged 方法来查看软件何时检测到列表确实发生了变化。在第一个代码中它确实触发了,但在第二个代码中没有。当我添加过滤器时,观察者可能没有检测到列表中的变化?

private void CompanyBindingSource_ListChanged(object sender, ListChangedEventArgs e)
{
    MessageBox.Show("List changed!");
}

最后,添加电机按钮:

private void button1_Click_1(object sender, EventArgs e)
{
    if (!string.IsNullOrWhiteSpace(textBox1.Text))
    {
        Motor m = new Motor();
        m.company = textBox1.Text;
        _context.Motors.Add(m);
        _context.SaveChanges();
        MessageBox.Show($"New motor, id: {m.motorID}");
    }
}

第一次实现时,组合框会更新并显示每个公司(每个电机):

按下添加按钮 -> “列表已更改!”弹出窗口->“新电机:id”弹出窗口

使用过滤器:

按下添加按钮 -> “新电机:id”弹出窗口

其实电机加了,但是重启程序才显示。

任何想法将不胜感激。我希望我已经很好地解释了自己。

【问题讨论】:

    标签: c# entity-framework data-binding


    【解决方案1】:

    第二个示例中的以下行打破了绑定:

    _context.Motors.Local.ToBindingList().Select(x => x.company).Distinct();
    

    原因是.Select(x => x.company).Distinct()的结果不是BindingList<Motor>,而是简单的IEnumerable<string>

    使用以下替换:

    var _companies = _context.Motors.Select(x => x.company).Distinct().ToList();
    
    this.companyBindingSource.DataSource = _companies;
    

    【讨论】:

    • 感谢您的回答 DmitryG。我认为您的意思是 _context.Motors.Select(x => x.company).Distinct().Load()。但是,它不起作用。组合框没有被数据填充。如果我写 _context.Motors.Where(m => m.company == "UPV").Load();然后我得到一个带有三个“UPV”的组合框(因为我有 3 个 UPV 电机)。如果我添加一个以 UPV 作为公司的新公司,它会添加到列表中,所以我有 4 个。问题是,如果我有任何其他公司,它也会添加,所以它不再过滤 company == "UPV" .我认为 Load() 语句中的过滤器只适用于第一次加载,对吧?
    • >>我认为Load()语句中的过滤器只适用于第一次加载,对吧?你是对的。在进行一些更改后,您应该从上下文重新加载数据源。
    • 您介意深入解释一下吗?你的意思是我也应该从 AddButton 调用 _context.Motors.Select(x => x.company).Distinct().Load() 吗?
    • 一般来说,是的,你应该这样做。我建议您将所有使用_context 的操作包装到单独的类(ContextViewModel)中,并公开为 UI 提供实际数据的 Entities 属性。任何与上下文修改相关的操作都应由此 ContextViewModel 管理并更新此属性的基础数据。
    • @lyurealm 我很高兴听到我的帮助很有帮助
    【解决方案2】:

    这一行

    this.companyBindingSource.DataSource = _context.Motors.Local.ToBindingList().Select(x => x.company).Distinct();
    

    返回IEnumerable<T>。在您的情况下,您希望它是列表,所以添加.ToList();

    this.companyBindingSource.DataSource = _context.Motors.Local.ToBindingList().Select(x => x.company).Distinct().ToList();
    

    【讨论】:

    • 首先感谢您的回答。不过,即使使用 .ToList(),它似乎也不起作用。
    猜你喜欢
    • 1970-01-01
    • 2015-11-12
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    相关资源
    最近更新 更多