Pergunta

Eu tenho dois HeaderedContentControls como aqueles abaixo que cada um tem sua propriedade de conteúdo vinculado a um dos dois imóveis vista modelo do mesmo tipo base (um controle está no lado esquerdo da janela e um à direita, portanto, o modelo de vista nomes de propriedades).

No entanto, a vista de modelo de propriedade pode ser um dos quatro tipos derivados diferentes. Assim, a esquerda pode ser uma Airplane eo direito pode ser um Car. Então, mais tarde, à esquerda pode ser um Boat e direita pode ser uma Airplane. Eu gostaria que a propriedade Style dos controles de cabeçalho para ser dinâmico com base no tipo derivado. Qual é a melhor maneira de fazer isso de forma declarativa?

<Window...>
    <StackPanel 
        Grid.Row="2"
        Orientation="Horizontal" VerticalAlignment="Top">
        <Border 
            Height="380" 
            Width="330"
            Margin="0,0,4,0"
            Style="{StaticResource MainBorderStyle}">
            <HeaderedContentControl
                Content="{Binding Path=LeftChild}"
                Header="{Binding LeftChild.DisplayName}"
                Style="{StaticResource StandardHeaderStyle}"
            />
        </Border>

        <Border 
            Height="380" 
            Width="330"
            Style="{StaticResource MainBorderStyle}">
            <HeaderedContentControl
                Content="{Binding Path=RightChild}"
                Header="{Binding RightChild.DisplayName}"
                Style="{StaticResource StandardHeaderStyle}"
            />  
        </Border>
    </StackPanel>
</Window>


<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:myViewModelNamespace;assembly=myViewModelAssembly"
    xmlns:vw="clr-namespace:myViewNamespace" >

    <!--***** Item Data Templates ****-->
    <DataTemplate DataType="{x:Type vm:CarViewModel}">
        <vw:CarView />
    </DataTemplate>

    <DataTemplate DataType="{x:Type vm:BoatViewModel}">
        <vw:BoatView />
    </DataTemplate>

    <DataTemplate DataType="{x:Type vm:AirplaneViewModel}">
        <vw:AirplaneView />
    </DataTemplate>

    <!--***** 
        Other stuff including the StandardHeaderStyle and the MainBorderStyle
    ****-->

</ResourceDictionary>
Foi útil?

Solução

A minha resposta é uma elaboração sobre Archimed de. Não hesite em pedir mais!

<Window x:Class="Datatemplate_selector.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:Datatemplate_selector">
<Window.Resources>
    <DataTemplate DataType="{x:Type local:CarDetail}">
     <Border BorderBrush="Yellow" BorderThickness="2">
        <HeaderedContentControl Margin="4" Foreground="Red">
            <HeaderedContentControl.Header>
                <Border BorderBrush="Aquamarine" BorderThickness="3">
                    <TextBlock Text="{Binding Name}"/>
                </Border>
             </HeaderedContentControl.Header>
            <HeaderedContentControl.Content>
                <Border BorderBrush="CadetBlue" BorderThickness="1">
                    <TextBlock TextWrapping="Wrap" Text="{Binding Description}"/>
                </Border>
            </HeaderedContentControl.Content>
        </HeaderedContentControl>
       </Border>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:HouseDetail}">
        <HeaderedContentControl Margin="4" Foreground="Yellow" FontSize="20"
                    Header="{Binding Name}">
            <HeaderedContentControl.Content>
                <TextBlock Foreground="BurlyWood"  TextWrapping="Wrap"
                           Text="{Binding Description}"/>
            </HeaderedContentControl.Content>
        </HeaderedContentControl>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:ItemDetail}">
        <HeaderedContentControl Margin="4" Foreground="Green" FontStyle="Italic" 
                    Content="{Binding Description}"
                    Header="{Binding Name}">
        </HeaderedContentControl>
    </DataTemplate>
