В моем текущем проекте мне нужно отобразить вывод журнала в отдельном окне, но по какой-то причине я не могу заставить его работать.Поскольку я довольно новичок в связывании данных 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)