未填充WPF树视图

未填充WPF树视图,wpf,treeview,viewmodel,populate,Wpf,Treeview,Viewmodel,Populate,我试图通过使用ViewModel动态填充WPF树,但是,由于某些原因,它不起作用。要么绑定不正确,要么我在代码背后的某个地方搞砸了 这是我的一个样本。 在XAML中,我定义我的树视图如下 <TreeView DockPanel.Dock="Left" Width="200" DataContext="{Binding MessageTree}" ItemsSource="{Binding MessageTree}"> <TreeView.ItemContainerSty

我试图通过使用ViewModel动态填充WPF树,但是,由于某些原因,它不起作用。要么绑定不正确,要么我在代码背后的某个地方搞砸了

这是我的一个样本。 在XAML中,我定义我的树视图如下

<TreeView DockPanel.Dock="Left" Width="200" DataContext="{Binding MessageTree}" ItemsSource="{Binding MessageTree}">
    <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            <Setter Property="FontWeight" Value="Normal" />
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="FontWeight" Value="Bold" />
                </Trigger>
            </Style.Triggers>
        </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate DataType="viewModel:Mail" ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Subject}" />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

邮件被定义为

public sealed class Mail : INotifyPropertyChanged
{
    private readonly ObservableCollection<Mail> _children;
    private readonly MailMessage _msg;
    private readonly Mail _parent;

    private bool _isExpanded;
    private bool _isSelected;

    public Mail()
    {
        _msg = new MailMessage {Subject = "Empty"};
        _parent = null;
        _children = new ObservableCollection<Mail>();
    }

    public Mail(MailMessage msg, Mail parent = null)
    {
        _msg = msg;
        _parent = parent;
        _children = new ObservableCollection<Mail>();
    }

    public IEnumerable<Mail> Children
    {
        get { return _children; }
    }

    public string Subject
    {
        get { return _msg.Subject; }
    }

    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (value != _isExpanded)
            {
                _isExpanded = value;
                OnPropertyChanged();
            }
            if (_isExpanded && _parent != null)
                _parent.IsExpanded = true;
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value != _isSelected)
            {
                _isSelected = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void Add(MailMessage msg)
    {
        _children.Add(new Mail(msg, this));
        OnPropertyChanged("Children");
    }

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
公共密封类邮件:INotifyPropertyChanged
{
私有只读可观察收集子对象;
私人只读邮件消息_msg;
私人只读邮件\u父级;
私人住宅被扩展;
私立学校当选;
公共邮件()
{
_msg=新邮件{Subject=“Empty”};
_parent=null;
_children=新的ObservableCollection();
}
公共邮件(MailMessage msg,Mail parent=null)
{
_味精=味精;
_父母=父母;
_children=新的ObservableCollection();
}
可数儿童的公共教育
{
获取{return\u children;}
}
公共字符串主题
{
获取{return\u msg.Subject;}
}
公共图书馆被扩展了
{
获取{return\u isExpanded;}
设置
{
如果(值!=\u扩展)
{
_isExpanded=值;
OnPropertyChanged();
}
if(_isExpanded&&u parent!=null)
_parent.IsExpanded=true;
}
}
公选学校
{
获取{return}isSelected;}
设置
{
如果(值!=\u已选择)
{
_isSelected=值;
OnPropertyChanged();
}
}
}
公共事件属性更改事件处理程序属性更改;
公共无效添加(邮件消息消息)
{
_添加(新邮件(msg,this));
财产变更(“子女”);
}
私有void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(handler!=null)handler(这是新的PropertyChangedEventArgs(propertyName));
}
}
我在里面找不到任何与网上找到的例子如此不同的东西,以至于它不起作用。Add方法不完整,我仍然需要一些逻辑来决定是将它们添加到集合中还是添加到集合成员之一的集合中,但正如我的所有邮件对象都已添加到集合中,但没有显示在树视图中一样

我遗漏了什么显而易见的东西?当我向集合中添加项目时,树视图不应该自动更新吗


我想让TreeView显示MessageTree属性的子级,以及这些子级的子级。

在没有看到整个设置的情况下,我不是肯定的,但我的猜测是,因为MessageTree是一个普通的CLR属性(与引发PropertyChanged或DependencyProperty或其他内容不同的是,绑定发生在您的
MessageTree=new Mail();
调用之前。当您将其设置为新实例时,绑定系统不会收到通知,因为它是普通属性


另一个潜在的问题是,您说代码在代码隐藏中。仅使用该绑定语法不会从代码隐藏中获取属性。可能是您在代码中的其他地方设置了未显示的属性。但通常情况下,您不会从视图绑定到代码隐藏,而是绑定到用作视图本身数据上下文的ViewModel。

编辑:在我的手机上看不到全部内容-根据实际查看所有内容的能力修改答案。:)

MOREEDIT:根据评论更新,让我们从头开始

首先,如果您打算使用window/whatever作为datacontext,那么让我们将其设置为“INotifyPropertyChange”……接下来,让“MessageTree”成为邮件的集合,而不仅仅是单个邮件(相信我,这将使绑定语义更容易)

