WP8.1 Как привязать свойство в диспетчере визуальных состояний стиля кнопки-переключателя

Я решил настроить кнопку-переключатель с собственным стилем: он содержит изображение и текст. Обычное состояние моей кнопки использует определенное изображение и определенный текст переднего плана. проверенное состояние использует другие.

Однако... переключатель не работает для моих изображений.

Я создал пользовательскую кнопку переключения. Код находится прямо здесь:

class CustomToggleButton : ToggleButton
{

    public String ImageSource
    {
        get { return (String)GetValue(ImageSourceProperty); }
        set { SetValue(ImageSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ImageSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ImageSourceProperty =
        DependencyProperty.Register("ImageSource", typeof(String), typeof(CustomToggleButton), new PropertyMetadata(String.Empty));



    public String SelectedImageSource
    {
        get { return (String)GetValue(SelectedImageSourceProperty); }
        set { SetValue(SelectedImageSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectedImageSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectedImageSourceProperty =
        DependencyProperty.Register("SelectedImageSource", typeof(String), typeof(CustomToggleButton), new PropertyMetadata(String.Empty));


}

Я использую свой контроль следующим образом:

<controls:CustomToggleButton ImageSource="/Resources/home.png" SelectedImageSource="/Resources/home-neg.png" FontSize="18"
                             Content="Acceuil" Style="{StaticResource HamburgerMenuItemStyle}"   VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>

Здесь пользовательский стиль кнопки переключения:

<x:Double x:Key="TextStyleLargeFontSize">18.14</x:Double>
    <Thickness x:Key="PhoneButtonContentPadding">9.5,0,9.5,3.5</Thickness>
    <x:Double x:Key="PhoneButtonMinHeight">57.5</x:Double>
    <x:Double x:Key="PhoneButtonMinWidth">109</x:Double>
    <Style x:Key="HamburgerMenuItemStyle" TargetType="ToggleButton">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="{ThemeResource PhoneForegroundBrush}"/>
        <Setter Property="Foreground" Value="{ThemeResource PhoneForegroundBrush}"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="FontFamily" Value="{StaticResource StandardFont}"/>
        <Setter Property="FontSize" Value="{ThemeResource TextStyleLargeFontSize}"/>
        <Setter Property="Padding" Value="{ThemeResource PhoneButtonContentPadding}"/>
        <Setter Property="MinHeight" Value="{ThemeResource PhoneButtonMinHeight}"/>
        <Setter Property="MinWidth" Value="{ThemeResource PhoneButtonMinWidth}"/>
        <Setter Property="HorizontalAlignment" Value="Left"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="controls:CustomToggleButton">
                    <Grid Background="Transparent">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="EnabledBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="EnabledContent">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource IaF-SColor-DarkGreen}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="ToggleImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding ImageSource}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOver"/>
                                <VisualState x:Name="Pressed"/>
                                <VisualState x:Name="Disabled"/>
                                <VisualState x:Name="Checked">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="EnabledBackground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource IaF-SColor-DarkGreen}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="EnabledContent">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="ToggleImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding SelectedImageSource}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="CheckedPointerOver"/>
                                <VisualState x:Name="CheckedPressed"/>
                                <VisualState x:Name="CheckedDisabled"/>
                                <VisualState x:Name="Indeterminate"/>
                                <VisualState x:Name="IndeterminatePointerOver"/>
                                <VisualState x:Name="IndeterminatePressed"/>
                                <VisualState x:Name="IndeterminateDisabled"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="EnabledBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{ThemeResource PhoneTouchTargetOverhang}">
                            <ContentPresenter AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding ContentTemplate}" 
                                              Foreground="{TemplateBinding Foreground}" Margin="{TemplateBinding Padding}" >
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition/>
                                        <ColumnDefinition/>
                                        <ColumnDefinition/>
                                        <ColumnDefinition/>
                                    </Grid.ColumnDefinitions>
                                    <Image x:Name="ToggleImage" Source="{Binding ImageSource}"/>
                                    <TextBlock Grid.Column="1" Grid.ColumnSpan="3" x:Name="EnabledContent" Style="{StaticResource BaseTextBlockStyle}" Foreground="{TemplateBinding Foreground}"
                                               FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" Text="{TemplateBinding Content}" Margin="10,0,0,0"
                                               TextAlignment="Left" VerticalAlignment="Center"/>
                                </Grid>
                            </ContentPresenter>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Как видите, я пытаюсь установить свои пользовательские свойства кнопки-переключателя для двух разных состояний:

Нормальное состояние:

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="ToggleImage">
    <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding ImageSource}"/>
</ObjectAnimationUsingKeyFrames>

И проверенное состояние:

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="ToggleImage">
    <DiscreteObjectKeyFrame KeyTime="0" Value="{Binding SelectedImageSource}"/>
</ObjectAnimationUsingKeyFrames>

И... совсем не работает.

ИЗМЕНИТЬ:

Для заинтересованных товарищей мое решение доступно ниже.


person Klaonis    schedule 25.03.2016    source источник
comment
Вы пробовали TemplateBinding?   -  person Archana    schedule 25.03.2016
comment
Попробуйте это {Binding RelativeSource={RelativeSource TemplateParent},Path=ImageSource}   -  person Archana    schedule 25.03.2016
comment
Первое решение просто не работает, а второе приводит к сбою моего приложения!   -  person Klaonis    schedule 25.03.2016
comment
Можете ли вы сказать мне исключение?   -  person Archana    schedule 25.03.2016
comment
Он падает в App.g.i.cs с этим сообщением: test.exe!test.App.InitializeComponent.AnonymousMethod__2(отправитель объекта, Windows.UI.Xaml.UnhandledExceptionEventArgs e) Строка 50 C# Я думаю, XAML не нравится, как мы пытаемся привязать данные.   -  person Klaonis    schedule 25.03.2016
comment
Смотрите ответ. Это невозможно сделать в визуальных состояниях   -  person Archana    schedule 25.03.2016


Ответы (3)



Лучше иметь перекрывающиеся изображения и изменять видимость изображений в зависимости от состояния кнопки переключения.

person Chirag Shah    schedule 25.03.2016
comment
действительно, это может быть решением. Однако мне интересно, можно ли добиться этого в диспетчере визуальных состояний. - person Klaonis; 25.03.2016

Наконец, мое решение немного отличается от первоначальной идеи: я интегрировал дополнительное изображение для управления «выбранным состоянием». Затем я играю с атрибутом видимости изображения в диспетчере визуальных состояний.

У меня было дополнительное свойство в пользовательском классе кнопки переключения, чтобы установить «выбранный источник изображения».

public class CustomToggleButton : ToggleButton
{

    [...]

    public String SelectedImageSource
    {
        get { return (String)GetValue(SelectedImageSourceProperty); }
        set { SetValue(SelectedImageSourceProperty, value); }
    }

    // Using a DependencyProperty as the backing store for SelectedImageSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SelectedImageSourceProperty =
        DependencyProperty.Register("SelectedImageSource", typeof(String), typeof(CustomToggleButton), new PropertyMetadata(String.Empty));


}

Затем я изменил вызов этого пользовательского элемента управления:

<controls:CustomToggleButton ImageSource="/Resources/home.png" SelectedImageSource="/Resources/home-neg.png" FontSize="18" Click="CustomToggleButton_Click"
                             Content="Acceuil" Style="{StaticResource HamburgerMenuItemStyle}"   
                             VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>

Наконец, я изменил пользовательский стиль кнопки-переключателя, установив другое изображение, «SelectedItemImage», и я использовал атрибут видимости, чтобы скрыть или показать правильное изображение.

<Style x:Key="HamburgerMenuItemStyle" TargetType="ToggleButton">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="FontFamily" Value="{StaticResource StandardFont}"/>
        <Setter Property="HorizontalAlignment" Value="Left"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="controls:CustomToggleButton" >
                    <Grid Background="Transparent">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ItemBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ItemTextBlock">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource IaF-SColor-DarkGreen}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ItemImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="SelectedItemImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOver"/>
                                <VisualState x:Name="Pressed"/>
                                <VisualState x:Name="Disabled"/>
                                <VisualState x:Name="Checked">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ItemBorder">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource IaF-SColor-DarkGreen}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ItemTextBlock">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="White"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ItemImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="SelectedItemImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="CheckedPointerOver"/>
                                <VisualState x:Name="CheckedPressed"/>
                                <VisualState x:Name="CheckedDisabled"/>
                                <VisualState x:Name="Indeterminate"/>
                                <VisualState x:Name="IndeterminatePointerOver"/>
                                <VisualState x:Name="IndeterminatePressed"/>
                                <VisualState x:Name="IndeterminateDisabled"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="ItemBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                            <ContentPresenter AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding ContentTemplate}" 
                                              Margin="{TemplateBinding Padding}" VerticalAlignment="Center">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="5*"/>
                                    </Grid.ColumnDefinitions>
                                    <Image x:Name="ItemImage" Source="{Binding Path=ImageSource, RelativeSource={RelativeSource TemplatedParent}}" 
                                           VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MaxHeight="{StaticResource MenuButtonImageSize}" MaxWidth="{StaticResource MenuButtonImageSize}"/>
                                    <Image x:Name="SelectedItemImage" Source="{Binding Path=SelectedImageSource, RelativeSource={RelativeSource TemplatedParent}}" 
                                           VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MaxHeight="{StaticResource MenuButtonImageSize}" MaxWidth="{StaticResource MenuButtonImageSize}"/>
                                    <TextBlock Grid.Column="1" x:Name="ItemTextBlock" Style="{StaticResource BaseTextBlockStyle}" Foreground="{TemplateBinding Foreground}"
                                               FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" Text="{TemplateBinding Content}" Margin="20,0,0,0"
                                               TextAlignment="Left" VerticalAlignment="Center"/>
                                </Grid>
                            </ContentPresenter>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Основные изменения здесь:

<Image x:Name="ItemImage" Source="{Binding Path=ImageSource, RelativeSource={RelativeSource TemplatedParent}}" 
                                           VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MaxHeight="{StaticResource MenuButtonImageSize}" MaxWidth="{StaticResource MenuButtonImageSize}"/>
<Image x:Name="SelectedItemImage" Source="{Binding Path=SelectedImageSource, RelativeSource={RelativeSource TemplatedParent}}" 
                                           VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MaxHeight="{StaticResource MenuButtonImageSize}" MaxWidth="{StaticResource MenuButtonImageSize}"/>

Мы привязываем исходный код к пользовательским свойствам зависимости класса (благодаря предложению Archana), а затем играем с видимостью в диспетчере визуальных состояний, например так:

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ItemImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="SelectedItemImage">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
person Klaonis    schedule 25.03.2016
comment
Изображения статичны? Если да, есть простой способ получить изображения в стиле элемента управления и переключать видимость изображений в визуальных состояниях элемента управления. В противном случае свойство зависимости - это путь. - person Chirag Shah; 26.03.2016
comment
Что вы подразумеваете под статическим изображением? У меня есть папка с изображениями, и я несколько раз использую кнопку переключения с разными наборами изображений. - person Klaonis; 27.03.2016
comment
Например, кнопки-переключатели используются для логических вариантов использования, таких как yes-no true-false. Таким образом, под статическими изображениями я имел в виду, например, переключение изображений. При этом там же по одному значению. Отметьте изображение, если да, и перекрестное изображение, если нет. - person Chirag Shah; 27.03.2016