使用sql server在wpf中动态创建菜单

时间:2014-03-01 17:50:26

标签: c# sql-server wpf xaml mvvm

我在creating a menu dynamically using HierarchicalDataTemplate的互联网上找到了一个例子。

这是xaml:

<Window x:Class="WPF_Client.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ERP_Lite" Height="350" Width="525" 
        WindowState="Maximized" WindowStyle="None">

    <Grid>

        <Grid.Resources>
            <XmlDataProvider x:Key="src" XPath="/myDoc/item">
                <x:XData>
                    <myDoc xmlns="">
                        <item title="One" />
                        <item title="Two">
                            <item title="First Child" />
                            <item title="Second Child" />
                            <item title="Third Child" />
                            <item title="Fourth Child">
                                <item title="First Grand Child" />
                                <item title="Second Grand Child" />
                                <item title="Third Grand Child" />
                            </item>
                        </item>
                        <item title="Three" />
                        <item title="More" />
                    </myDoc>
                </x:XData>
            </XmlDataProvider>
        </Grid.Resources>

        <Menu DataContext="{StaticResource src}" ItemsSource="{Binding}">
            <Menu.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding XPath=item}">
                    <TextBlock Text="{Binding XPath=@title}" />
                </HierarchicalDataTemplate>
            </Menu.ItemTemplate>
        </Menu>

    </Grid>
</Window>

上面的xaml运行得非常好。现在我想使用SQL Server而不是xml数据源创建相同的东西。

所以,为此我创建了一个表并添加了如下数据:

ID  |  Title                 |   ParentID
----+------------------------+-----------
1   |  One                   |   NULL
2   |  Two                   |   NULL
3   |  Three                 |   NULL
4   |  Four                  |   NULL
5   |  First Child           |   2
6   |  Second Child          |   2
7   |  Third Child           |   2
8   |  Fourth Child          |   2
9   |  First Grand Child     |   8
10  |  Second Grand Child    |   8
11  |  Third Grand Child     |   8

现在有人可以告诉我如何用菜单绑定这个表的数据吗?

注意:我正在使用EntityFramework和MVVM。

更新

对不起,我在这个例子中没有使用过您的代码,因为我不理解Modelthe constructor of Node之类的内容,也没有填写父或子的值属性,所以它是我的界限,我尝试使用一种不同于你的方法。虽然你已经使用了参数化的构造函数,但是你从不向构造函数提供值,所以我觉得很难。

以下是我的尝试:

这是我的MenuItem模型类:

public partial class MenuItem
{
    public MenuItem()
    {
        this.MenuItems1 = new HashSet<MenuItem>();
    }

    public int MenuItemID { get; set; }
    public string Title { get; set; }
    public Nullable<int> ParentID { get; set; }

    public virtual ICollection<MenuItem> MenuItems1 { get; set; }
    public virtual MenuItem MenuItem1 { get; set; }
}

这是我为MenuItem类创建的数据传输对象,用于解决循环引用错误:

public class MenuItemDTO
{
    public int MenuItemID { get; set; }
    public string Title { get; set; }
    public Nullable<int> ParentID { get; set; }
}

以下是我在WCF服务中使用的方法:

public IEnumerable<MenuItemDTO> GetAllMenuItems()
{
    using (Entities db = new Entities())
    {
        return (from m in db.MenuItems
                select new MenuItemDTO
                {
                    MenuItemID = m.MenuItemID,
                    Title = m.Title,
                    ParentID = m.ParentID
                }).ToList();
    }
}

这是我的MainWindowViewModel:

public class MainWindowViewModel : MainViewModel
{
    public MainWindowViewModel()
    {
        ERP_Lite_ServiceClient client = new ERP_Lite_ServiceClient();

        Parents = new ObservableCollection<MenuItemDTO>
                        (client.GetAllMenuItems().Where(m => m.ParentID == null));
        Children = new ObservableCollection<MenuItemDTO>
                         (client.GetAllMenuItems().Where(m => m.ParentID != null));

        client.Close();
    }

    private ObservableCollection<MenuItemDTO> _parents;
    public ObservableCollection<MenuItemDTO> Parents
    {
        get
        {
            return _parents;
        }
        set
        {
            _parents = value;
            OnPropertyChanged("Parents");
        }
    }

    private ObservableCollection<MenuItemDTO> _children;
    public ObservableCollection<MenuItemDTO> Children
    {
        get
        {
            return _children;
        }
        set
        {
            _children = value;
            OnPropertyChanged("Children");
        }
    }

}

这是xaml:

<Menu ItemsSource="{Binding Parents}">
    <Menu.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type Service:MenuItemDTO}" 
                                  ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Title}" />
        </HierarchicalDataTemplate>
    </Menu.ItemTemplate>
</Menu>

但是我的代码遇到了一些问题。在输出中,我获得所有父项,但不显示子项。你能救我吗?

1 个答案:

答案 0 :(得分:2)

为了与HierarchicalDataTemplate合作,您的 ViewModel 也需要具有层次结构。这意味着ItemsSource内的HierarchicalDataTemplate与该节点相关。但是在你的代码中你已经在同一个 ViewModel 中定义了 Parent Children

MenuItemDTO视为树中的一个随机节点,因此它应该有一些具有相同类型(MenuItemDTO)的子节点。

如果您将ItemsSource Menu设置为"{Binding Parents}",则表示该菜单的顶级项目为“父母”。

现在,如果您将ItemsSource的{​​{1}}设置为HierarchicalDataTemplate,则可以通过查看自己的"{Binding Children}"找到该节点的子节点。应该为树中的每个节点设置。

解决方案:

ItemsSource移至Children

然后您可能需要稍微修改MenuItemDTO

尝试下面的代码(经过测试,工作正常)。它返回属于第一级菜单的GetAllMenuItems()列表,每个菜单都递归填充MenuItemDTO

第一级树(菜单)=没有父级的菜单项

Children