Могу ли я указать универсальный тип в XAML (pre.NET 4 рамки)?
в XAML я могу объявить DataTemplate, чтобы шаблон использовался всякий раз, когда отображается определенный тип. Например, этот DataTemplate будет использовать текстовый блок для отображения имени клиента:
<DataTemplate DataType="{x:Type my:Customer}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
Мне интересно, можно ли определить DataTemplate, который будет использоваться в любое время, когда отображается IList. Поэтому, если содержимое ContentControl является, скажем, ObservableCollection, он будет использовать этот шаблон.
можно ли объявить универсальный тип, например IList в XAML, используя расширение разметки {x:Type}?
6 ответов:
не из коробки, нет; но есть предприимчивые разработчики там, которые сделали это.
Майк Хиллберг в Microsoft играл с ним в этот пост, например. У Google есть и другие, конечно.
не непосредственно в XAML, однако вы можете ссылаться на
DataTemplateSelector
из XAML, чтобы выбрать правильный шаблон.public class CustomerTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { DataTemplate template = null; if (item != null) { FrameworkElement element = container as FrameworkElement; if (element != null) { string templateName = item is ObservableCollection<MyCustomer> ? "MyCustomerTemplate" : "YourCustomerTemplate"; template = element.FindResource(templateName) as DataTemplate; } } return template; } } public class MyCustomer { public string CustomerName { get; set; } } public class YourCustomer { public string CustomerName { get; set; } }
словарь ресурсов:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" > <DataTemplate x:Key="MyCustomerTemplate"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="150"/> </Grid.RowDefinitions> <TextBlock Text="My Customer Template"/> <ListBox ItemsSource="{Binding}" DisplayMemberPath="CustomerName" Grid.Row="1"/> </Grid> </DataTemplate> <DataTemplate x:Key="YourCustomerTemplate"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="150"/> </Grid.RowDefinitions> <TextBlock Text="Your Customer Template"/> <ListBox ItemsSource="{Binding}" DisplayMemberPath="CustomerName" Grid.Row="1"/> </Grid> </DataTemplate> </ResourceDictionary>
окно XAML:
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" xmlns:local="clr-namespace:WpfApplication1" > <Grid> <Grid.Resources> <local:CustomerTemplateSelector x:Key="templateSelector"/> </Grid.Resources> <ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource templateSelector}" /> </Grid> </Window>
окне кода:
public partial class Window1 { public Window1() { InitializeComponent(); ObservableCollection<MyCustomer> myCustomers = new ObservableCollection<MyCustomer>() { new MyCustomer(){CustomerName="Paul"}, new MyCustomer(){CustomerName="John"}, new MyCustomer(){CustomerName="Mary"} }; ObservableCollection<YourCustomer> yourCustomers = new ObservableCollection<YourCustomer>() { new YourCustomer(){CustomerName="Peter"}, new YourCustomer(){CustomerName="Chris"}, new YourCustomer(){CustomerName="Jan"} }; //DataContext = myCustomers; DataContext = yourCustomers; } }
вы также можете обернуть свой универсальный класс в производный класс, который указывает T
public class StringList : List<String>{}
и использовать StringList из XAML.
aelij (координатор проекта для WPF Contrib) есть еще один путь сделать это.
Что еще круче (хотя это когда-нибудь в будущем) ... это то, что XAML 2009 (XAML 2006-это текущая версия) будет поддерживать Это изначально. Проверьте это PDC 2008 сессия для получения информации о ней и многое другое.
Я считаю, что в resent версии .net framework Это можно сделать.
Регистрация дженерики в документации XAML. Вам нужно будет использовать
x:TypeArguments
; есть некоторые ограничения, поэтому сначала прочитайте documentaion.Смотрите также Как указать аргумент универсального типа в XAML вопрос по Stackoverflow
вполне побеждает цель универсального, но вы можете определить класс, производный от универсального, как так, с единственной целью иметь возможность использовать этот тип в XAML.
public class MyType : List<int> { }
и использовать его в XAML, например, как
<DataTemplate DataType={x:Type myNamespace:MyType}>