2

`さまざまなタスクの結果を表す項目を含むリストボックスがあります。それぞれが共通の基本クラス「ResultsViewModel」を拡張するため、表示者が必要とする特定の属性を共有します。

リソース ディクショナリで定義したいのは、さまざまなタイプのタスク結果ごとのデータ テンプレートです。たとえば、タスク A には ResultsAViewModel の実装クラスがあり、タスク B には ResultsBViewModel などがあります。これらのそれぞれにデータ テンプレートを定義したいと考えています。サブクラスでは、Listbox の ItemsSource を ObservableCollection (親クラス) にバインドし、WPF のポリモーフィズムを使用して実行時に使用するデータ テンプレートを決定します。複雑なのは、さまざまなトリガーに応じて、結果が処理中か、完了済みか、失敗したかに応じて、各結果タイプに対して選択された 3 つのデータ テンプレートのいずれかになることです。したがって、各派生クラスにはテンプレートがあります。

これまでのところ、以下のようにリストボックスのスタイルに一般的なスタイルを適用しました

<ListBox Background="{StaticResource AppBackground}" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Padding="10" Style="{StaticResource ResultsItemTemplate}" ItemsSource="{Binding Results}" MouseDoubleClick="ListBox_MouseDoubleClick" />

そのスタイルは次のとおりです

    <!-- Region General Results styles -->
<Style TargetType="{x:Type ListBox}" x:Key="ResultsItemTemplate" >
    <Setter Property="Background">
        <Setter.Value>
            Tan
        </Setter.Value>
    </Setter>
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <ContentControl Content="{Binding}">
                    <ContentControl.Style>
                        <Style TargetType="{x:Type ContentControl}">
                            <Setter Property="ContentTemplate" Value="{DynamicResource CalculatingResultsTemplate}"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Path=ProcessingResult}" Value="1">
                                    <Setter Property="ContentTemplate" Value="{DynamicResource ProcessedResultsTemplate}"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Path=ProcessingResult}" Value="-1">
                                    <Setter Property="ContentTemplate" Value="{DynamicResource ErroredResultsTemplate}"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">
                                    <Setter Property="Background" Value="White"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </ContentControl.Style>
                </ContentControl>
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Background" Value="{StaticResource AppBackground}" />
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True" >
                        <Setter Property="Background" Value="{StaticResource AppBackground}" />
                    </Trigger>
                </Style.Triggers>
                <Style.Resources>
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
                    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
                </Style.Resources>
            </Style>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <WrapPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
</Style>

<!-- EndRegion -->

重要なのは、このスタイルがトリガーに応じて ItemTemplate を 3 つの値のいずれかに設定することです。これらのテンプレート キーは

ProcessedResultsTemplate CalculatingResultsTemplate ErroredResultsTemplate

それぞれがリソース ディクショナリのデータ テンプレートです。

私が抱えている問題は、各派生ビューモデル タイプに対して上記の 3 つのデータ テンプレートがそれぞれ 1 つ必要なことです。そして、私はそれらをキーで参照しています。また、辞書に同じキーを持つ 2 つの項目を含めることはできません。たとえば、キー "ProcessedResultsTemplate" を持つ 2 つのデータ テンプレートを作成すると、1 つは DataType が x:Type CalculationResultsViewModel で、もう 1 つは同じキーで DataType が x:Type SpotStressResultsViewModel の場合、両方が同じキーを持つため機能しません。

したがって、ここで WPF ポリモーフィズムの楽しみを得るためにこれを実装する正しい方法が正確にはわかりません。それは私が間違っている基本的なことですか?

更新: datatemplate セレクターを下って、以下のクラスを使用してみました。ロジックは正常に実装されていますが、問題は、オブジェクトが最初にレンダリングされたときにのみ datatemplateselector が呼び出されることです。元の XAML には、特定の依存関係プロパティが変更されたときにデータ テンプレートを変更するトリガーがありました。トリガーまたは依存関係プロパティを使用して、datatemplateselector に新しいデータ値からデータテンプレートを再選択するように依頼するにはどうすればよいですか?

class ResultsDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate CalculateOnlyProcessedTemplate { get; set; }
    public DataTemplate CalculateOnlyCalculatingTemplate { get; set; }
    public DataTemplate CalculateOnlyErroredTemplate { get; set; }

    public DataTemplate SpotStressProcessedTemplate { get; set; }
    public DataTemplate SpotStressCalculatingTemplate { get; set; }
    public DataTemplate SpotStressErroredTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is CalculationResultsViewModel)
        {
            var vm = item as CalculationResultsViewModel;

            if (vm.ProcessingResult == 1)
                return CalculateOnlyProcessedTemplate;

            if (vm.ProcessingResult == -1)
                return CalculateOnlyErroredTemplate;

            return CalculateOnlyCalculatingTemplate;
        }

        if (item is SpotStressResultsViewModel)
        {
            var vm = item as SpotStressResultsViewModel;

            if (vm.ProcessingResult == 1)
                return SpotStressProcessedTemplate;

            if (vm.ProcessingResult == -1)
                return SpotStressErroredTemplate;

            return SpotStressCalculatingTemplate;
        }

        return null;
    }
}
4

1 に答える 1

4

明らかな解決策は、適切なテンプレートを選択するという任意の複雑な決定にDataTemplateSelectorを使用することです。実際のロジックを XAML にシフトすると、問題が発生します。

個人的には、ViewModel は、ビュー、それらの構成のニーズ、およびそれらの相互作用の直接的で、テスト可能で、外見のない表現であるべきだと思います。あなたがデモンストレーションしているViewModelは、ビューを表すのではなく、ビジネスモデルオブジェクトのようです。ViewModel レイヤーは、暗黙の生成を担当する必要があります。

  • ResultsACalculatingViewModel
  • ResultsAProcessingViewModel
  • ResultsAErrorViewModel
  • ResultsBCalculatingViewModel
  • ResultsBProcessingViewModel
  • ResultsBErrorViewModel

そして、あなたのビューコードはそれらをスタイリングするだけです。ポリモーフィズムは、これらの暗黙の ViewModel を簡単に実現するための優れた方法ですが、UI を作成する人にとっては問題ではありません。

于 2013-07-26T16:26:47.983 に答える