What is the most minimal way to dynamically interchange UIElements at a certian "slot" on the UI? I have a number of UIElements and based on some external databinding (e.g. a combobox selection) I want one of them to be shown and the one that was currently visible to be hidden. So the behavior is sort of like the tabcontrol but without the tabstrip, the chrome and the tabitem instances. So I could actually use the TabControl and override the control template. But is this really the most minimal approach?
<ContentControl Content="{Binding SomePropertyThatYieldsTheContent}"/>
HTH, Kent
The way I do it is to layer the elements on top of each other and programatically change their Visibility property from Visible to Collapsed and back again as needed.
I don't know if this is the most succinct way, but if you are using a DataTemplate, you could use DataTriggers (the assumption here is that the initial visibility is Collapsed):
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=SourceProperty.ValueType}">
<DataTrigger.Value>
<pm:ValueType>Text</pm:ValueType>
</DataTrigger.Value>
<Setter TargetName="TextEditor" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=SourceProperty.ValueType}">
<DataTrigger.Value>
<pm:ValueType>Logical</pm:ValueType>
</DataTrigger.Value>
<Setter TargetName="LogicalEditor" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=SourceProperty.ValueType}">
<DataTrigger.Value>
<pm:ValueType>DateTime</pm:ValueType>
</DataTrigger.Value>
<Setter TargetName="DateEditor" Property="Visibility" Value="Visible" />
</DataTrigger>
...
Look into Data Template Selectors, Bea Stollnitz has a good post here. Basically you'll use a ContentPresenter in each of your UI "slots" and then use the ContentTemplateSelector property to define which template selector you'll use.
You have several options. As Bryan mentioned, Data Template Selectors can definitely work, although I've decided that they are frequently overkill. Take your example for instance - if you want to bind the visibility of an element to the selection in a ComboBox, I would prefer a ValueConverter instead. Pass the ComboBox.SelectedItem to the Converter and have it return a Visibility value:
public class MyObjectToVisibleOrCollapsed : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is MyObject)
{
var myObject = (MyObject)value;
if (myObject.SomeState)
{
return Visibility.Visible;
}
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Now in your Window.Resources, create an instance of the ValueConverter and Bind the Element to the ComboBox.SelectedItem using the ValueConverter instance:
<local:MyObjectToVisibleOrCollapsed x:Key="myObjectToVisibleOrCollapsed"/>
<DataTemplate x:Key="MyTemplate">
<TextBlock Text="{Binding Path=myText}"
x:Name="MyText"
Visibility="{Binding ElementName=MyComboBox, Path=SelectedItem, Converter={StaticResource myObjectToVisibleOrCollapsed}, Mode=Default}" />
</DataTemplate>
And of course you can reuse the ValueConverter for all the elements in your Data Template (and if there are a lot of them, then the Data Template Selector approach becomes more desirable).
[Disclaimer: the code above was hashed out from memory and not tested - it may need a little tweaking]
I create custom user controls for each possible 'view'.
Their visibility is changed using c#, thou. Little coding needed.
The primary reason for this approach is the ease of development — the designer focuses on particular view rather than the set of all posible controls that will be there.