1

これは私の簡略化された XAML です。

<Window x:Class="MyForm.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyForm"
        Title="MyForm" Closing="Window_Closing" Icon="Images\main.ico" Height="633" Width="1602" Loaded="Window_Loaded" xmlns:my="clr-namespace:MyForm">
    <Window.Resources>
        <ObjectDataProvider x:Key="dataSetProvider" MethodName="CreateDataSet" ObjectType="{x:Type local:DataSetCreator}" />
        <DataTemplate x:Key="ItemTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding item_title}">
                </TextBlock>
            </StackPanel>
        </DataTemplate>
        <HierarchicalDataTemplate x:Key="FeedTemplate" ItemsSource="{Binding FK_FM_FEEDS_FEED_0_0}" ItemTemplate="{StaticResource ItemTemplate}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding feed_title}">
                </TextBlock>
            </StackPanel>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid>
        <TreeView LayoutUpdated="treeViewMain_LayoutUpdated" TreeViewItem.Expanded="TextBlock_Expanded" Name="treeViewMain" DataContext="{StaticResource dataSetProvider}" ItemsSource="{Binding FM_FEEDS_FEEDS}" ItemTemplate="{StaticResource FeedTemplate}">
        </TreeView>
    </Grid>
</Window>

バインドは期待どおりに機能し、データセットの親テーブルの feed_title がツリービューの最上位ノードにバインドされます。次に、その特定のフィード (データセットの子テーブル) 内のすべての項目が、子ノードとしてツリービューの最上位ノードにバインドされます。

私が達成しようとしていること: feed_title だけでなく、トップ ノードにさらに情報を追加したいと思います。どのアイテムが同期されているかどうかを子テーブルから読み取り、最上位ノードを更新して、「(4/10) タイトル」のようなテキストを含めたいと思います。そのため、10 個のアイテムのうち 4 個だけが同期されていることがユーザーに通知されます。解決策は必要ありませんが、これについてどうすればよいか知りたいです...

4

3 に答える 3

2

@mikehc によって提案されたアプローチがどのように機能するかを説明するために、次の実際のコード サンプルを見てください。

FeedViewModel.cs - 子の同期ステータスからの情報を使用して、タイトルの定期的な更新 (このコードで 1 秒、または好きな/必要なもの) にタイマーを使用していることに注意してください。これは、各子からのイベントをサブスクライブして、同期されるときに通知を受けたり、新しい子アイテムの追加や古い子アイテムの削除などを処理したりするよりも、はるかに簡単なソリューションです。

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Threading;

namespace WpfApplication11
{
    public class FeedViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate {};

        DispatcherTimer timer =
                        new DispatcherTimer(DispatcherPriority.Background);

        private string feedName;

        public string FeedName
        {
            get { return feedName; }
            set
            {
                feedName = value;
                PropertyChanged(this,
                                    new PropertyChangedEventArgs("FeedName"));
                PropertyChanged(this,
                                    new PropertyChangedEventArgs("FeedTitle"));
            }
        }

        public ObservableCollection<ItemViewModel> FeedItems { get; set; }

        public string FeedTitle
        {
            get
            {
                return string.Format("({0}/{1}) {2}",
                        FeedItems.Count(item => item.IsSynchronized),
                        FeedItems.Count,
                        FeedName);
            }
        }

        public FeedViewModel()
        {
            FeedItems = new ObservableCollection<ItemViewModel>();

            timer.Interval = TimeSpan.FromMilliseconds(1000);
            timer.Tick += (sender, args) =>
                    PropertyChanged(this,
                                   new PropertyChangedEventArgs("FeedTitle"));
            timer.Start();
        }
    }
}

ItemViewModel.cs :

using System.ComponentModel;

namespace WpfApplication11
{
    public class ItemViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate {};

        private string itemName;
        private bool isSynchronized;

        public string ItemName
        {
            get { return itemName; }
            set
            {
                itemName = value;
                PropertyChanged(this, new PropertyChangedEventArgs("ItemName"));
            }
        }

        public bool IsSynchronized
        {
            get { return isSynchronized; }
            set
            {
                isSynchronized = value;
                PropertyChanged(this,
                                new PropertyChangedEventArgs("IsSynchronized"));
            }
        }
    }
}

DataSetCreator.cs - これは、コードで言及したクラスのDataSetDataSetCreatorの 2 つのモックに過ぎないため、独自のものを自由に使用してください):

using System.Collections.ObjectModel;

namespace WpfApplication11
{
    public class DataSet
    {
        public ObservableCollection<FeedViewModel> Feeds { get; private set; }

