是否可以将多个资源传递到DataTemplate中? [英] Is it possible to pass multiple resources into a DataTemplate?
问题描述
我想为ListView中的多个列重用DataTemplate。给定两个 XmlDataProvider
,我通过使用第一个中的选定项从第二个中选择值。
如果我在 DataTemplate
中指定其他资源,则此方法有效。但这迫使我复制DataTemplate的代码,而只是交换附加资源。
我想做的是这样:
I want to reuse a DataTemplate for multiple columns in a ListView. Given the two XmlDataProvider
I select values from the second by using the selected item in the first.
This works if I specify the additional resource in the DataTemplate
. But this forces me to duplicate the code of the DataTemplate and just exchange the addtional resource.
What I would like to do is this:
<Window x:Class="LayoutTests.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LayoutTests"
Title="Window2" Height="300" Width="300">
<Window.Resources>
<XmlDataProvider x:Key="XmlDataA" IsInitialLoadEnabled="True">
<x:XData>
<Items xmlns="">
<Item id="1" text="A:1"/>
<Item id="2" text="A:2"/>
<Item id="3" text="A:3"/>
</Items>
</x:XData>
</XmlDataProvider>
<XmlDataProvider x:Key="XmlDataB" IsInitialLoadEnabled="True">
<x:XData>
<Items xmlns="">
<Item id="1" text="B:1"/>
<Item id="2" text="B:2"/>
<Item id="3" text="B:3"/>
</Items>
</x:XData>
</XmlDataProvider>
<local:MultiXmlConverter x:Key="MultiXmlConverter"/>
<local:DatabindingDebugConverter x:Key="DatabindingDebugConverter"/>
<DataTemplate x:Key="Template" >
<TextBlock Text="{Binding Converter={StaticResource MultiXmlConverter}}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Source={StaticResource XmlDataA}, XPath='/Items/Item'}" Background="Transparent">
<ListView.View>
<GridView>
<GridViewColumn CellTemplate="{StaticResource Template}">
<GridViewColumn.DisplayMemberBinding>
<MultiBinding>
<Binding Path="/"/>
<Binding Source="{StaticResource XmlDataB}"/>
</MultiBinding>
</GridViewColumn.DisplayMemberBinding>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
为了完整性(和参考),这里是一个可能的转换器:
For completeness (and reference) here is a possible converter:
public class MultiXmlConverter : IMultiValueConverter
{
public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var element = value[0] as XmlElement;
var dataProvider = value[1] as XmlDataProvider;
XmlNodeList nodes = dataProvider.Document.SelectNodes("/Items/Item/[@id='" + element.Attributes["id"].Value.ToString() + "']");
return nodes[0].Attributes["Text"].Value.ToString();
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
请注意,上述XAML代码将无法正常工作并产生出现以下错误:由于必须指定MultiValueConverter,因此无法设置MultiBinding。。 MultiBinding
只是我想做的事情的占位符。研究没有发现将其他参数传递给 DataTemplate
的可能性-但我无法相信如此有用的东西并未隐藏在某处。
Note that above XAML code will not work and produces the following error: "Cannot set MultiBinding because MultiValueConverter must be specified.". The MultiBinding
is merely a placeholder for the thing I want to do. Research didnt reveal any possibility to pass additional parameters to a DataTemplate
- but I cant believe that something so usefull is not hidden somewhere.
那么,如何将其他资源传递到 DataContext
DataTemplate
?
So how do I pass an additional resource into a DataTemplate
next to the DataContext
?
推荐答案
经过大量调试和讨论,我找到了解决上述问题的方法。
要将其他数据传递到模板,可以将属性附加到层次结构中的父元素。不幸的是,我们可以访问的东西- GridViewColumn
没有显示在视觉树中。为了能够指定正确的资源,我们必须进行一些包装。我将上面的示例修改为完整,因此需要更长的时间:
After a lot of debugging and discussion I found a solution to above problem.
To pass additional data to a template one can attach properties to parent elements in the hierarchy. Unfortunately the thing where we have access - the GridViewColumn
isn't showing up in the visual tree. To be able to specify the right resources, we have to wrap things up a little bit. I modified above example to be complete so this is a little bit longer:
<Window x:Class="LayoutTests.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LayoutTests"
Title="Window2" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<XmlDataProvider x:Key="XmlDataA" IsInitialLoadEnabled="True">
<x:XData>
<Items xmlns="">
<Item id="1" text="A:1"/>
<Item id="2" text="A:2"/>
<Item id="3" text="A:3"/>
</Items>
</x:XData>
</XmlDataProvider>
</ResourceDictionary>
<ResourceDictionary>
<XmlDataProvider x:Key="XmlDataB" IsInitialLoadEnabled="True">
<x:XData>
<Items xmlns="">
<Item id="1" text="B:1"/>
<Item id="2" text="B:2"/>
<Item id="3" text="B:3"/>
</Items>
</x:XData>
</XmlDataProvider>
</ResourceDictionary>
<ResourceDictionary>
<local:MultiXmlConverter x:Key="MultiXmlConverter"/>
<local:DatabindingDebugConverter x:Key="DatabindingDebugConverter"/>
<DataTemplate x:Key="Template" >
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiXmlConverter}">
<Binding/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="(local:Window2.AttachedXmlDataProvider)"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
<DataTemplate x:Key="TemplateA">
<ContentPresenter ContentTemplate="{StaticResource Template}" local:Window2.AttachedXmlDataProvider="{StaticResource XmlDataA}"/>
</DataTemplate>
<DataTemplate x:Key="TemplateB">
<ContentPresenter ContentTemplate="{StaticResource Template}" local:Window2.AttachedXmlDataProvider="{StaticResource XmlDataB}"/>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Source={StaticResource XmlDataA}, XPath='/Items/Item'}" Background="Transparent">
<ListView.View>
<GridView>
<GridViewColumn CellTemplate="{StaticResource TemplateA}"/>
<GridViewColumn CellTemplate="{StaticResource TemplateB}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
.cs文件中的内容:
And the stuff from the .cs file:
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
public static readonly DependencyProperty AttachedXmlDataProviderProperty =
DependencyProperty.RegisterAttached("AttachedXmlDataProvider",
typeof(XmlDataProvider),
typeof(Window2),
new FrameworkPropertyMetadata((XmlDataProvider)null, FrameworkPropertyMetadataOptions.AffectsRender));
public static void SetAttachedXmlDataProvider(DependencyObject depObj, XmlDataProvider value)
{
depObj.SetValue(AttachedXmlDataProviderProperty, value);
}
public static XmlDataProvider GetAttachedXmlDataProvider(DependencyObject depObj)
{
return (XmlDataProvider)depObj.GetValue(AttachedXmlDataProviderProperty);
}
}
public class MultiXmlConverter : IMultiValueConverter
{
public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var element = value[0] as XmlElement;
var dataProvider = value[1] as XmlDataProvider;
string id = element.Attributes["id"].Value.ToString();
if( dataProvider.Document == null )
return null;
XmlNodeList nodes = dataProvider.Document.SelectNodes("/Items/Item[@id='" + id + "']");
string result = nodes[0].Attributes["text"].Value;
return result;
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}
}
上面代码的优点在于我们将不同的资源集成到 DataTemplate
中,并且仅需少量代码即可交换资源。即在编写 DataTemplate
来简单包装真实模板的过程中。
从上面的示例中可能并不明显,但是如果您有一个复杂的 DataTemplate
,并且只需要更改正在处理的资源,那么这是一个非常好的解决方案
The beauty of the code above lies in the fact that we integrate different resources in a DataTemplate
and can exchange the resource with only a small amount of code. Namely in writing a DataTemplate
that simply wraps up the real template.
It may not be obvious from above example, but if you have a real complicate DataTemplate
and need to just change the resources it's working on this is a really nice solution.
这篇关于是否可以将多个资源传递到DataTemplate中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!