将EntityFramework实体绑定到树视图

时间:2014-11-23 18:51:02

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

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

为了快速总结,我试图将数据绑定到树视图。这就是我所拥有的:

我有一个数据库,我创建了一个ADO.NET实体数据模型。我想在树视图中绑定3个实体:Country,Sector和Entity。国家(一)与实体(许多)和部门(一)与实体(许多)相关联。

以下是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; }
}

我现在想要将它们绑定到WPF表单中的treeview控件,以获得类似这样的内容:

  • 国家1
    • 扇区1
      • ENTITY1
      • ENTITY2
    • Sector2
      • ENTITY3
      • Entity4
  • COUNTRY2
    • 扇区1
      • Entity5
      • Entity6

...

无论我多找多少,我都无法找到如何将它们直接绑定到Treeview中。

提前感谢您提供的任何帮助。

1 个答案:

答案 0 :(得分:2)

首先按如下方式创建视图模型类:

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设为ItemsSource的{​​{1}}。由于TreeView是继承的,DataContext的{​​{1}}与您之前指定为DataContext的{​​{1}}的实例相同。

TreeView

使用NO KEY定义三个资源,以便MainVm根据项目的DataContext自动选择其中一个。

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

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

TreeView.ItemTemplate

<强>替代地 您可以实现一个ViewModel而不是三个(称之为TreeNodeVm)

DataType

并按如下方式编写TreeView xaml代码:

<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>