        public DataSet()
        {
            Feeds = new ObservableCollection<FeedViewModel>
            {
                new FeedViewModel
                {
                    FeedName = "Feed #1",
                    FeedItems = new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel
                        {
                            ItemName = "Item #1.1",
                            IsSynchronized = true
                        },
                        new ItemViewModel
                        {
                            ItemName = "Item #1.2",
                            IsSynchronized = true
                        },
                        new ItemViewModel
                        {
                            ItemName = "Item #1.3",
                            IsSynchronized = false
                        },
                    }
                },
                new FeedViewModel
                {
                    FeedName = "Feed #2",
                    FeedItems = new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel
                        {
                            ItemName = "Item #2.1",
                            IsSynchronized = true
                        },
                        new ItemViewModel
                        {
                            ItemName = "Item #2.2",
                            IsSynchronized = true
                        },
                    }
                },
                new FeedViewModel
                {
                    FeedName = "Feed #3",
                    FeedItems = new ObservableCollection<ItemViewModel>
                    {
                        new ItemViewModel
                        {
                            ItemName = "Item #3.1",
                            IsSynchronized = false
                        },
                        new ItemViewModel
                        {
                            ItemName = "Item #3.2",
                            IsSynchronized = false
                        },
                    }
                }
            };
        }
    }

    public class DataSetCreator
    {
        public DataSet CreateDataSet()
        {
            return new DataSet();
        }
    }
}

最後に、MainWindow.xaml -上記のモック クラスDataSetCreator.csを使用するように更新します。

<Window x:Class="WpfApplication11.MainWindow"
        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:local="clr-namespace:WpfApplication11"
        mc:Ignorable="d" Title="MainWindow" Height="350" Width="525">
    <Window.Resources>

        <local:ItemViewModel x:Key="DesignItemViewModel" />
        <local:FeedViewModel x:Key="DesignFeedViewModel" />

        <ObjectDataProvider x:Key="dataSetProvider"
                            ObjectType="{x:Type local:DataSetCreator}"
                            MethodName="CreateDataSet" />

        <DataTemplate x:Key="ItemTemplate">
            <StackPanel Orientation="Horizontal"
                        d:DataContext="{StaticResource DesignItemViewModel}">
                <TextBlock Text="{Binding Path=ItemName}" />
                <CheckBox IsChecked="{Binding Path=IsSynchronized}" 
                                    Margin="25,0,0,0"
                          Content=" is synchronized?"/>
            </StackPanel>
        </DataTemplate>

        <HierarchicalDataTemplate x:Key="FeedTemplate"
                                  ItemsSource="{Binding Path=FeedItems}"
                                  ItemTemplate="{StaticResource ItemTemplate}">

            <StackPanel Orientation="Horizontal"
                        d:DataContext="{StaticResource DesignFeedViewModel}">
                <TextBlock Text="{Binding Path=FeedTitle}" />
            </StackPanel>

        </HierarchicalDataTemplate>

    </Window.Resources>

    <Grid>
        <TreeView DataContext="{StaticResource dataSetProvider}"
                  d:DataContext="{StaticResource dataSetProvider}"
                  ItemsSource="{Binding Path=Feeds}"
                  ItemTemplate="{StaticResource FeedTemplate}" />
    </Grid>

</Window>
于 2013-06-19T13:47:19.697 に答える
1

子と親の間のこれらの複雑な関係を処理するために、カスタム モデルまたはビューモデルを構築することをお勧めします。例えば:

  1. Parent と Child という名前の 2 つのクラスを作成します。
  2. 各クラスには、対応するデータセットを保持するためのプロパティがあります。
  3. 親は子のコレクションを持っています。
  4. INotifyPropertyChanged親がイベントをサブスクライブし、子がいつ読まれたかを知ることができるように子を実装しPropertyChangedます (そしてそれを追跡します)。

最後に、データセットではなく、クラス プロパティにバインドします。INotifyPropertyChangedバインドまたは使用するプロパティに実装することを忘れないでくださいDependencyProperties

ここに実装に関するいくつかのトリックがありますINotifyPropertyChanged

于 2013-06-15T23:17:06.747 に答える
0

モデルまたはビューモデルレイヤーには、そのステータスを示す「IsSynchronized」などのプロパティがあると思います。その条件である場合は、バインディングでコンバーター (おそらく IValueConverter から継承) を使用することをお勧めします。コンバーターの実装では、すべての子の同期ステータスを取得し、計算された数を UI 要素に返すことができます。

確かに、INotifyPropertyChanged インターフェイスを実装する必要があります。

于 2013-06-17T09:04:47.927 に答える