public类树中包含的内容:窗口,InotifyProperty已更改
{
公共WhateverContainsTheTree()
{
此.Loaded+=已加载;
这是。_messageTree=newobservetecollection();
this.DataContext=this;
}
已加载专用void(对象发送方,RoutedEventArgs e)
{
_worker=新的BackgroundWorker();
_worker.DoWork+=WorkerWorkin;
_worker.RunWorkerAsync();
}
私人背景工人;
私有可观察收集(messageTree);
公共可观察收集消息树
{ 
获取{return\u messageTree;}
设置{u messageTree=value;RaisePropertyChanged(“messageTree”);}
}
公共事件PropertyChangedEventHandler PropertyChanged=委托{};
私有void RaisePropertyChanged(字符串propertyName)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
私有void WorkerWorkin(对象发送方,DoWorkerVentargs e)
{
//显然,将此更改为您的内容;我添加了一个ctor以便可以传递字符串
睡眠(3000);
Console.WriteLine(“确定,设置消息树”);
调度程序。调用(
System.Windows.Threading.DispatcherPriority.Normal,
(行动)(()=>
{ 
var mail1=新邮件(“邮件1:从后台线程更改”);
var mail2=新邮件(“邮件2:邮件1的子邮件”);
var mail3=新邮件(“邮件3:邮件的子邮件2”);
var mail4=新邮件(“邮件4:邮件的子邮件1”);
var mail5=新邮件(“邮件5:邮件的子邮件4”);
mail1.Children.Add(mail2);
mail1.Children.Add(mail4);
mail2.Children.Add(mail3);
mail4.Children.Add(mail5);
MessageTree.Add(mail1);
})
);
}
}
另外,正如我在最初的回复中所说,让我们稍微调整一下邮件。孩子们:

public ObservableCollection<Mail> Children
{
    get { return _children; }
}
公共可观察收集子对象
{
public sealed class Mail : INotifyPropertyChanged
{
    private readonly ObservableCollection<Mail> _children;
    private readonly MailMessage _msg;
    private readonly Mail _parent;

    private bool _isExpanded;
    private bool _isSelected;

    public Mail()
    {
        _msg = new MailMessage {Subject = "Empty"};
        _parent = null;
        _children = new ObservableCollection<Mail>();
    }

    public Mail(MailMessage msg, Mail parent = null)
    {
        _msg = msg;
        _parent = parent;
        _children = new ObservableCollection<Mail>();
    }

    public IEnumerable<Mail> Children
    {
        get { return _children; }
    }

    public string Subject
    {
        get { return _msg.Subject; }
    }

    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (value != _isExpanded)
            {
                _isExpanded = value;
                OnPropertyChanged();
            }
            if (_isExpanded && _parent != null)
                _parent.IsExpanded = true;
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value != _isSelected)
            {
                _isSelected = value;
                OnPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void Add(MailMessage msg)
    {
        _children.Add(new Mail(msg, this));
        OnPropertyChanged("Children");
    }

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class WhateverContainsTheTree : Window, INotifyPropertyChanged
{
    public WhateverContainsTheTree()
    {
        this.Loaded += OnLoaded;
        this._messageTree = new ObservableCollection<Mail>();
        this.DataContext = this;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        _worker = new BackgroundWorker();
        _worker.DoWork += WorkerWorkin;
        _worker.RunWorkerAsync();
    }

    private BackgroundWorker _worker;
    private ObservableCollection<Mail> _messageTree;    
    public ObservableCollection<Mail> MessageTree 
    { 
        get { return _messageTree; }  
        set { _messageTree = value; RaisePropertyChanged("MessageTree"); } 
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate {};
    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private void WorkerWorkin(object sender, DoWorkEventArgs e)
    {
                // obviously, change this to your stuff; I added a ctor so I could pass a string
        Thread.Sleep(3000);
        Console.WriteLine("Ok, setting message tree");
        Dispatcher.Invoke(
            System.Windows.Threading.DispatcherPriority.Normal,
            (Action)(() => 
            { 
                var mail1 = new Mail("Mail#1:Changed from background thread");
                var mail2 = new Mail("Mail#2:Submail of mail #1");
                var mail3 = new Mail("Mail#3:Submail of mail #2");
                var mail4 = new Mail("Mail#4:Submail of mail #1");
                var mail5 = new Mail("Mail#5:Submail of mail #4");
                mail1.Children.Add(mail2);
                mail1.Children.Add(mail4);
                mail2.Children.Add(mail3);
                mail4.Children.Add(mail5);
                MessageTree.Add(mail1);
            })
        );
    }
}
public ObservableCollection<Mail> Children
{
    get { return _children; }
}
<TreeView DockPanel.Dock="Left" Width="200" ItemsSource="{{Binding MessageTree}}">
    <TreeView.ItemContainerStyle>
            <Style TargetType="{{x:Type TreeViewItem}}">
            <Setter Property="IsExpanded" Value="{{Binding IsExpanded, Mode=TwoWay}}" />
            <Setter Property="IsSelected" Value="{{Binding IsSelected, Mode=TwoWay}}" />
            <Setter Property="FontWeight" Value="Normal" />
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="FontWeight" Value="Bold" />
                </Trigger>
            </Style.Triggers>
        </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate DataType="viewModel:Mail" ItemsSource="{{Binding Children}}">
                <TextBlock Text="{{Binding Subject}}" />
            </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>
MessageTree = new Mail();
Tree.ItemSource = MessageTree.Children;