Button ControlTemplate Foreground WPF
От: Sergey_BG Россия  
Дата: 27.12.10 11:31
Оценка:
Помогите пожалуйста.
Имею стиль для кнопки написанный с использование триггеров и сеттеров.
Переделываю под использование VisualStateManager.
Ряд свойств объектов привязан к свойству Button.Foreground.
В состоянии Disabled хочу менять это свойство.
Background работает, а Foreground не находит. Кнопка является потомком Control, и оно у него должно быть. Может я binding не правильно делаю...

        <Style x:Key="buttonLeftStyle" TargetType="Button">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate x:Name="template" TargetType="{x:Type Button}">
                        <Grid x:Name="gridOfButton">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Disabled">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames
                                                Storyboard.Target="{Binding RelativeSource={RelativeSource TemplatedParent}}"
                                                Storyboard.TargetProperty="Foreground"
                                              Duration="0">
                                                <ObjectAnimationUsingKeyFrames.KeyFrames>
                                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource buttonDisabledBrush} /">
                                                </ObjectAnimationUsingKeyFrames.KeyFrames>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>



С помощью триггера/сеттера это делается крайне легко, а со Storyboard имею проблемы.

<ControlTemplate.Triggers>
    <Trigger Property="IsEnabled" Value="False">
        <Setter Property="Foreground" Value="{StaticResource buttonDisabledBrush}"/>
    </Trigger>
</ControlTemplate.Triggers>
Сергей
Re: Button ControlTemplate Foreground WPF
От: MxMsk Португалия  
Дата: 27.12.10 12:06
Оценка:
Здравствуйте, Sergey_BG, Вы писали:

S_B>Помогите пожалуйста.

S_B>Имею стиль для кнопки написанный с использование триггеров и сеттеров.
S_B>Переделываю под использование VisualStateManager.
S_B>Ряд свойств объектов привязан к свойству Button.Foreground.
S_B>В состоянии Disabled хочу менять это свойство.
S_B>Background работает, а Foreground не находит. Кнопка является потомком Control, и оно у него должно быть. Может я binding не правильно делаю...
В чем выражается? Есть ли какие-нибудь исключения или сообщения в Output?
Re[2]: Button ControlTemplate Foreground WPF
От: Sergey_BG Россия  
Дата: 27.12.10 12:22
Оценка:
Здравствуйте, MxMsk, Вы писали:

Есть ли какие-нибудь исключения или сообщения в Output?

"InvalidOperationException was thrown on button "buttonNext": Cannot resolve all propertiey references in the property path 'Foreground'. Verify that applicable objects support the property".

Details:
at System.Windows.Media.Animation.Storyboard.VerifyPathIsAnimatable(PropertyPath path)



"buttonNext" — это кнопка со стилем Disabled
Сергей
Re[3]: Button ControlTemplate Foreground WPF
От: Sergey_BG Россия  
Дата: 27.12.10 12:30
Оценка:
Здравствуйте, Sergey_BG, Вы писали:

Точно, посмотрел стек, оно конектится к корневому элементу Grid. У которого нет этого свойства. Т.е. binding некорректен. Как привязаться к свойству кнопки?
В Storyboard не получается используя ими объекта и имя свойства это сделать. Если же получить Target ={TemplateBinding Foreground}, то нет такого имени свойства TargetProperty чтоб задать кисть, а имя свойства требуется обязательно.
Сергей
Re[4]: Button ControlTemplate Foreground WPF
От: Vladek Россия Github
Дата: 28.12.10 05:21
Оценка:
Здравствуйте, Sergey_BG, Вы писали:

S_B>Здравствуйте, Sergey_BG, Вы писали:


S_B>Точно, посмотрел стек, оно конектится к корневому элементу Grid. У которого нет этого свойства. Т.е. binding некорректен. Как привязаться к свойству кнопки?

S_B>В Storyboard не получается используя ими объекта и имя свойства это сделать. Если же получить Target ={TemplateBinding Foreground}, то нет такого имени свойства TargetProperty чтоб задать кисть, а имя свойства требуется обязательно.

