c# - 将 EntityFramework 实体绑定(bind)到 TreeView

标签 c# wpf entity-framework data-binding treeview

首先,即使我发现了一些类似的问题,但没有一个(到目前为止)回答了我的具体问题。

为了快速总结,我正在尝试将数据绑定(bind)到 TreeView 。这是我所拥有的:

我有一个数据库,我用它创建了一个 ADO.NET 实体数据模型。我想在 TreeView 中绑定(bind) 3 个实体:国家、部门和实体。国家(一)与实体(多个)相关联,部门(一)与实体(多个)相关联。

下面是 ADO.NET 实体数据模型为每个对象生成的代码

public partial class Country
{
    public Country()
    {
        this.Entities = new HashSet<Entity>();
    }

    public int country_id { get; set; }
    public string country_name { get; set; }

    public virtual ICollection<Entity> Entities { get; set; }
}

public partial class Sector
{
    public Sector()
    {
        this.Entities = new HashSet<Entity>();
    }

    public int sector_id { get; set; }
    public string sector_name { get; set; }

    public virtual ICollection<Entity> Entities { get; set; }
}

public partial class Entity
{
    public Entity()
    {
        this.Entities_to_Indexes = new HashSet<Entities_to_Indexes>();
        this.StreamParameters_to_Entities = new HashSet<StreamParameters_to_Entities>();
        this.Tweets_to_Entities = new HashSet<Tweets_to_Entities>();
    }

    public int entity_id { get; set; }
    public string entity_name { get; set; }
    public int sector_id { get; set; }
    public int country_id { get; set; }

    public virtual Country Country { get; set; }
    public virtual Sector Sector { get; set; }
    public virtual ICollection<Entities_to_Indexes> Entities_to_Indexes { get; set; }
    public virtual ICollection<StreamParameters_to_Entities> StreamParameters_to_Entities { get; set; }
    public virtual ICollection<Tweets_to_Entities> Tweets_to_Entities { get; set; }
}

我现在想将它们绑定(bind)到 WPF 表单中的 TreeView 控件,以获得如下内容:

  • 国家1
    • 部门1
      • 实体1
      • 实体2
    • Sector2
      • 实体3
      • 实体4
  • 国家2
    • 部门1
      • 实体5
      • 实体6

...

无论我如何寻找它,我都无法找到如何将它们直接绑定(bind)到 TreeView 中。

预先感谢您提供的任何帮助。

最佳答案

首先创建 View 模型类,如下所示:

public class CountryVm
{
    public CountryVm(string name)
    {
        //since Name is a simple property it's better to initialize it in constructor
        //because Name is neither a dependency property nor notifies about it changes.
        //see DependencyProperty and INotifyPropertyChanged documentation
        Name = name;
    }
    public string Name { get; set; }

    //an observable collection notifies about any changes made in it
    public ObservableCollection<SectorVm> Sectors { get { return _sectors; } }
    private ObservableCollection<SectorVm> _sectors = new ObservableCollection<SectorVm>();
}
public class SectorVm
{
    public SectorVm(string name)
    {
        Name = name;
    }
    public string Name { get; set; }

    public ObservableCollection<EntityVm> Entities { get { return _entities; } }
    private ObservableCollection<EntityVm> _entities = new ObservableCollection<EntityVm>();
}
public class EntityVm
{
    public EntityVm(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
}

为整个窗口(或UserControl或其他什么)创建另一个viewModel,我称之为MainVm我实现了两个额外的依赖属性作为示例:

public class MainVm : DependencyObject
{
    /// <summary>
    /// Gets or sets a fully bindable value that indicates MyText
    /// </summary>
    public string MyText
    {
        get { return (string)GetValue(MyTextProperty); }
        set { SetValue(MyTextProperty, value); }
    }
    public static readonly DependencyProperty MyTextProperty=
        DependencyProperty.Register("MyText", typeof(string), typeof(MainVm),
        new PropertyMetadata("default value here"));

    /// <summary>
    /// Gets or sets a fully bindable value that indicates MyProp
    /// </summary>
    public float MyProp
    {
        get { return (float)GetValue(MyPropProperty); }
        set { SetValue(MyPropProperty, value); }
    }
    public static readonly DependencyProperty MyPropProperty =
        DependencyProperty.Register("MyProp", typeof(float), typeof(MainVm),
        new PropertyMetadata(0f,//default value (MUST be the same type as MyProp)
            //property changed callback
            (d, e) => 
            {
                var vm = (MainVm)d;
                var val = (float)e.NewValue;
                vm.MyText = val.ToString();
            }, 
            //coerce value callback
            (d, v) => 
            {
                var vm = (MainVm)d;
                var val = (float)v;
                //prevents from having negative value
                if (val < 0f) return 0f;
                return v;
            }));


    public ObservableCollection<CountryVm> AllCountries { get { return _allCountries; } }
    private ObservableCollection<CountryVm> _allCountries = new ObservableCollection<CountryVm>();
}

设置 MainVm 的实例作为DataContext您的窗口(或 UC 或...)

public MainWindow()
{
    InitializeComponent();
    DataContext = new MainVm();
}

设置AllCountries作为ItemsSourceTreeView 。自 DataContext是继承的,DataContextTreeViewMainVm 的同一个实例您之前指定为 DataContext窗口的。

    <TreeView ItemsSource="{Binding AllCountries}"/>

定义三个没有 KEY 的资源,以便 TreeView.ItemTemplate根据 DataType 自动选择其中之一项目的。

<Window.Resources>
    <HierarchicalDataTemplate ItemsSource="{Binding Sectors}" DataType="{x:Type vm:CountryVm}">
        <TextBlock Text="{Binding Name}"/>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Entities}" DataType="{x:Type vm:Sector}">
        <TextBlock Text="{Binding Name}"/>
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type vm:Entity}">
        <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
</Window.Resources>

还要将此行添加到 .xaml 代码的开头(在 Window 标记中)。您可能必须将命名空间更改为您自己的 ViewModel 的命名空间:

xmlns:vm="clr-namespace:MyWpfApplication1.Core.ViewModels;assembly=MyWpfApplication1.Core">

或者 您可以实现一个 ViewModel 而不是三个(将其称为 TreeNodeVm)

public class TreeNodeVm
{
    public TreeNodeVm(string name)
    {
        Name = name;
    }
    public string Name { get; set; }

    public ObservableCollection<TreeNodeVm> Children { get { return _children; } }
    private ObservableCollection<TreeNodeVm> _children = new ObservableCollection<TreeNodeVm>();
}

并编写TreeView xaml代码如下:

    <TreeView ItemsSource="{Binding AllCountries}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

关于c# - 将 EntityFramework 实体绑定(bind)到 TreeView ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27092875/

相关文章:

c# - 使用 Style 将 Calendar 的宽度更改为其父 DatePicker 的宽度

c# - 如何模拟代码优先策略创建的 Entity Framework 数据库?

c# - DbQuery 与 IQueryable SQL 性能对比

c# - 使用可能为空的列表通过 EF6 进行查询

c# - 如何在 Entity Framework Core 2.0 中从 DbDataReader 转换为 Task<IEnumerable<TEntity>>?

c# - 协变分配不起作用

c# - 正则表达式从字符串中删除特定标签及其内容

c# - 如何使用 Linq 实现 NextRcord 和 PreviousRecord 按钮?

c# - 当 WPF 中的大量 UI 更新时,ProgressRing 卡住了?

c# - 字节(1024)到字符串转换(1 KB)?