</Window.Resources>
<StackPanel>
    <ItemsControl ItemsSource="{Binding ItemDetails}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Columns="2"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</StackPanel>

using System.Collections.ObjectModel;
using System.Windows;

namespace Datatemplate_selector
{
   public partial class Window1 : Window
    {
        public ObservableCollection<ItemDetail> ItemDetails { get; set; }

        public Window1()
        {
            ItemDetails = new ObservableCollection<ItemDetail>
                              {
                                  new CarDetail{Name="Trabant"},
                                  new HouseDetail{Name="Taj Mahal"}
                              };
            DataContext = this;
            InitializeComponent();
        }
    }

    public class ItemDetail:DependencyObject
    {
        public string Name
        {
            get { return (string)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }

        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Name",
            typeof(string),
            typeof(ItemDetail),
            new UIPropertyMetadata(string.Empty));

        public virtual string Description
        {
             get { return Name + " has a lot of details"; }
        }
    }

    public class CarDetail:ItemDetail
    {
        public override string Description
        {
            get { return string.Format("The car {0} has two doors and a max speed of 90 kms/hr", Name); }
        }
    }

    public class HouseDetail:ItemDetail
    {
        public override string Description
        {
            get { return string.Format("The house {0} has two doors and a backyard", Name); }
        }
    }
}

PS: Eu pensei que este uso de herança em uma coleção genérica não foi apoiado em .Net 3. Estou agradavelmente surpreendido que este código funciona

Outras dicas

Você tem certeza que precisa variar Estilo de HeaderedContentControl, não o baseando ContentTemplate do tipo de dinâmica de conteúdo? Em outras palavras: você precisa para variar o estilo do controle ou você só precisa variar de dados de modelo do item

?

Porque há muito útil propriedade ContentTemplateSelector e se você vai escrever classe muito simples que você vai ser capaz de selecionar o baseando DataTemplate no tipo de dinâmica de conteúdo.

Se isso não é o caso e você tem certeza de que você precisa para variar o estilo, então você poderia por favor elaborar um pouco quais partes do estilo que você gostaria de variar - talvez haja uma solução alternativa através do mesmo ContentTemplateSelector está disponível <. / p>

No caso de você insistir em variar os estilos, pensar um pouco sobre o uso de gatilho dados dentro de seu estilo - usando um conversor muito simples, você será capaz de variar certas propriedades (ou todos eles, se você preferir) de seu estilo.

eu vou ser feliz para lhe fornecer mais assistência assim que vou elaborar as especificidades do seu problema.

UPD : OK, autor insiste que ele precisa para variar o estilo. Aqui estão duas maneiras possíveis de como você pode fazer isso.

Antes de solução simples, mas severamente um limitado: uma vez que o seu conteúdo Header pode ser especificado por meio de conteúdo Content você pode fazer isso:

<DataTemplate x:Key="DefaultTemplate">
    <HeaderedContentControl Content="{Binding}"
                            Header="{Binding DisplayName}"
                            Style="{StaticResource DefaultStyle}" />
</DataTemplate>
<DataTemplate x:Key="CarTemplate"
              DataType="dm:Car">
    <HeaderedContentControl Content="{Binding}"
                            Header="{Binding DisplayName}"
                            Style="{StaticResource CarStyle}" />
</DataTemplate>
<DataTemplate x:Key="BoatTemplate"
              DataType="dm:Boat">
    <HeaderedContentControl Content="{Binding}"
                            Header="{Binding DisplayName}"
                            Style="{StaticResource BoatStyle}" />
</DataTemplate>

<u:TypeBasedDataTemplateSelector x:Key="MySelector"
                                 DefaultTemplate="{StaticResource DefaultTemplate}"
                                 NullTemplate="{StaticResource DefaultTemplate}">
    <u:TypeMapping Type="dm:Car" Template="{StaticResource CarTemplate}" />
    <u:TypeMapping Type="dm:Boat" Template="{StaticResource BoatTemplate}" />
