在我目前的项目中,我需要将日志输出显示到一个单独的窗口中,但无论出于何种原因我都无法使用它。由于我对WPF数据绑定很陌生,我怀疑问题是我; O)。
这是它应该如何工作:
有三个视图模型类,每个类代表另一个的聚合(为清晰起见而消化)
// The VM starting point, using a Singleton instance
// It holds a collection of log "sources", each representing a separate class' logging
internal sealed class ClassLogVM : DependencyObject
{
private readonly Dictionary<object, ClassLogSourceVM> _sourceIndex;
private readonly object _syncRoot;
/* dependency property initialization omitted */
private static ClassLogVM _s_singleton;
public static ClassLogVM Singleton
{
get { return _s_singleton ?? (_s_singleton = new ClassLogVM()); }
}
public IEnumerable<ClassLogSourceVM> Items
{
get { return (IEnumerable<ClassLogSourceVM>) GetValue(_s_itemsProp); }
set { SetValue(_s_itemsProp, value); }
}
private void classLogLogged(object sender, ClassLogEventArgs args)
{
VM.InvokeInUiThread(() =>
{
ClassLogSourceVM source;
var caller = args.Caller == null ? "(unknown)" : args.Caller.ToString();
lock (_syncRoot)
if (!_sourceIndex.ContainsKey(caller))
{
source = new ClassLogSourceVM(caller);
((List<ClassLogSourceVM>) Items).Add(source);
_sourceIndex.Add(caller, source);
}
else
source = _sourceIndex[caller];
source.Add(new ClassLogItemVM(args.Timestamp, args.Message));
});
}
private ClassLogVM()
{
_syncRoot = new object();
_sourceIndex = new Dictionary<object, ClassLogSourceVM>();
Items = new List<ClassLogSourceVM>();
ClassLog.Logged += classLogLogged;
}
}
// represents a collection of log entries (see: Items property)
public class ClassLogSourceVM : DependencyObject
{
public string Name
{
get { return (string) GetValue(_s_nameProp); }
set { SetValue(_s_nameProp, value); }
}
public IEnumerable<ClassLogItemVM> Items
{
get { return (IEnumerable<ClassLogItemVM>)GetValue(_s_itemsProp); }
private set { SetValue(_s_itemsProp, value); }
}
public void Add(ClassLogItemVM item)
{
((List<ClassLogItemVM>)Items).Add(item);
}
public override string ToString()
{
return GetValue(_s_nameProp) + " (Count: " + Items.Count() + ")";
}
public ClassLogSourceVM(string name)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException("name");
SetValue(_s_nameProp, name);
Items = new List<ClassLogItemVM>();
}
}
// represents an individual log entry
public sealed class ClassLogItemVM : DependencyObject
{
public DateTime Timestamp
{
get { return (DateTime) GetValue(_s_timestampProp); }
}
public string Message
{
get { return (string) GetValue(_s_messageProp); }
set { SetValue(_s_messageProp, value); }
}
public override string ToString()
{
return Timestamp.ToString("HH:mm:ss:fff") + ": " + Message;
}
public ClassLogItemVM(DateTime timestamp, string message)
{
SetValue(_s_timestampProp, timestamp);
SetValue(_s_messageProp, message);
}
}
这就是我设置XAML(用户控件叫做“ClassLogView”)的方法......
<UserControl x:Class="GeDevelop.GVSViewer.Views.Debug.ClassLogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Debug="clr-namespace:GeDevelop.GVSViewer.ViewModel.Debug"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding Debug:ClassLogVM.Singleton.Items}">
<UserControl.Resources>
<CollectionViewSource x:Key="sources" Source="{Binding}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Source" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate DataType="{x:Type Debug:ClassLogSourceVM}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</UserControl.Resources>
<Grid d:DataContext="{Binding Debug:ClassLogVM.Singleton}">
<TreeView ItemsSource="{Binding Source={StaticResource sources}}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type Debug:ClassLogSourceVM}" ItemsSource="{Binding Items}">
<TextBlock Text="{Binding}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
结果是Treeview为空。
现在,我的问题是: 1.我错过了什么,导致TreeView什么都没显示? 2.我需要以编程方式将DataContext分配给用户控件,尽管我在标签中已经说明了这一点。为什么呢?
会很感激解释。 WPF肯定不适合胆小的人......; O)
答案 0 :(得分:0)
据我所知,这不是你如何创建DependencyProperties。 DependencyObject是大多数UIElements的核心/基类,我会非常谨慎地将我的课程建立在它上面。
Google或在StackOverflow中搜索DependencyProperty,如果你真的想使用它。
在大多数情况下,使用INotifyPropertyChanged包装DomainModel / BusinessObject足以让WPF绑定拾取它