Reputation: 21
I need to bind a button to a Control Template. The XAML looks something like this:
Button Template="{Binding Status, Converter={StaticResource StatustoTemplate}}"
The converter (StatustoTemplate) runs fine as the status (which is an integer, but happy for it to be a string) changes:
public class StatustoTemplate : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value==1)
{
return ControlTemplateName1;
}
if (value==2)
{
return ControlTemplateName2;
}
}
}
Now, in what format can I send back ControlTemplate1, or ControlTemplate2? Let us assume that ControlTemplate1 and ControlTemplate2 are valid Control Templates as defined in the XAML. I now that it needs to return a ControlTemplate - but how to set it up?
Upvotes: 2
Views: 1423
Reputation: 35646
my preferred approach is to use a Style with DataTriggers to switch Template, without converters
<Style TargetType="Button" x:Key="StatusButton"> <!--set BasedOn if there is a base Style-->
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="1">
<Setter Property="Template" Value="{StaticResource ControlTemplateName1}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="2">
<Setter Property="Template" Value="{StaticResource ControlTemplateName2}"/>
</DataTrigger>
</Style.Triggers>
</Style>
and then apply this Style:
<Button Style="{StaticResource StatusButton}"/>
Upvotes: 1
Reputation: 1649
I have a MarkupExtension
that might work for you. It is getting xaml defined Resources
by ResourceKey
.
First: abstract class StyleRefExtension:
public abstract class StyleRefExtension : MarkupExtension
{
protected static ResourceDictionary RD;
public string ResourceKey { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
return ProvideValue();
}
public object ProvideValue()
{
if (RD == null)
throw new Exception(
@"You should define RD before usage.
Please make it in static constructor of extending class!");
return RD[ResourceKey];
}
}
Second: class implementation as StyleRefExt
public class StyleRefExt : StyleRefExtension
{
static StyleRefExt()
{
RD = new ResourceDictionary
{
Source = new Uri("pack://application:,,,/##YOUR_ASSEMBLYNAME##;component/Styles/##YOUR_RESOURCE_DICTIONARY_FILE##.xaml")
};
}
}
Just replace ##YOUR_ASSEMBLYNAME## with the name of your assembly and ##YOUR_RESOURCE_DICTIONARY_FILE## with the filename of your ResourceDictionary
(that is located in folder Styles
).
Your Converter
should look like this:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value==1) {
StyleRefExt sr = new StyleRefExt {ResourceKey = "ControlTemplateName1"};
return sr.ProvideValue();
}
if (value==2) {
StyleRefExt sr = new StyleRefExt {ResourceKey = "ControlTemplateName2"};
return sr.ProvideValue();
}
}
Upvotes: 0
Reputation: 526
It is not easy for converter to find resource defined in XAML. I usually define one control template which has both definitions and switch them using Visibility
. The code is just a short sample.
XAML
<Window>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<local:MyConverter x:Key="MyConverter"/>
<ControlTemplate x:Key="template">
<Grid>
<Grid Visibility="{Binding Status, Converter={StaticResource MyConverter}, ConverterParameter=1}">
<TextBox Text="1"/>
</Grid>
<Grid Visibility="{Binding Status, Converter={StaticResource MyConverter}, ConverterParameter=2}">
<TextBox Text="2"/>
</Grid>
</Grid>
</ControlTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Button Template="{StaticResource template}"/>
</Grid>
</Window>
Converter
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((string)parameter == "1") ? Visibility.Visible : Visibility.Collapsed;
}
// ConvertBack
}
Upvotes: 0