c# - TreeView 的子节点无法反射(reflect)绑定(bind)的变化

标签 c# wpf mvvm binding treeview

只有顶级节点可以反射(reflect)背后的变化,但它们的节点不能。有任何想法吗?谢谢!在下面的代码中,它应该同时添加一个新经理和一个新员工
.

楷模

public class Employee
{
    public Guid EmployeeId { get; set; }
    public string EmployeeName { get; set; }
}

public class Manager
{
    public Guid ManagerId { get; set; }
    public string ManagerName { get; set; }
    public IEnumerable<Employee> Employees { get; set; }
}

View 模型
public class TreeWindowViewModel : INotifyPropertyChanged
{
    private List<Employee> employeeList = new List<Employee>();
    private List<Manager> managerList = new List<Manager>();

    public TreeWindowViewModel()
    {
        //Create fake data for testing
        employeeList.Add(new Employee() { EmployeeId = Guid.NewGuid(), EmployeeName = "Adam" });
        employeeList.Add(new Employee() { EmployeeId = Guid.NewGuid(), EmployeeName = "Benson" });
        employeeList.Add(new Employee() { EmployeeId = Guid.NewGuid(), EmployeeName = "Cooker" });
        employeeList.Add(new Employee() { EmployeeId = Guid.NewGuid(), EmployeeName = "Denny" });
        employeeList.Add(new Employee() { EmployeeId = Guid.NewGuid(), EmployeeName = "Ellis" });

        //Create ObservableCollection object
        employees = new ObservableCollection<Employee>(employeeList);

        //Create 2 managers and make 
        Manager manager1 = new Manager()
        {
            ManagerId = Guid.NewGuid(),
            ManagerName = "Frank",
            Employees = new List<Employee>(employeeList)
        };

        Manager manager2 = new Manager()
        {
            ManagerId = Guid.NewGuid(),
            ManagerName = "Green",
            Employees = new List<Employee>(employeeList)
        };

        managerList.Add(manager1);
        managerList.Add(manager2);

        managers = new ObservableCollection<Manager>(managerList);

    }

    private ObservableCollection<Manager> managers;
    public ObservableCollection<Manager> Managers
    {
        get
        {
            return managers;
        }
        set
        {
            managers = value;

            OnPropertyChanged(new PropertyChangedEventArgs("Managers"));
        }
    }

    private ObservableCollection<Employee> employees;
    public ObservableCollection<Employee> Employees
    {
        get
        {
            return employees;
        }
        set
        {
            employees = value;

            OnPropertyChanged(new PropertyChangedEventArgs("Employees"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }
}

XAML
    <Window x:Class="BindingTests.TreeWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:m="clr-namespace:BindingTests.Models"
        Title="TreeWindow" Height="300" Width="300">
    <Window.Resources>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Employees}" DataType="{x:Type m:Manager}">
            <TextBlock Text="{Binding Path=ManagerName}"/>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type m:Employee}">
            <TextBlock Text="{Binding Path=EmployeeName}"/>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TreeView ItemsSource="{Binding Managers, Mode=OneWay, NotifyOnSourceUpdated=True}" Grid.Column="0">
            <TreeView.Resources>
                <Style TargetType="Label">
                    <Setter Property="Margin" Value="0"/>
                    <Setter Property="Padding" Value="0"/>
                </Style>
                <Style TargetType="TreeViewItem">
                    <Setter Property="Margin" Value="0"/>
                    <Setter Property="Padding" Value="0"/>
                </Style>
            </TreeView.Resources>
        </TreeView>
        <StackPanel Grid.Column="1">
            <Button Content="Click me to add a manager" Click="Button_Click" Height="30"/>
        </StackPanel>
    </Grid>
</Window>

XAML.CS
    namespace BindingTests
    {
    /// <summary>
    /// Interaction logic for TreeWindow.xaml
    /// </summary>
    public partial class TreeWindow : Window
    {
        public TreeWindow()
        {
            InitializeComponent();

            this.DataContext = new TreeWindowViewModel();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TreeWindowViewModel ds = this.DataContext as TreeWindowViewModel;
            if (ds != null)
            {
                ds.Managers.Add(new Manager() { ManagerId = Guid.NewGuid(), ManagerName = "New Manager" });
                ds.Employees.Add(new Employee() { EmployeeId = Guid.NewGuid(), EmployeeName = "New Employee"});
            }
        }
    }
}

Initial UI

enter image description here

最佳答案

您没有得到预期结果的主要原因是您添加了 Employeepublic ObservableCollection<Employee> Employees ,并且 UI 上的任何地方都没有绑定(bind)。您真正看到的 Managers 的初始列表绑定(bind)到 TreeView . <HierarchicalDataTemplate ItemsSource="{Binding Path=Employees}" ...实际上是在看Manager.Employees ,所以在你的按钮点击中,如果你这样做了:

if (ds != null)
{
    ds.Managers.Add(new Manager() { ManagerId = Guid.NewGuid(), ManagerName = "New Manager" });
    ds.Managers[0].Employees.Add(new Employee() { EmployeeId = Guid.NewGuid(), EmployeeName = "New Employee"});
}

然后您会看到在经理“Frank”下添加了“新员工”。所以我认为你的代码没问题,只是你添加它的方式导致了问题。

您的下一个问题可能是:“我怎么知道应该向谁添加员工?”这就是您要创建 public object SelectedItem 的地方在您的 TreeWindowViewModel并将其绑定(bind)到可以添加到 TreeView 的依赖属性, 自 TreeViewSelectedItem是一个只读的非 DP。然后你就可以调用类似的东西:
if(ds.SelectedItem is Manager)
{
    (ds.SelectedItem as Manager).Employees.Add( ... );
}

但是现在我们已经超出了范围,将来可能会为您提出一个新的 SO 问题。

关于c# - TreeView 的子节点无法反射(reflect)绑定(bind)的变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26144608/

相关文章:

c# - 代码找不到类

c# - 根据for循环位置制作字典的键

c# - 将图像附加到 MSTest 中的测试报告

mvvm - 如何将自动完成框与 mvvm 中的模型绑定(bind)?

c# - 传递流的子序列而不将其内容复制到新实例中

wpf - 什么时候应该使用 ComponentResourceKey 而不是字符串作为资源键?

c# - Dispatcher.Invoke 和传播错误

c# - 窗口 ResizeMode 绑定(bind)到设置

c# - UI 未从单独 ViewModel 的命令调用的 ObservableCollection 进行更新

c# - wpf - 一个用于动态选项卡的 ViewModel