views:

245

answers:

2

Hello,

I have made a sample demo VS 2010 RC sample project, because in my production project I have the same error using MVVM.

In my sample demo project I use only Code-behind without 3rd party dependencies so you can download the demo project here and run it for yourself: http://www.sendspace.com/file/mwx7wv

Now to the problem: When I click the girls/boys button it should switch the datatemplate, not?

What do I wrong?

OK I offer here a code snippet too:

Code-Behind MainWindow.cs:

namespace ContentTemplateSelectorDemo

{ /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { Person person;

    public MainWindow()
    {
        InitializeComponent();

        person = new Person(){ Gender = "xxx"};
        person.IsBoy = true;


        ContentGrid.DataContext = person;
    }

    private void btnBoys_Click(object sender, RoutedEventArgs e)
    {
        person.IsBoy = true;
        person.IsGirl = false;
        this.ContentGrid.DataContext = person;
    }

    private void btnGirls_Click(object sender, RoutedEventArgs e)
    {
        person.IsGirl = true;
        person.IsBoy = false;
        this.ContentGrid.DataContext = person;

    }        
}

}

XAML MainWindow.xaml:

<Window x:Class="ContentTemplateSelectorDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ContentTemplateSelectorDemo"
    Title="MainWindow" Height="350" Width="525">

<Window.Resources>

    <DataTemplate x:Key="girlsViewTemplate">
        <local:UserControl1 />
    </DataTemplate>

    <DataTemplate x:Key="boysViewTemplate" >
        <local:UserControl2 />
    </DataTemplate>

    <local:PersonDataTemplateSelector x:Key="PersonSelector" />

</Window.Resources>

<Grid x:Name="ContentGrid" >
    <StackPanel>
        <Button Name="btnGirls" Click="btnGirls_Click">Switch Girls</Button>
        <Button Name="btnBoys" Click="btnBoys_Click">Switch Boys</Button>
    <ContentControl Content="{Binding}" ContentTemplateSelector="{StaticResource ResourceKey=PersonSelector}" />
    </StackPanel>
</Grid>

DataTemplateSelector class:

public class PersonDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item,DependencyObject container)
    {
        if (item is Person)
        {
            Person person = item as Person;

            Window window = Application.Current.MainWindow;

            if (System.ComponentModel.DesignerProperties.GetIsInDesignMode( window))
                return null;

            if (person.IsBoy)               
                return window.FindResource("boysViewTemplate") as DataTemplate;
            if (person.IsGirl)            
                return window.FindResource("girlsViewTemplate") as DataTemplate;

        }
        return null;
    }
}

:)

A: 

I like Neil's solution (found on Josh's post via the link you provided):

<DataTemplate DataType="{x:Type local:MyType}">
        <ContentPresenter Content="{Binding}" Name="cp" />
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=IsRunning}" Value="True">
                <Setter TargetName="cp" Property="ContentTemplate" Value="{StaticResource StopTemplate}" />
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=IsRunning}" Value="False">
                <Setter TargetName="cp" Property="ContentTemplate" Value="{StaticResource StartTemplate}" />
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

Edit: I couldn't actually get the above code to work, but this works using a style:


        <DataTrigger Binding="{Binding Path=SourceSystem.SourceSystemName}"
                     Value="mysite.com">
   <Setter Property="ContentControl.ContentTemplate" 
                    Value="{StaticResource mysiteToolbar}" />

        <DataTrigger Binding="{Binding Path=SourceSystem.SourceSystemName}"
                     Value="mysite2.com">
   <Setter Property="ContentControl.ContentTemplate" 
                    Value="{StaticResource mysiteToolbar2}" />

  </Style.Triggers>            

Simon_Weaver
A: 

Note: I think this method is quite clumsy, but could work for some scenarios. I favor the method of using a trigger (from Neil) that I posted as a separate answer.


Another possible way is to bind the Content of the ContentTemplateSelector to the property that determines the template that should be selected. For instance here I have two different toolbars chosen based upon the value of SourceSystem. I set the Content to be the sourcesystem property itself.

<ContentControl ContentTemplateSelector="{StaticResource toolbarTemplateSelector}" 
                DataContext="{Binding}" Content="{Binding SourceSystem}" />

The template selector simply looks at the source system and returns the necessary template.

If the template needs access to the datacontext of the control, just use element binding to set it.

 <UserControl.Resources>
    <DataTemplate x:Key="toolbar1">
        <views:OrdersToolbar1View Margin="0,5,0,0" 
               DataContext="{Binding ElementName=control,Path=DataContext}"/>
    </DataTemplate>
    <DataTemplate x:Key="toolbar2">
        <views:OrdersToolbar2View Margin="0,5,0,0" 
               DataContext="{Binding ElementName=control,Path=DataContext}"/>
    </DataTemplate>
 </UserControl.Resources>
Simon_Weaver