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(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) Ред 50 C# Мисля, че XAML не харесва начина, по който се опитваме да свързване на данни.   -  person Klaonis    schedule 25.03.2016
comment
Вижте отговора. Не е възможно да го направите във визуални състояния   -  person Archana    schedule 25.03.2016


Отговори (3)


Според тази връзка не е възможно. Не можете да използвате препратки към динамични ресурси или изрази за обвързване на данни, за да зададете стойности на свойство Storyboard или анимация. Това е така, защото всичко вътре в ControlTemplate трябва да е безопасно за нишки и системата за синхронизиране трябва да замрази обектите на Storyboard, за да ги направи безопасни за нишки. Storyboard не може да бъде замразен, ако той или неговите дъщерни времеви линии съдържат препратки към динамични ресурси или изрази за обвързване на данни

person Archana    schedule 25.03.2016

По-добре е да имате припокриващи се изображения и да променяте видимостта на изображенията в зависимост от състоянието на бутона за превключване

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
Например бутоните за превключване се използват за случаи на използване на bool като да-не вярно-невярно. Така че под статични изображения имах предвид, като превключване на изображение с отметка-кръст. При което има същото за една стойност. Поставете отметка върху изображението за „да“ и кръстосано изображение за „не“. - person Chirag Shah; 27.03.2016