2012-04-18 31 views
0

我想爲ListView中的多個列重用DataTemplate。給定兩個XmlDataProvider我從第一個選擇的項目中選擇第二個值。 如果我在DataTemplate中指定了附加資源,這將起作用。但是這迫使我複製DataTemplate的代碼並交換addtional資源。是否有可能將多個資源傳遞到DataTemplate中?

<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> 

爲了完整(和參考)這裏是一個可能的轉換:

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 - 但我不相信有用的東西不會隱藏在某個地方。

那麼如何將附加資源傳遞到DataContext旁邊的DataTemplate

+0

以某種方式相關的問題是http://stackoverflow.com/questions/8328443/generic-datatemplate-used-in-multiple-gridviewcolumns – Pascal 2012-04-18 13:41:45

回答

0

經過大量的調試和討論後,我找到了解決上述問題的方法。 要將附加數據傳遞給模板,可以將屬性附加到層次結構中的父元素。不幸的是,我們有權訪問的東西 - GridViewColumn沒有出現在視覺樹中。爲了能夠指定正確的資源,我們必須稍微包裝一下。我修改了上面的例子是完整的,所以這是一個有點長:

<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文件的東西:

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,只需要改變它正在處理的資源,這是一個非常好的解決方案。

相關問題