将"extra"节点添加到 XAML 树视图



使用MVVM模式,我试图在XAML中构建一个TreeView,看起来像这样(注意括号内的项目实际上代表按钮):

- [Edit] [Delete] Location 1
    - [Edit] [Delete] Location 1, Project 1
    - [Edit] [Delete] Location 1, Project 2
    - [Edit] [Delete] Location 1, Project 3
    - [New Project]
- [Edit] [Delete] Location 2
    - [Edit] [Delete] Location 2, Project 1
    - [New Project]
- [Edit] [Delete] Location 3
    - [Edit] [Delete] Location 3, Project 1
    - [Edit] [Delete] Location 3, Project 2
    - [New Project]
- [New Location]

这个想法是,TreeView中的每个节点在标题文本旁边都有两个按钮,用户可以单击它们来删除/编辑节点。然后,在每个项目"组"的底部,有一个[新建项目]按钮,可以点击该按钮向该"组"添加新项目。最后,在整个TreeView的底部有一个[New Location]按钮,这样就可以添加一个新的Location节点。

我有TreeView和[新位置]按钮正确布局,但不知道如何将[新项目]按钮添加到每个位置的项目组的底部。我试过使用多个嵌套的TreeView控件,但是分组和滚动似乎不像预期的那样起作用。

下面是我的MainPageView代码:
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="SilverlightApplication2.MainPageView"
    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:silverlightApplication2="clr-namespace:SilverlightApplication2"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.DataContext>
        <silverlightApplication2:MainPageViewModel/>
    </UserControl.DataContext>
    <StackPanel Orientation="Vertical">
        <sdk:TreeView ItemsSource="{Binding Locations}" BorderBrush="Transparent">
            <sdk:TreeView.ItemTemplate>
                <sdk:HierarchicalDataTemplate ItemsSource="{Binding Projects}">
                    <StackPanel Orientation="Horizontal">
                        <Button Margin="2">
                            <Image Source="edit.png"/>
                            <ToolTipService.ToolTip>
                                <ToolTip Content="Edit item"/>
                            </ToolTipService.ToolTip>
                        </Button>
                        <Button Margin="2">
                            <Image Source="delete.png"/>
                            <ToolTipService.ToolTip>
                                <ToolTip Content="Delete item"/>
                            </ToolTipService.ToolTip>
                        </Button>
                        <sdk:TreeViewItem Header="{Binding Name}"/>
                    </StackPanel>
                </sdk:HierarchicalDataTemplate>
            </sdk:TreeView.ItemTemplate>
        </sdk:TreeView>
        <Button Margin="30,0,0,0" Height="23" Width="23" HorizontalAlignment="Left">
            <Image Source="green-plus-sign-md.png"></Image>
            <ToolTipService.ToolTip>
                <ToolTip Content="Add new location"/>
            </ToolTipService.ToolTip>
        </Button>
    </StackPanel>
</UserControl>
下面是我的MainPageViewModel代码:
using System.Collections.ObjectModel;
namespace SilverlightApplication2
{
    public class MainPageViewModel
    {
        #region Constructors
        public MainPageViewModel()
        {
            this.Locations = new ObservableCollection<LocationViewModel>
                                 {
                                     new LocationViewModel
                                         {
                                             Name = "Location 1",
                                             Projects = new ObservableCollection<ProjectViewModel>
                                                            {
                                                                new ProjectViewModel { Name = "Location 1 - Project 1"},
                                                                new ProjectViewModel { Name = "Location 1 - Project 2"},
                                                                new ProjectViewModel { Name = "Location 1 - Project 3"},
                                                                new ProjectViewModel { Name = "Location 1 - Project 4"},
                                                            }
                                         },
                                     new LocationViewModel
                                         {
                                             Name = "Location 2",
                                             Projects = new ObservableCollection<ProjectViewModel>
                                                            {
                                                                new ProjectViewModel { Name = "Location 2 - Project 1"},
                                                                new ProjectViewModel { Name = "Location 2 - Project 2"}
                                                            }
                                         },
                                     new LocationViewModel
                                         {
                                             Name = "Location 3",
                                             Projects = new ObservableCollection<ProjectViewModel>
                                                            {
                                                                new ProjectViewModel { Name = "Location 3 - Project 1"},
                                                                new ProjectViewModel { Name = "Location 3 - Project 2"},
                                                                new ProjectViewModel { Name = "Location 3 - Project 3"},
                                                                new ProjectViewModel { Name = "Location 3 - Project 4"},
                                                                new ProjectViewModel { Name = "Location 3 - Project 5"},
                                                                new ProjectViewModel { Name = "Location 3 - Project 6"},
                                                                new ProjectViewModel { Name = "Location 3 - Project 7"}
                                                            }
                                         }
                                 };
        }
        #endregion
        #region Properties
        public ObservableCollection<LocationViewModel> Locations { get; set; } 
        #endregion
    }
}

这里是LocationViewModelCode:

using System.Collections.ObjectModel;
using Microsoft.Practices.Prism.ViewModel;

namespace SilverlightApplication2
{
    public class LocationViewModel : NotificationObject
    {
        #region Properties
        public string Name { get; set; }
        public ObservableCollection<ProjectViewModel> Projects { get; set; }
        #endregion
    }
}
最后,ProjectViewModel代码:
namespace SilverlightApplication2
{
    public class ProjectViewModel
    {
        #region Properties
        public string Name { get; set; }
        #endregion
    }
}

正如你所看到的,我在Silverlight中这样做,但是如果有人知道如何做到这一点,WPF解决方案可能会同样好。

我也意识到,这可能可以很容易地完成代码隐藏,但我试图保持真实的MVVM模式,并找到一种方法来做这个纯粹在XAML。

谢谢你的帮助

我将泛化树节点的视图模型。

可能有IsLocation, IsProject和HasContent属性。

HasContent属性可以控制节点是否显示"New…"的链接。然后你可以在该链接的命令中检查它的类型。

如果你不想拥有IsLocation和IsProject,你可以为树节点使用一个抽象基类,并从它继承两个类型。两者对HasContent都有类似的逻辑,然后对'New'逻辑有不同的命令

也许重新考虑架构会有所帮助?

我个人认为"新项目"操作是对Location对象的操作,而不是位于Projects集合内的操作。在这种情况下,您的"新项目"按钮可能应该与Location的根editdelete按钮放在一起。

也许不是直接回答你的问题,而是一个侧面的方法。

最新更新