Search code examples
c#wpfdatatemplatecontentpresenterdatatemplateselector

WPF DataTemplate, TemplateSelectors, ContentPresenter based on SelectedItem


I am very confused what to use and how to start implementations, but I want is based on a Enum property when changed a certain grid should display.

Currently I have like 20 grids, working with visibility when the property change. This is not ideal for 2 things. All 20 grids will bind from startup and it isnot good for performance. Secondly some "Grids" are the same for some values of the enum property. So I have duplicate code in some grids.

Now what I have is an enum:

   public enum MyEnumsForDropDown
    {
        Enum1= 1,
        Enum2= 2,
        Enum3= 3,
        Enum4= 4,
        Enum5= 5
    }

My Object in my ViewModel, which I bind to is for :

Public class MyObject
{
  private Enums.MyEnumsForDropDown _myChosenEnum;
  public Enums.MyEnumsForDropDown MyChosenEnum
  {
    get { return _myChosenEnum; }
    set
    {
      _myChosenEnum = value;
      this.NotifyPropertyChanged( x => x.MyChosenEnum );
    }
  }
}

My XAML:

<ComboBox ItemsSource="{Binding CollectionOfEnums}" 
DisplayMemberPath="Value" SelectedValuePath="Key" SelectedValue="{Binding 
MyObject.MyChosenEnum}"></ComboBox>

<Grid Grid.Row="1" Grid.Column="3" Visibility="{Binding 
Path=MyObject.MyChoseEnum, Converter={StaticResource 
EnumToVisibleCollapseConverter}, ConverterParameter={x:Static 
myenumsNameSpace:Enums+MyEnumsForDropDown.Enum1}}">
  <TextBlock Content"This Grid displays when Enum1 is chosen"/>
</Grid>

<Grid Grid.Row="1" Grid.Column="3" Visibility="{Binding 
Path=MyObject.MyChoseEnum, Converter={StaticResource 
EnumToVisibleCollapseConverter}, ConverterParameter={x:Static 
myenumsNameSpace:Enums+MyEnumsForDropDown.Enum2}}">
  <TextBlock Content"This Grid displays when Enum2 is chosen"/>
</Grid>

How do I change the Grids to work somehow like ContentPresenters or DataTemplates or whatever I need to use depended on when the property MyChosenEnum changes in my object??


Solution

  • You could define a DataTemplate for each enum value and then use a ContentControl with a Style to display the correct one:

    <ContentControl Content="{Binding MyObject.MyChosenEnum}">
        <ContentControl.Resources>
            <DataTemplate x:Key="Enum1">
                <Grid />
            </DataTemplate>
            <DataTemplate x:Key="Enum2">
                <Grid />
            </DataTemplate>
        </ContentControl.Resources>
        <ContentControl.Style>
            <Style TargetType="ContentControl">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding MyObject.MyChosenEnum}"
                                 Value="{x:Static myenumsNameSpace:Enums+MyEnumsForDropDown.Enum1}">
                        <Setter Property="ContentTemplate" Value="{StaticResource Enum1}" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding MyObject.MyChosenEnum}"
                                 Value="{x:Static myenumsNameSpace:Enums+MyEnumsForDropDown.Enum2}">
                        <Setter Property="ContentTemplate" Value="{StaticResource Enum2}" />
                    </DataTrigger>
                    <!-- and so on for each enum value -->
                </Style.Triggers>
            </Style>
        </ContentControl.Style>
    </ContentControl>
    

    Or you could use a DataTemplateSelector:

    public class YourSelector : DataTemplateSelector
    {
        public DataTemplate Enum1 { get; set; }
        public DataTemplate Enum2 { get; set; }
        //...
    
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            MyEnumsForDropDown value = (MyEnumsForDropDown)item;
            switch(value)
            {
                case MyEnumsForDropDown.Enum1:
                    return Enum1;
                case MyEnumsForDropDown.Enum2:
                    return Enum2;
            }
    
            return base.SelectTemplate(item, container);
        }
    }
    

    <Grid>
        <Grid.Resources>
            <DataTemplate x:Key="Enum1">
                <Grid />
            </DataTemplate>
            <DataTemplate x:Key="Enum2">
                <Grid />
            </DataTemplate>
            <local:YourSelector x:Key="selector" Enum1="{StaticResource Enum1}" Enum2="{StaticResource Enum2}" />
        </Grid.Resources>
        <ContentControl Content="{Binding MyObject.MyChosenEnum}"
                        ContentTemplateSelector="{StaticResource selector}" />
    </Grid>