</u:TypeBasedDataTemplateSelector>

<ContentPresenter Content="{Binding LeftChild}"
                  ContentTemplateSelector="{StaticResource MySelector}" />

O único código que você precisa para fazer esta solução puramente declarativa é uma implementação seletor de modelo muito simples. Aqui vai:

public class TypeMapping
{
    public Type Type { get; set; }
    public DataTemplate Template { get; set; }
}

public class TypeBasedDataTemplateSelector : DataTemplateSelector, IAddChild
{
    public DataTemplate DefaultTemplate { get; set; }
    public DataTemplate NullTemplate { get; set; }
    private readonly Dictionary<Type, DataTemplate> Mapping = new Dictionary<Type, DataTemplate>();

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item == null)
            return NullTemplate;

        DataTemplate template;

        if (!Mapping.TryGetValue(item.GetType(), out template))
            template = DefaultTemplate;

        return template;
    }


    #region IAddChild Members

    public void AddChild(object value)
    {
        if (!(value is TypeMapping))
            throw new Exception("...");

        var tm = (TypeMapping)value;

        Mapping.Add(tm.Type, tm.Template);
    }

    public void AddText(string text)
    {
        throw new NotImplementedException();
    }

    #endregion
}

A segunda solução é mais genérico e pode ser aplicada aos casos em que o conteúdo Header não tem nada a ver com o conteúdo Content. Ele baseia nas capacidades do conversor da ligação.

<Style x:Key="StandardHeaderedStyle">
    <!--...-->
</Style>

<Style x:Key="CarHeaderedStyle"
       BasedOn="{StaticResource StandardHeaderedStyle}">
    <!--...-->
</Style>

<Style x:Key="BoatHeaderedStyle"
       BasedOn="{StaticResource StandardHeaderedStyle}">
    <!--...-->
</Style>

<Style x:Key="UnknownHeaderedStyle"
       BasedOn="{StaticResource StandardHeaderedStyle}">
    <!--...-->
</Style>

<u:StylesMap x:Key="MyStylesMap" 
             FallbackStyle="{StaticResource UnknownHeaderedStyle}">
    <u:StyleMapping Type="Car" Style="{StaticResource CarHeaderedStyle}" />
    <u:StyleMapping Type="Boat" Style="{StaticResource BoatHeaderedStyle}" />
</u:StylesMap>

<u:StyleSelectorConverter x:Key="StyleSelectorConverter" />

<HeaderedContentControl Content="{Binding LeftChild}"
                        Header="{Binding LeftChild.DisplayName}">
    <HeaderedContentControl.Style>
        <Binding Path="LeftChild"
                 Converter="{StaticResource StyleSelectorConverter}"
                 ConverterParameter="{StaticResource MyStylesMap}" />
    </HeaderedContentControl.Style>
</HeaderedContentControl>

Ele também requer algumas das código de apoio:

public class StyleMapping
{
    public Type Type { get; set; }
    public Style Style { get; set; }
}

public class StylesMap : Dictionary<Type, Style>, IAddChild
{
    public Style FallbackStyle { get; set; }

    #region IAddChild Members

    public void AddChild(object value)
    {
        if (!(value is StyleMapping))
            throw new InvalidOperationException("...");

        var m = (StyleMapping)value;

        this.Add(m.Type, m.Style);
    }

    public void AddText(string text)
    {
        throw new NotImplementedException();
    }

    #endregion
}

public class StyleSelectorConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var m = (StylesMap)parameter;

        if (value == null)
            return m.FallbackStyle;

        Style style;
        if (!m.TryGetValue(value.GetType(), out style))
            style = m.FallbackStyle;

        return style;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

HTH

tente usar a classe Selector Estilo:

http://msdn.microsoft.com /en-us/library/system.windows.controls.styleselector.aspx

Eu não usei-me especificamente, então eu não tenho nenhum código de exemplo para você verificar para fora, mas o link MSDN tem algum.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top