Анимировать свойства контрола нельзя, это бессмысленно. Анимировать надо тот элемент и то его свойство, к которому применён биндинг {TemplateBinding Foreground} в шаблоне контрола.
Re[5]: Button ControlTemplate Foreground WPF
От: Sergey_BG Россия  
Дата: 30.12.10 09:49
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Анимировать свойства контрола нельзя, это бессмысленно. Анимировать надо тот элемент и то его свойство, к которому применён биндинг {TemplateBinding Foreground} в шаблоне контрола.


Я уже многое прочитал по этому поводу. Основное, это не бессмысленность, а небезопасность. Обращение к дочерним элементам внутри ControlTemplate runtime безопасно.

А вопрос возник потому, что в примерах для начинающих, меняют (правда с помощью setter) свойства ControlTemplate, а при прочтении МСДН я заметил что используется VisualStateManager и Animation с duration=0. Из VisualStateManager для меня сейчас невозможно изменять свойства контрола. VisualStateManager меняет свойства корневого элемента (по умолчанию), в котором он собственно и находится.

В целях самообучения я пытался привязать свойство элемента имеющего аналог Foreground (например Fill) к свойству ControlTemplate с Mode=TwoWay, и меняя его, менять свойство ControlTemplate, но у меня почему-то не получилось.

Правда мне кое-что не до конца понятно. Если я в VisualStateManager меняю какое нибудь свойство которое {TemplateBinding Foreground}. Свойство самого контрола не будет же изменено. Т.е. это не тоже самое как если в триггере ControlTemplate с помощью setter я меняю свойство ControlTemplate.

Это я сужу из того, что я имею два свойства внутри шаблона с биндингом
1 {TemplateBinding Foreground}
и
2 {Binding RelativeSource={RelativeSource TemplatedParent}, Path=Foreground, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}".

Изменение второго не приводит к изменению первого свойства.

Я понимаю, что если сделать биндинг первого свойства на второе, то все заработает. Ну а если есть другой контрол (например Button 2), и он биндится к свойству этого контрола (Button 1)? Тогда он (Button 2) не увидит, что свойство поменялось, так как свойство контрола (Button 1) изменено не было. Будут изменены свойства дочерних контролов внутри темплейта.

Я этот вопрос на текущий момент не понимаю, и буду очень благодарен всем замечаниям, подсказкам и ссылкам.
Сергей
Re[6]: Button ControlTemplate Foreground WPF
От: Vladek Россия Github
Дата: 30.12.10 12:29
Оценка: 3 (2)
Здравствуйте, Sergey_BG, Вы писали:

S_B>Я этот вопрос на текущий момент не понимаю, и буду очень благодарен всем замечаниям, подсказкам и ссылкам.


Например
Re[7]: Button ControlTemplate Foreground WPF
От: Sergey_BG Россия  
Дата: 30.12.10 15:10
Оценка:
Здравствуйте, Vladek, Вы писали:

Вот простой пример показывающий, что я имел в виду. Здесь две кнопки. Background второй забинден на первую. Первая меняет при загрузке свойство дочернего элемента имеющего
Fill="{Binding RelativeSource={RelativeSource TemplatedParent}
и в триггере меняет background ControlTemplate при перемещении над кнопкой мыши.

Видно, что менять свойство ControlTemplate не бессмысленно. И вторая кнопка, и дочерние элементы изменения подловили.
В случае же изменения свойства дочернего элемента с биндингом к ParentTemplate и Mode=TwoWay это не работает.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="212" Width="319">
    <Window.Resources>
        <Style x:Key="buttonStyle" TargetType="Button">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="Red" />
                            </Trigger>
                            <EventTrigger RoutedEvent="Loaded">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="background" Storyboard.TargetProperty="Fill" Duration="0">
                                            <ObjectAnimationUsingKeyFrames.KeyFrames>
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <SolidColorBrush Color="Green" />
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames.KeyFrames>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </ControlTemplate.Triggers>
                        <Grid>
                            <Rectangle x:Name="background" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
                            <ContentPresenter
                                x:Name="contentPresenter"
                                Content="{TemplateBinding Content}"
                                ContentTemplate="{TemplateBinding ContentTemplate}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                Margin="{TemplateBinding Padding}"
                                />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="66,78,0,0" Name="button1" VerticalAlignment="Top" Width="75" Style="{StaticResource buttonStyle}" />
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="172,78,0,0" Name="button2" VerticalAlignment="Top" Width="75" Background="{Binding ElementName=button1, Path=Background}" />
    </Grid>
</Window>
Сергей
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.