この階層構造を表示しようとしています:
public interface IProgressIndicator
{
CancellationToken CancellationToken { get; }
string Name { get; set; }
}
public interface IPercentageProgressIndicator : IProgressIndicator
{
int ProgressPercentage { get; set; }
}
public interface ICountProgressIndicator : IProgressIndicator
{
int ProgressPercentage { get; }
int CurValue { get; set; }
int MaxValue { get; set; }
}
public interface ICompositeProgressIndicator : ICountProgressIndicator
{
ObservableCollection<IProgressIndicator> SubProgressItems { get; }
void MarkAsComplete(IProgressIndicator progress);
IPercentageProgressIndicator CreatePercentageIndicator();
ICountProgressIndicator CreateCountIndicator();
ICompositeProgressIndicator CreateCompositeIndicator();
}
ビューは、階層構造が整っていると想定すべきではありません。つまり、通常の IProgressIndicator を (ContentControl を使用して) 表示し、DataTemplates を使用して他のタイプを表示する必要があります。
したがって、IProgressIndicator が ICompositeProgressIndicator の場合、階層全体のルートは TreeView である必要があり、ルート ツリー ビュー アイテムは情報 (ProgressPercentage や Name など) を表示します。次に、子を IProgressIndicator として再度表示し、DataTemplates を使用してそのデータを表示する適切な方法を選択します。ネストされた ICompositeProgressIndicator オブジェクトは、別のツリー ビュー項目を追加するだけです (TreeView 全体ではありません)。
これが私が思いついたものです。Complex Hierarchical Data Templatesを使用する必要がありました。また、かなり単純なカスタム DataTemplateSelector を使用しています。
public class ProgressIndicatorTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var element = (container as FrameworkElement);
if (item is ICompositeProgressIndicator)
return element.FindResource("CompositeProgressIndicatorTemplate") as DataTemplate;
else if (item is ICountProgressIndicator)
return element.FindResource("CountProgressIndicatorTemplate") as DataTemplate;
else if (item is IPercentageProgressIndicator)
return element.FindResource("PercentageProgressIndicatorTemplate") as DataTemplate;
return null;
}
}
XAML は次のとおりです。
<StackPanel Grid.Row="2" Margin="5" Orientation="Vertical">
<StackPanel.Resources>
<editorUtil:ProgressIndicatorTemplateSelector x:Key="progressIndicatorTemplateSelector" />
<Converters:ObjectToTypeConverter x:Key="objectTypeConverter" />
<DataTemplate x:Key="CompositeProgressIndicatorTemplateBase">
<StackPanel Orientation="Vertical">
<TextBlock Text="CompositeProgressIndicatorTemplateBase" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding SubProgressItems.Count}" />
<TextBlock Text="{Binding Converter={StaticResource objectTypeConverter}}" Margin="5" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="CompositeProgressIndicatorTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical">
<TextBlock Text="CompositeProgressIndicatorTemplateBase" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding SubProgressItems.Count}" />
<TextBlock Text="{Binding Converter={StaticResource objectTypeConverter}}" Margin="5" />
</StackPanel>
<TreeView Grid.Row="1" DataContext="{Binding}">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="true"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeViewItem ItemsSource="{Binding SubProgressItems}" DataContext="{Binding}"
ItemTemplateSelector="{StaticResource progressIndicatorTemplateSelector}" IsExpanded="True">
<TreeViewItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<StackPanel.DataContext>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type coreUtil:ICompositeProgressIndicator}}"
Path="."/>
</StackPanel.DataContext>
<TextBlock Text="CompositeProgressIndicatorTemplate" />
<ContentControl ContentTemplate="{StaticResource CompositeProgressIndicatorTemplateBase}">
<ContentControl.DataContext>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type coreUtil:ICompositeProgressIndicator}}"
Path="."/>
</ContentControl.DataContext>
</ContentControl>
</StackPanel>
</DataTemplate>
</TreeViewItem.HeaderTemplate>
</TreeViewItem>
</TreeView>
</Grid>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type coreUtil:ICompositeProgressIndicator}" ItemsSource="{Binding Path=SubProgressItems}">
<ContentControl ContentTemplate="{StaticResource CompositeProgressIndicatorTemplateBase}" />
</HierarchicalDataTemplate>
<DataTemplate x:Key="CountProgressIndicatorTemplate" DataType="{x:Type coreUtil:ICountProgressIndicator}">
<Grid>
<ProgressBar Height="20" Value="{Binding ProgressPercentage, Mode=OneWay}" />
<TextBlock Margin="5" HorizontalAlignment="Center" Text="{Binding ProgressPercentage, Converter={StaticResource percentageConverter}, StringFormat=P}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="PercentageProgressIndicatorTemplate" DataType="{x:Type coreUtil:IPercentageProgressIndicator}">
<Grid>
<ProgressBar Height="20" Value="{Binding ProgressPercentage, Mode=OneWay}" />
<TextBlock Margin="5" HorizontalAlignment="Center" Text="{Binding ProgressPercentage, Converter={StaticResource percentageConverter}, StringFormat=P}" />
</Grid>
</DataTemplate>
</StackPanel.Resources>
<ContentControl Content="{Binding ProgressIndicator}" ContentTemplateSelector="{StaticResource progressIndicatorTemplateSelector}">
</ContentControl>
</StackPanel>
現時点での様子は次のとおりです。
ルート ツリー ビュー アイテムの DataContext がありません。