Я прочитал почти тысячу постов, объясняющих, что установка закрытого универсального типа как DataType
на DataTemplate
не работает, потому что WPF не будет поддерживать это. Но на самом деле это просто неправильно.
Я могу определить следующее DataTemplate
в моем Window.Resources
, и оно будет использовано при назначении списка строк для элемента управления контентом. Например:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Generic="clr-namespace:System.Collections.Generic;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate DataType="{x:Type TypeName=Generic:List`1[System.String]}">
<TextBlock Text="Hi List of Strings"
FontSize="40"
Foreground="Cyan"/>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl x:Name="_contentControl">
</ContentControl>
</Grid>
</Window>
и в коде позади:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_contentControl.Content = new List<string> { "Huhu" };
}
}
При этой настройке вы увидите «Привет список строк». Для меня это доказательство того, что я могу определить универсальные типы как DataType
. Но я хочу сделать еще один шаг вперед: я бы хотел определить Dictionary<string, string>
как DataType
. Но, к сожалению, я не могу заставить его работать.
Итак, вопрос : Как я могу определить Dictionary<string, string>
как DataType
из DataTemplate
?
Если вы знаете ответ, вы можете перестать читать. Но поскольку хорошей практикой является показать, что я уже сделал, я продолжаю писать.
Что я уже сделал?
Сначала я пошел грубой силой и попробовал несколько комбинаций, подобных:
- DataType="{x:Type TypeName=Generic:Dictionary`2[System.String];[System.String]}"
- DataType="{x:Type TypeName=Generic:Dictionary`2[System.String],[System.String]}"
- DataType="{x:Type TypeName=Generic:Dictionary`2[System.String,System.String]}"
Но так как ни один из них не работал, я углубился в System.Xaml
и посмотрел на TypeExtension
, GenericTypeNameParser
и GenericTypeNameScanner
, потому что я думал, что это кодовые строки, которые разрешают тип. Но, глядя на код, я понял, что `это недопустимый символ.
Чтобы доказать это, я написал свой MarkupExtension
public class UseTheTypeExtensionsParser : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
var a = new TypeExtension("Generic:List`1[[System.String]]");
var type = a.ProvideValue(serviceProvider);
return type.ToString();
}
}
и использовал его следующим образом:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Generic="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:WpfApp1="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ContentControl Content="{WpfApp1:UseTheTypeExtensionsParser}"/>
</Grid>
</Window>
И это породило исключение, что символ `не ожидался и что тип xaml недействителен.
Это заставило меня задуматься, почему мой первый пример сработал. Я думаю, что при компиляции разметки xaml для wpf это не TypeExtension
, который используется для разрешения XamlType, но я думаю, что используется XamlNamespace
. Потому что у этого класса есть MangleGenericTypeName
-метод, который использует `-характер.
Но я все еще не вижу код, который извлекает аргументы типа, поэтому я не вижу правильный синтаксис для указания аргументов типа для словаря. Вот где я застрял.
(Само собой разумеется, что Microsoft-Docs бесполезны в этой теме.)
Редактировать : Поскольку кажется неясным, почему я этого хочу, я объясню это: я хочу автоматический выбор ContentTemplate ContentControl. И конечно: мой построенный DataTemplate
в примере очень прост. Но каждый должен представить, что мне нужны разные шаблоны данных для списков, словарей или простых строк.
У меня есть ViewModel, которая имеет свойство public object Result { get; }
. И иногда, результатом является int, иногда строка, иногда List и так далее, и так далее. Я связываю это Result
-свойство с Content
-Свойством ContentControl
. И для всех упомянутых типов я написал разные шаблоны данных, которые автоматически выбираются WPF. Таким образом, int
s показаны в Rectangle
, а String
s показаны в Ellipse
.
.
После того, как я все это заработал, я хочу другой DataTemplate, но на этот раз для словаря.