ContentControl 不会使用 DataTemplates
ContentControl won't use DataTemplates
我有两个模型要表示为目录和文件。这两个模型都实现了一个包含 属性 string Name {get;}
.
的接口
public interface INode
{
string Name { get; }
string Path { get; }
}
public class Directory : INode
{
public Directory(string name, string path)
{
this.Name = name;
this.Path = path;
}
public string Name { get; }
public string Path { get; }
}
public class File : INode
{
public File(string name, string path)
{
this.Name = name;
this.Path = path;
}
public string Name { get; }
public string Path { get; }
}
我创建了两个 DataTemplates
,每个 INode
实现一个。每个模板都有一个 ContentControl
来渲染 Path
,还有一个 TextBlock
来渲染 INode.Name
属性。
<views:NavigationAwarePage
x:Class="OpenTasks.Views.ProviderDirectoryBrowserPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="using:OpenTasks.Views"
xmlns:models="using:OpenTasks.DomainLogic">
<views:NavigationAwarePage.Resources>
<DataTemplate x:Key="FolderIconTemplate">
<Path Data="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
<DataTemplate x:Key="FileIconTemplate">
<Path Data="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,4H6V20H11L18,20V11H11V4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
<DataTemplate x:DataType="models:Directory"
x:Key="DirectoryItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{StaticResource FolderIconTemplate}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:DataType="models:File"
x:Key="FileItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{StaticResource FileIconTemplate}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</views:NavigationAwarePage.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{Binding Path=ContentsOfPath}" />
</Grid>
</views:NavigationAwarePage>
然后我将 ListView
数据绑定到 List<INode>
集合。然而,问题是 ListView
只是呈现 INode
实现的 ToString()
版本,而不是使用 DataTemplate
.
为什么 ListView
不能正确使用我定义的 DataTemplate
之一?我也整理了一个 DataTemplateSelector
,但是 ListView 仍然没有使用我的模板之一。
public class DirectoryListingTemplateSelector : DataTemplateSelector
{
public DataTemplate DirectoryTemplate { get; set; }
public DataTemplate FileTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
if (item is File)
{
return FileTemplate;
}
return DirectoryTemplate;
}
}
<views:NavigationAwarePage.Resources>
<views:DirectoryListingTemplateSelector x:Key="DirectoryListingSelector"
FileTemplate="{StaticResource FileItemTemplate}"
DirectoryTemplate="{StaticResource DirectoryItemTemplate}" />
<ListView ItemsSource="{Binding Path=ContentsOfPath}"
ItemTemplateSelector="{StaticResource DirectoryListingSelector}" />
UWP
应用程序处理 DataTemplate
的方式与 WPF
不同吗?我注意到我无法在不指定键的情况下定义模板,即使我指定了 DataType
。我不确定还有哪些其他差异会导致我出现此问题。这个确切的例子在 WPF 应用程序中对我来说工作得很好,所以这个问题特定于 UWP
。
编辑
我不确定为什么它在我第一次尝试时不起作用,但模板选择器现在可以使用了。我不希望为每个可以支持多个模板的 ContentControl
或 ItemsControl
编写模板选择器。模板选择器是进入 UWP
的唯一途径吗?
<views:NavigationAwarePage
x:Class="OpenTasks.Views.ProviderDirectoryBrowserPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="using:OpenTasks.Views"
xmlns:models="using:OpenTasks.DomainLogic"
xmlns:viewModels="using:OpenTasks.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DataContext="viewModels:ProviderDirectoryBrowserViewModelDesignData">
<views:NavigationAwarePage.Resources>
<views:DirectoryListingTemplateSelector x:Key="DirectoryListingSelector"
FileTemplate="{StaticResource FileItemTemplate}"
DirectoryTemplate="{StaticResource DirectoryItemTemplate}" />
<DataTemplate x:Key="FolderIconTemplate">
<Path Data="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Width="24"
Height="24" />
</DataTemplate>
<DataTemplate x:Key="FileIconTemplate">
<Path Data="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,4H6V20H11L18,20V11H11V4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Width="24"
Height="24" />
</DataTemplate>
<DataTemplate x:DataType="models:Directory"
x:Key="DirectoryItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl ContentTemplate="{StaticResource FolderIconTemplate}"
VerticalAlignment="Center"
Margin="0 0 10 0"/>
<TextBlock Text="{Binding Path=Name}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:DataType="models:File"
x:Key="FileItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl ContentTemplate="{StaticResource FileIconTemplate}"
Margin="0 0 10 0"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding Path=Name}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</views:NavigationAwarePage.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{Binding Path=ContentsOfPath}"
ItemTemplateSelector="{StaticResource DirectoryListingSelector}" />
</Grid>
</views:NavigationAwarePage>
我想说有几种方法可以解决这个问题。对于您的情况,我很想使用自定义转换器并将您的图标模板分配给它。
转换器可能如下所示:
public class FileIconConverter : IValueConverter
{
public DataTemplate FileIconTemplate { get; set; }
public DataTemplate FolderIconTemplate { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is Directory)
{
return this.FolderIconTemplate;
}
if (value is File)
{
return this.FileIconTemplate;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
然后,在页面资源中,创建转换器并分配图标模板:
<local:FileIconConverter x:Key="FileIconConverter">
<local:FileIconConverter.FileIconTemplate>
<DataTemplate>
<Path Data="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,4H6V20H11L18,20V11H11V4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
</local:FileIconConverter.FileIconTemplate>
<local:FileIconConverter.FolderIconTemplate>
<DataTemplate>
<Path Data="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
</local:FileIconConverter.FolderIconTemplate>
</local:FileIconConverter>
最后,在您的列表视图中,绑定您的数据并使用转换器:
<ListView x:Name="ListView">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ContentControl ContentTemplate="{Binding Converter={StaticResource FileIconConverter}}"
Margin="0 0 10 0"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding Path=Name}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我有两个模型要表示为目录和文件。这两个模型都实现了一个包含 属性 string Name {get;}
.
public interface INode
{
string Name { get; }
string Path { get; }
}
public class Directory : INode
{
public Directory(string name, string path)
{
this.Name = name;
this.Path = path;
}
public string Name { get; }
public string Path { get; }
}
public class File : INode
{
public File(string name, string path)
{
this.Name = name;
this.Path = path;
}
public string Name { get; }
public string Path { get; }
}
我创建了两个 DataTemplates
,每个 INode
实现一个。每个模板都有一个 ContentControl
来渲染 Path
,还有一个 TextBlock
来渲染 INode.Name
属性。
<views:NavigationAwarePage
x:Class="OpenTasks.Views.ProviderDirectoryBrowserPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="using:OpenTasks.Views"
xmlns:models="using:OpenTasks.DomainLogic">
<views:NavigationAwarePage.Resources>
<DataTemplate x:Key="FolderIconTemplate">
<Path Data="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
<DataTemplate x:Key="FileIconTemplate">
<Path Data="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,4H6V20H11L18,20V11H11V4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
<DataTemplate x:DataType="models:Directory"
x:Key="DirectoryItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{StaticResource FolderIconTemplate}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
<DataTemplate x:DataType="models:File"
x:Key="FileItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl Content="{StaticResource FileIconTemplate}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</views:NavigationAwarePage.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{Binding Path=ContentsOfPath}" />
</Grid>
</views:NavigationAwarePage>
然后我将 ListView
数据绑定到 List<INode>
集合。然而,问题是 ListView
只是呈现 INode
实现的 ToString()
版本,而不是使用 DataTemplate
.
为什么 ListView
不能正确使用我定义的 DataTemplate
之一?我也整理了一个 DataTemplateSelector
,但是 ListView 仍然没有使用我的模板之一。
public class DirectoryListingTemplateSelector : DataTemplateSelector
{
public DataTemplate DirectoryTemplate { get; set; }
public DataTemplate FileTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
if (item is File)
{
return FileTemplate;
}
return DirectoryTemplate;
}
}
<views:NavigationAwarePage.Resources>
<views:DirectoryListingTemplateSelector x:Key="DirectoryListingSelector"
FileTemplate="{StaticResource FileItemTemplate}"
DirectoryTemplate="{StaticResource DirectoryItemTemplate}" />
<ListView ItemsSource="{Binding Path=ContentsOfPath}"
ItemTemplateSelector="{StaticResource DirectoryListingSelector}" />
UWP
应用程序处理 DataTemplate
的方式与 WPF
不同吗?我注意到我无法在不指定键的情况下定义模板,即使我指定了 DataType
。我不确定还有哪些其他差异会导致我出现此问题。这个确切的例子在 WPF 应用程序中对我来说工作得很好,所以这个问题特定于 UWP
。
编辑
我不确定为什么它在我第一次尝试时不起作用,但模板选择器现在可以使用了。我不希望为每个可以支持多个模板的 ContentControl
或 ItemsControl
编写模板选择器。模板选择器是进入 UWP
的唯一途径吗?
<views:NavigationAwarePage
x:Class="OpenTasks.Views.ProviderDirectoryBrowserPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="using:OpenTasks.Views"
xmlns:models="using:OpenTasks.DomainLogic"
xmlns:viewModels="using:OpenTasks.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DataContext="viewModels:ProviderDirectoryBrowserViewModelDesignData">
<views:NavigationAwarePage.Resources>
<views:DirectoryListingTemplateSelector x:Key="DirectoryListingSelector"
FileTemplate="{StaticResource FileItemTemplate}"
DirectoryTemplate="{StaticResource DirectoryItemTemplate}" />
<DataTemplate x:Key="FolderIconTemplate">
<Path Data="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Width="24"
Height="24" />
</DataTemplate>
<DataTemplate x:Key="FileIconTemplate">
<Path Data="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,4H6V20H11L18,20V11H11V4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Width="24"
Height="24" />
</DataTemplate>
<DataTemplate x:DataType="models:Directory"
x:Key="DirectoryItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl ContentTemplate="{StaticResource FolderIconTemplate}"
VerticalAlignment="Center"
Margin="0 0 10 0"/>
<TextBlock Text="{Binding Path=Name}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:DataType="models:File"
x:Key="FileItemTemplate">
<StackPanel Orientation="Horizontal">
<ContentControl ContentTemplate="{StaticResource FileIconTemplate}"
Margin="0 0 10 0"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding Path=Name}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</views:NavigationAwarePage.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{Binding Path=ContentsOfPath}"
ItemTemplateSelector="{StaticResource DirectoryListingSelector}" />
</Grid>
</views:NavigationAwarePage>
我想说有几种方法可以解决这个问题。对于您的情况,我很想使用自定义转换器并将您的图标模板分配给它。
转换器可能如下所示:
public class FileIconConverter : IValueConverter
{
public DataTemplate FileIconTemplate { get; set; }
public DataTemplate FolderIconTemplate { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is Directory)
{
return this.FolderIconTemplate;
}
if (value is File)
{
return this.FileIconTemplate;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
然后,在页面资源中,创建转换器并分配图标模板:
<local:FileIconConverter x:Key="FileIconConverter">
<local:FileIconConverter.FileIconTemplate>
<DataTemplate>
<Path Data="M13,9H18.5L13,3.5V9M6,2H14L20,8V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V4C4,2.89 4.89,2 6,2M11,4H6V20H11L18,20V11H11V4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
</local:FileIconConverter.FileIconTemplate>
<local:FileIconConverter.FolderIconTemplate>
<DataTemplate>
<Path Data="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z"
Fill="{StaticResource AppTint}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="96"
Height="96">
<Path.RenderTransform>
<ScaleTransform ScaleX="2" ScaleY="2" />
</Path.RenderTransform>
</Path>
</DataTemplate>
</local:FileIconConverter.FolderIconTemplate>
</local:FileIconConverter>
最后,在您的列表视图中,绑定您的数据并使用转换器:
<ListView x:Name="ListView">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ContentControl ContentTemplate="{Binding Converter={StaticResource FileIconConverter}}"
Margin="0 0 10 0"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding Path=Name}"
VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>