【问题标题】:Binding entity into WPF datagrid with EF 7 (core)使用 EF 7(核心)将实体绑定到 WPF 数据网格中
【发布时间】:2016-02-02 21:48:07
【问题描述】:

我有一个简单的数据绑定问题。我无法获取数据网格DeviceDataGrid 来可视化实体信息。 MainWindow.xaml文件如下:

<Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:domain="clr-namespace:FxEditorDatabaseStructure.Core.Domain"
    mc:Ignorable="d" x:Class="FxEditorDatabaseStructure.MainWindow"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
    <Window.Resources>
        <CollectionViewSource x:Key="DeviceViewSource" d:DesignSource="{d:DesignInstance {x:Type domain:Device}, CreateList=True}"/>
    </Window.Resources>
    <Grid DataContext="{StaticResource DeviceViewSource}">
        <DataGrid x:Name="DeviceDataGrid" AutoGenerateColumns="False" EnableRowVirtualization="True" ItemsSource="{Binding}" Margin="0,64,0,0" RowDetailsVisibilityMode="VisibleWhenSelected">
            <DataGrid.Columns>
                <DataGridTextColumn x:Name="NameColumn" Binding="{Binding Name}" Header="Name" Width="250"/>
                <DataGridTextColumn x:Name="SocketCountColumn" Binding="{Binding DeviceId}" Header="Id" Width="Auto"/>
                <DataGridTextColumn x:Name="DescriptionColumn" Binding="{Binding Description}" Header="Description" Width="Auto"/>
                <DataGridTextColumn x:Name="ProductTypeColumn" Binding="{Binding ProductType}" Header="Product Type" Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
        <Button Content="Add" HorizontalAlignment="Left" Margin="23,25,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="-0.143,-0.057" Click="AddDevice_Click"/>
    </Grid>
</Window>

并尝试在 MainWindow 上可视化实体内的数据。 数据库已正确创建,甚至添加按钮也有效。我可以通过 Firefox SQLite Manager 看到这一点。

这是 xaml.cs 文件,它在将实体预加载到内存后将实体“绑定”到数据网格中:

    public partial class MainWindow : Window
    {
        private FxContext _context = new FxContext();

        public MainWindow()
        {
            InitializeComponent();
            _context.Database.Migrate();
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _context.Devices.Add(new Device
            {
                ProductCode = "100",
                Name = "LUX999",
                Description = "Measurement device",
                Supplier = "X",
                Category = "Sensors",
                ProductType = "Field device",
                TimeCreated = DateTime.Now
            });
            _context.SaveChanges();

            System.Windows.Data.CollectionViewSource deviceViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("DeviceViewSource")));
            _context.Devices.Load();
            _context.Sockets.Load();
            _context.ProductTypes.Load();
            deviceViewSource.Source = _context.Devices.GetLocal();
            deviceViewSource.Source = _context.Categories.GetLocal();
            deviceViewSource.Source = _context.ProductTypes.GetLocal();
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            base.OnClosing(e);

            _context.Dispose();
        }

        private void AddDevice_Click(object sender, RoutedEventArgs e)
        {
            _context.Devices.Add(
                new Device
                {
                    TimeCreated = DateTime.Now,
                    Name = "New Device at " + DateTime.Now.ToShortDateString()
                });

            _context.SaveChanges();
        }
    }
}

因为 EF7(核心)仍然缺少 local() 的实现,所以我使用的是 alternative extension method

public static class Extensions
{
    public static ObservableCollection<TEntity> GetLocal<TEntity>(this DbSet<TEntity> set)
        where TEntity : class
    {
        var context = set.GetService<DbContext>();
        var data = context.ChangeTracker.Entries<TEntity>().Select(e => e.Entity);
        var collection = new ObservableCollection<TEntity>(data);

        collection.CollectionChanged += (s, e) =>
        {
            if (e.NewItems != null)
            {
                context.AddRange(e.NewItems.Cast<TEntity>());
            }

            if (e.OldItems != null)
            {
                context.RemoveRange(e.OldItems.Cast<TEntity>());
            }
        };

        return collection;
    }
}

当我运行应用程序时,datagrid 没有在其列表视图中显示来自数据库的任何值。不知何故,这条线没有正确传输实体deviceViewSource.Source = _context.Devices.GetLocal(); 或者 xaml 文件中的某些绑定过程错误?

任何想法我做错了什么?

【问题讨论】:

  • 我更新了问题描述,希望它能更好地解释问题。
  • 这值得 +1 仅用于扩展方法。虽然我也试图弄清楚 wpf 数据绑定到 EF7(核心)。尽管当前 DbSet 没有看到 GetService 方法。那是另一种扩展方法吗?
  • 我知道纯链接答案不是很好的做法,但您可能会在这张票上找到您要找的东西:github.com/aspnet/EntityFramework/issues/5385 扩展我的答案,它不是扩展方法,而是与实体框架核心有关本身,并且在 RC1 - 1.1 等之间发生了变化。

标签: c# wpf data-binding entity-framework-core


【解决方案1】:

问题是,您将 deviceViewSource.Source 设置为设备,然后替换为类别,然后替换为 ProductTypes

deviceViewSource.Source = _context.Devices.GetLocal();
deviceViewSource.Source = _context.Categories.GetLocal();
deviceViewSource.Source = _context.ProductTypes.GetLocal();

此时,您正在对 ProductTypes 进行数据绑定...删除两条底线。

我相信您也不需要 GetLocal() 方法。试试这个:

deviceViewSource.Source = _context.Devices

【讨论】:

  • 太棒了,这完全是真的,新手的错误。当我移除底部的两个时,一切正常。但是,当尝试仅使用 deviceViewSource.Source = _context.Devices我收到此异常:附加信息:不支持直接将数据绑定到存储查询。而是通过调用 ToList() 或 ToArray() 等方法将结果具体化为一个集合,然后绑定到该集合。应该这样做以避免每次数据绑定控件迭代数据时向数据库发送查询。
猜你喜欢
  • 2011-12-13
  • 1970-01-01
  • 2021-10-17
  • 1970-01-01
  • 2014-04-19
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
  • 2011-01-31
相关资源
最近更新 更多