#c# #wpf #xaml #binding #controltemplates
#c# #wpf #xaml #привязка #controltemplates
Вопрос:
Мне нужно привязать кнопку к шаблону элемента управления. XAML выглядит примерно так:
Button Template="{Binding Status, Converter={StaticResource StatustoTemplate}}"
Конвертер (StatustoTemplate) работает нормально при изменении статуса (который является целым числом, но рад, что это строка):
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;
}
}
}
Теперь, в каком формате я могу отправить обратно ControlTemplate1 или ControlTemplate2? Давайте предположим, что ControlTemplate1 и ControlTemplate2 являются допустимыми шаблонами элементов управления, как определено в XAML. Теперь я понимаю, что ему нужно вернуть ControlTemplate — но как это настроить?
Ответ №1:
мой предпочтительный подход заключается в использовании стиля с DataTriggers для переключения шаблона без конвертеров
<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>
а затем примените этот стиль:
<Button Style="{StaticResource StatusButton}"/>
Комментарии:
1. Для тех, кто здесь работает с Xamarin, вы должны указать TargetType DataTrigger, в данном примере
Button
type.<DataTrigger TargetType="Button" Binding="{Binding Status}" Value="1">
Ответ №2:
Конвертеру нелегко найти ресурс, определенный в XAML. Обычно я определяю один шаблон элемента управления, который содержит оба определения, и переключаю их с помощью Visibility
. Код представляет собой всего лишь короткий пример.
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>
Конвертер
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((string)parameter == "1") ? Visibility.Visible : Visibility.Collapsed;
}
// ConvertBack
}
Ответ №3:
У меня есть MarkupExtension
что может сработать для вас. Это получение xaml, определенного Resources
с помощью ResourceKey
.
Первое: расширение стиля абстрактного класса:
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];
}
}
Второе: реализация класса в виде StyleRefExt
public class StyleRefExt : StyleRefExtension
{
static StyleRefExt()
{
RD = new ResourceDictionary
{
Source = new Uri("pack://application:,,,/##YOUR_ASSEMBLYNAME##;component/Styles/##YOUR_RESOURCE_DICTIONARY_FILE##.xaml")
};
}
}
Просто замените ##YOUR_ASSEMBLYNAME## на имя вашей сборки и ##YOUR_RESOURCE_DICTIONARY_FILE ## на ваше ResourceDictionary
имя файла (которое находится в папке Styles
).
Ваш Converter
должен выглядеть следующим образом:
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();
}
}