2011-07-07 9 views
1

私の現在のプロジェクトでは、ログ出力を別のウィンドウに表示する必要がありますが、何らかの理由でそれを動作させることはできません。私はWPFのデータバインディングにはかなり新しいので、問題は私だと思う; O)。ここでいくつかのWPFバインディングの質問

は、それが動作するようになっています方法は次のとおりです。

3つのビューモデルクラス、(明確にするために消化)別の集計を表す各があります

// 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> 

その結果、ツリービューは空です。

私の質問は次のとおりです。 1.何が表示されないのですか? 2.私はタグ内に記述したにもかかわらず、プログラムでDataContextをユーザーコントロールに割り当てる必要があります。どうして?

説明がわかります。 WPFは確かに哀れな心配ではありません...; O)

答えて

0

私が知る限り、DependencyPropertiesをどのように作成しますか。 DependencyObjectはほとんどのUIElementsのコア/ベースクラスです。クラスをベースにするのは非常に慎重です。

Googleを使用するか、実際に使用したい場合はDependencyPropertyのStackOverflowで検索してください。多くの場合

は、ラップINotifyPropertyChangedのとあなたのドメインモデル/てBusinessObjectは、WPFは

+0

は、なぜあなたはそれはあなたがDependencyPropertiesを作成する方法はありませんと言うんそれを拾う結合取得するには十分すぎるほどでしょうか? OPは実際のDependencyProperty.Register呼び出しを削除しましたが、それ以外の場合は合法に見えます。確かに、DependencyObjectからViewModelオブジェクトを降下させるのは少し珍しいことです。これは、多くの人がUIレイヤーに属すると考えているアセンブリへの依存度が高いからですが、それはやや主観的です - DependencyObjectsを使用して何かを得ることができたら、価値がある。 –

+0

私は 'DependencyObject'に基づいて他のVMクラスを構築しました。しかし、私は他の開発者がこれを行うことを警告し、代わりに 'INotifyPropertyChanged'の使用を推奨しています。私はこれを試しましたが、DOアプローチで働くバインディングは 'INotifyPropertyChanged'では機能しないようです。なぜ私は考えていない。 –

+0

あなたがViewModelをUIに依存させるべきでない場合、ViewModelを他のビューと共に使用したいということです。WPFアセンブリを同梱して出荷します。 –

関連する問題