2016-05-21 15 views
1

Ich versuche, das Microsoft-Beispielobjekt ObservableConcurrentDictionary.cs an ein TreeView zu binden. Ich habe nach Beispielen zum Binden eines Wörterbuchs gesucht, aber obwohl es viele Beispiele gibt, scheinen keine von ihnen für mich zu funktionieren. Immer wenn ich es starte, erscheint der Bildschirm mit einem leeren treeview (nur weißer Umriss). Ich habe meinen Code auf das absolute Minimum abgespeckte zu testen und meine Implementierung ist wie folgt:Wie binde ich ein ObservableConcurrentDictionary an WPF TreeView

<Window x:Name="AppWindow" x:Class="ControlCenter.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Control Center" Height="1000" Width="1200" 
    WindowStartupLocation="CenterScreen"> 
<Grid x:Name="left_grid" Margin="362,199,551,237"> 
    <TreeView ItemsSource="{Binding _hostList}"> 
     <TreeView.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding _hostList.Values}"/> 
      </DataTemplate> 
     </TreeView.ItemTemplate> 
    </TreeView> 
</Grid> 

public partial class MainWindow : Window 
{ 

    public ObservableConcurrentDictionary<string, string> _hostList = new ObservableConcurrentDictionary<string, string>(); 
    public MainWindow() 
    { 
     InitializeComponent(); 
     _hostList.Add("TestHost1", "Host1"); 
     _hostList.Add("TestHost2", "Host2"); 
     _hostList.Add("TestHost3", "Host3"); 
    } 
} 

using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.ComponentModel; 
using System.Threading; 
using System.Diagnostics; 

namespace System.Collections.Concurrent 
{ 
[DebuggerDisplay("Count={Count}")] 
public class ObservableConcurrentDictionary<TKey, TValue> : 
    ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>, 
    INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    private readonly SynchronizationContext _context; 
    private readonly ConcurrentDictionary<TKey, TValue> _dictionary; 

    /// <summary> 
    /// Initializes an instance of the ObservableConcurrentDictionary class. 
    /// </summary> 
    public ObservableConcurrentDictionary() 
    { 
     _context = AsyncOperationManager.SynchronizationContext; 
     _dictionary = new ConcurrentDictionary<TKey, TValue>(); 
    } 

    /// <summary>Event raised when the collection changes.</summary> 
    public event NotifyCollectionChangedEventHandler CollectionChanged; 
    /// <summary>Event raised when a property on the collection changes.</summary> 
    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary. 
    /// </summary> 
    private void NotifyObserversOfChange() 
    { 
     var collectionHandler = CollectionChanged; 
     var propertyHandler = PropertyChanged; 
     if (collectionHandler != null || propertyHandler != null) 
     { 
      _context.Post(s => 
      { 
       if (collectionHandler != null) 
       { 
        collectionHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
       } 
       if (propertyHandler != null) 
       { 
        propertyHandler(this, new PropertyChangedEventArgs("Count")); 
        propertyHandler(this, new PropertyChangedEventArgs("Keys")); 
        propertyHandler(this, new PropertyChangedEventArgs("Values")); 
       } 
      }, null); 
     } 
    } 

    /// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary> 
    /// <param name="item">The item to be added.</param> 
    /// <returns>Whether the add was successful.</returns> 
    private bool TryAddWithNotification(KeyValuePair<TKey, TValue> item) 
    { 
     return TryAddWithNotification(item.Key, item.Value); 
    } 

    /// <summary>Attempts to add an item to the dictionary, notifying observers of any changes.</summary> 
    /// <param name="key">The key of the item to be added.</param> 
    /// <param name="value">The value of the item to be added.</param> 
    /// <returns>Whether the add was successful.</returns> 
    private bool TryAddWithNotification(TKey key, TValue value) 
    { 
     bool result = _dictionary.TryAdd(key, value); 
     if (result) NotifyObserversOfChange(); 
     return result; 
    } 

    /// <summary>Attempts to remove an item from the dictionary, notifying observers of any changes.</summary> 
    /// <param name="key">The key of the item to be removed.</param> 
    /// <param name="value">The value of the item removed.</param> 
    /// <returns>Whether the removal was successful.</returns> 
    private bool TryRemoveWithNotification(TKey key, out TValue value) 
    { 
     bool result = _dictionary.TryRemove(key, out value); 
     if (result) NotifyObserversOfChange(); 
     return result; 
    } 

