Привязка к шаблону элемента управления

#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();
    }
}