0

にバインドされたタブ付きウィジェットがありDictionary<string, DataTable>ます。タブ名はディクショナリにバインドされKeys、タブの内容は にバインドされますDataTables。これはすべて正常にロードされますが、構築後の特定されていない時点で、すべてのテーブルがはるかに大きく複雑なテーブルとして再構築されます。私の問題は、WPF がテーブルを正しく更新するように変更通知を提供する方法です。

それは非常に明白なことのように思えますが、何かが欠けているのか、それとも監視可能なディクショナリ構造または変更通知を伴うカスタマイズされた DataTable ラッパーを本当に使用する必要があるのか​​ 疑問に思っています。

これまでに試した解決策:

  • を使用し、ObservableCollection< KeyValuePair<string, DataTable>エントリを追加または削除します。これは実際には問題なく機能しますが、テーブルを更新する必要があるときにタブが消えて再表示されるという視覚的に魅力のない効果が発生します。

  • コードビハインドを使用して明らかにハッキングできますが、可能であればこれを避けたいと思います。

ここにXAMLがあります

<TabControl ItemsSource="{Binding StringToDataTableDictionary}" >
  <TabControl.ItemTemplate>
    <DataTemplate>
      <Label Content="{Binding Key}" />
    </DataTemplate>
  </TabControl.ItemTemplate>
  <TabControl.ContentTemplate>
    <DataTemplate>
      <igDP:XamDataGrid DataSource="{Binding Path=Value}"
    </DataTemplate>
  </TabControl.ContentTemplate>
</TabControl>
4

2 に答える 2

0

INotifyCollectionChangedしたがって、結局のところ、 andを実装するクラスが必要ですIEnumerable( ObservableCollection、 または などICollectionView)。もちろん、自分で作成することもできます。主なことは、クラスに両方のインターフェースを実装しCollectionChanged、コレクションが変更されたときに呼び出すことです。

簡単な例:

class MyObservableDictionary<T, U> : INotifyCollectionChanged, IEnumerable
{
    Dictionary<T, U> items = new Dictionary<T,U>();

    public void Add(T key, U value)
    {
        this.items.Add(key, value);

        // Update any listeners
        if (CollectionChanged != null)
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    // This is from implementing INotifyCollectionChanged
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    // This is from implementing IEnumerable
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        // Dump the entire collection into a 'yield return'. C# will automatically
        // build an enumerator class from it.
        foreach (KeyValuePair<T, U> item in items)
            yield return item;
    }
}

ご覧のとおり、項目を追加するときは、それCollectionChangedが null でないことを確認して (つまり、誰かがこのクラスのコレクションの変更を監視している)、それを呼び出します。これにより、監視オブジェクトが を呼び出すように促されますGetEnumerator。関数では、for each を実行し、GetEnumerator各項目を「yield return」します (これにより、C# に列挙子を自動的に構築するように指示されるため、自分で行う必要はありません)。

XAML:

<ListBox ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Label Content="{Binding Key}" FontWeight="Bold"/>
                <Label Content="{Binding Value}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
于 2013-02-06T13:39:52.627 に答える
0

結局、私の問題を解決するコレクション通知メカニズムはありませんでした。これは、WPF が舞台裏で DataTable への参照を保持しており、それが変更通知を提供するために必要な参照であるためだと思います。コレクションからテーブルを削除して再度追加することもできましたが、これにより GUI が非常に遅くなっていました。そこで、変更通知を提供する DataTable ラッパーを作成しました。こちらを参照してください。

public class DataTableWithNotification : INotifyPropertyChanged
{
    private DataTable _theTable = new DataTable();

    public DataTableWithNotification()
    {
    }

    public DataTableWithNotification(DataTable dt)
    {
        _theTable = dt;
    }

    public DataTable Table
    {
        get { return _theTable; }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void ChangeTableAndNotify(DataTable newTable)
    {
        _theTable = newTable;

        OnPropertyChanged("Table");
    }

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}
于 2013-04-17T11:34:15.360 に答える