    /// <summary>Attempts to add or update an item in the dictionary, notifying observers of any changes.</summary> 
    /// <param name="key">The key of the item to be updated.</param> 
    /// <param name="value">The new value to set for the item.</param> 
    /// <returns>Whether the update was successful.</returns> 
    private void UpdateWithNotification(TKey key, TValue value) 
    { 
     _dictionary[key] = value; 
     NotifyObserversOfChange(); 
    } 

    #region ICollection<KeyValuePair<TKey,TValue>> Members 
    void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) 
    { 
     TryAddWithNotification(item); 
    } 

    void ICollection<KeyValuePair<TKey, TValue>>.Clear() 
    { 
     ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Clear(); 
     NotifyObserversOfChange(); 
    } 

    bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) 
    { 
     return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Contains(item); 
    } 

    void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 
    { 
     ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).CopyTo(array, arrayIndex); 
    } 

    int ICollection<KeyValuePair<TKey, TValue>>.Count 
    { 
     get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).Count; } 
    } 

    bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly 
    { 
     get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).IsReadOnly; } 
    } 

    bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) 
    { 
     TValue temp; 
     return TryRemoveWithNotification(item.Key, out temp); 
    } 
    #endregion 

    #region IEnumerable<KeyValuePair<TKey,TValue>> Members 
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() 
    { 
     return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return ((ICollection<KeyValuePair<TKey, TValue>>)_dictionary).GetEnumerator(); 
    } 
    #endregion 

    #region IDictionary<TKey,TValue> Members 
    public void Add(TKey key, TValue value) 
    { 
     TryAddWithNotification(key, value); 
    } 

    public bool ContainsKey(TKey key) 
    { 
     return _dictionary.ContainsKey(key); 
    } 

    public ICollection<TKey> Keys 
    { 
     get { return _dictionary.Keys; } 
    } 

    public bool Remove(TKey key) 
    { 
     TValue temp; 
     return TryRemoveWithNotification(key, out temp); 
    } 

    public bool TryGetValue(TKey key, out TValue value) 
    { 
     return _dictionary.TryGetValue(key, out value); 
    } 

    public ICollection<TValue> Values 
    { 
     get { return _dictionary.Values; } 
    } 

    public TValue this[TKey key] 
    { 
     get { return _dictionary[key]; } 
     set { UpdateWithNotification(key, value); } 
    } 
    #endregion 
} 

}

Antwort

2

Es gibt ein paar Probleme. Zuerst, da Sie keine Quelle in Ihrer Bindung angegeben haben, wird diese von der DataContext entfernt, die null ist.

Ich denke, dass Sie denken, dass, da Sie mit MainWindow arbeiten, dass die Quelle Ihrer verbindlichen Aussagen das MainWindow Objekt sein wird, aber das ist nicht der Standard für eine Bindung. Wenn Sie dies tun wollten, müssten Sie in Ihren Bindungen eine RelativeSource verwenden, aber normalerweise würden Sie die Sammlung einfach in die DataContext als Teil eines Ansichtsmodells oder direkt als das gesamte Ansichtsmodell einfügen. Etwas wie folgt aus:

public ObservableConcurrentDictionary<string, string> _hostList = new ObservableConcurrentDictionary<string, string>(); 
public MainWindow() 
{ 
    InitializeComponent(); 
    _hostList.Add("TestHost1", "Host1"); 
    _hostList.Add("TestHost2", "Host2"); 
    _hostList.Add("TestHost3", "Host3"); 
    DataContext = _hostList; 
} 

Dann werden Sie nur Ihre Bindungen aus der DataContext gehen so würden Sie Ihren Code wie folgt aktualisieren:

<TreeView ItemsSource="{Binding}"> 
    <TreeView.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding Values}"/> 
     </DataTemplate> 
    </TreeView.ItemTemplate> 
</TreeView> 

Dies wird nicht vollständig lösen Ihre Probleme, die ich denke bin obwohl ich denke, dass du an die falschen Eigenschaften gebunden bist. ItemsSource sollte für etwas bindend sein, das ein IEnumerable irgendeiner Art ist, und sollte an ein string binden.

Also ich bin mir nicht sicher, was Sie im Idealfall versuchen zu zeigen, aber bin mir ziemlich sicher, dass Sie nicht richtig binden. In der Regel mit einem TreeView werden Sie eine HierarchicalDataTemplate verwenden und ich denke, das ist wahrscheinlich das, was Sie verwenden möchten.