分层结构未在视图中更新

时间:2017-10-01 21:14:44

标签: c# wpf xaml mvvm

我基本上有这个XAML和ViewModel:

 <ResourceDictionary>

            <DataTemplate DataType="{x:Type bizzTypes:WindowsDirectory}" x:Key="directory">
                <Expander Header="{Binding Path=Name}" Expanded="Expander_Expanded" Cursor="Hand" MouseLeftButtonDown="Expander_MouseLeftButtonDown">
                    <Expander.Content>
                        <ItemsControl  ItemsSource="{Binding Path=Directories, Mode=TwoWay}" ItemTemplate="{DynamicResource ResourceKey=directory}">
                        </ItemsControl>
                    </Expander.Content>
                </Expander>
            </DataTemplate>
            <DataTemplate DataType="{x:Type bizzTypes:WindowsDrive}" x:Key="drive">
                <Expander Header="{Binding Path=PathFormattedHeader}" Cursor="Hand">
                    <Expander.Content>
                        <ItemsControl ItemsSource="{Binding Path=Directories, Mode=TwoWay}" ItemTemplate="{StaticResource ResourceKey=directory}"></ItemsControl>
                    </Expander.Content>
                </Expander>
            </DataTemplate>
        </ResourceDictionary>
    </Base:ControlBase.Resources>
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="350" />
            <ColumnDefinition Width="3" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="25" />
            <RowDefinition />
            <RowDefinition Height="25" />
        </Grid.RowDefinitions>
        <GridSplitter Grid.Column="1" Grid.Row="1" Width="3" HorizontalAlignment="Left" />
        <ItemsControl Grid.Row="0" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        </ItemsControl>
        <ScrollViewer HorizontalAlignment="Stretch" Grid.Row="1" VerticalAlignment="Stretch" x:Name="Drives">
            <ItemsControl  ItemsSource="{Binding Path=Drives, Mode=TwoWay}" ItemTemplate="{DynamicResource drive}">
            </ItemsControl>
        </ScrollViewer>

我背后有这个视图模型

  public class WindowsDirectory
  {
  private ObservableCollection<WindowsDirectory> _directories { get; set; }
  public ObservableCollection<WindowsDirectory> Directories 
  {
       get
       {
           return _directories;
       }
       private set
       {
           _directories = value;
           RaisePropertyChanged(nameof(Directories));
       }
  }
  }

如果在渲染WPF UI之前填充数据树,它基本上可以工作。但每当我更新ObservableCollection<WindowsDirectory> Directories时,WPF UI都不会反映Obervable中所做的更改。该目录不会更新为RaisePropertyChanged(nameof(Directories));而没有RaisePropertyChanged我会得到一个空的ItemsControl

任何有关为何会发生这种情况的想法?

1 个答案:

答案 0 :(得分:1)

以下是一个例子:

  • HierarchicalDataTemplate
  • 使用ObservableCollection<T>
  • 进行实时更新
  • 向树中添加随机元素的按钮

<强>元素

namespace WpfApp2
{
    public interface IFileSystemElement
    {
        string Name { get; }
    }
}

元素助手

namespace WpfApp2
{
    public abstract class FileSystemElement : IFileSystemElement
    {
        protected FileSystemElement(string name)
        {
            Name = name;
        }

        public string Name { get; }

        public override string ToString()
        {
            return Name;
        }
    }
}

文件

namespace WpfApp2
{
    public class File : FileSystemElement
    {
        public File(string name) : base(name)
        {
        }
    }
}

<强>目录

using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace WpfApp2
{
    public class Directory : FileSystemElement, IEnumerable<IFileSystemElement>
    {
        public Directory(string name) : base(name)
        {
        }

        public ICollection<IFileSystemElement> Elements { get; } = new ObservableCollection<IFileSystemElement>();

        public IEnumerator<IFileSystemElement> GetEnumerator()
        {
            return Elements.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable) Elements).GetEnumerator();
        }

        public T Add<T>(T item) where T : IFileSystemElement
        {
            Elements.Add(item);
            return item;
        }
    }
}

查看

using System;
using System.Windows;

namespace WpfApp2
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();

            var level0 = new Directory("level 0");
            var level1 = level0.Add(new Directory("level 1"));
            var level2 = level1.Add(new Directory("level 2"));
            var file1 = level2.Add(new File("file 1"));
            var file2 = level2.Add(new File("file 2"));
            DataContext = new[] {level0}; // to show root in tree
        }

        private Random Random { get; } = new Random();

        private Directory SelectedDirectory { get; set; }

        private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            SelectedDirectory = e.NewValue as Directory;
            Button.IsEnabled = SelectedDirectory != null;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var next = Random.Next(2);

            switch (next)
            {
                case 0:
                    SelectedDirectory.Add(new Directory("New directory"));
                    break;
                case 1:
                    SelectedDirectory.Add(new File("New file"));
                    break;
            }
        }
    }
}

查看

<Window
    x:Class="WpfApp2.MainWindow"
    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:local="clr-namespace:WpfApp2"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <TreeView
            Grid.Row="0"
            ItemsSource="{Binding}"
            SelectedItemChanged="TreeView_OnSelectedItemChanged">
            <TreeView.ItemContainerStyle>
                <Style TargetType="TreeViewItem">
                    <Setter Property="IsExpanded" Value="True" />
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate DataType="local:Directory" ItemsSource="{Binding Elements}">
                    <TextBlock Text="{Binding}" />
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>

        <Button
            x:Name="Button"
            Grid.Row="1"
            Click="Button_Click"
            Content="Button"
            IsEnabled="False" />

    </Grid>
</Window>