Mamad
Mamad

Reputation: 454

How to change ancestor's property from a style

I have a Style for my Button I want to change my window's WindowState property to maximized when my Button Click Event Fired from style without any code behind . I have tried this but is not working. And this error Came up : "Cannot resolve all property references in the property path 'WindowState'. Verify that applicable objects support the properties."

Do you have any working idea please.

<Window x:Class="MyTestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyTestApp"
        mc:Ignorable="d"
        x:Name="ss"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="Button">
            <Style.Triggers>               
                <EventTrigger RoutedEvent="Button.Click">
                    <BeginStoryboard>
                        <Storyboard >
                            <ObjectAnimationUsingKeyFrames 
                                Storyboard.Target="{Binding RelativeSource={RelativeSource AncestorType=Window ,Mode=FindAncestor }}" 
                                Storyboard.TargetProperty="WindowState"
                                >
                                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                    <DiscreteObjectKeyFrame.Value>
                                        <WindowState>Maximized</WindowState>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>

                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>

                </EventTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <StackPanel Width="200" Height="200" Background="Aqua">
        <Button Content="Click me !" Width="100" Height="50"/>
        </StackPanel>
    </Grid>
</Window> 

UPDATE 1 :

I have a new Problem.I created two buttons , one for maximize State one for Normal State.if i use just this two buttons there is no problem. I Tried to Maximize my window by window's Maximize Button, then my Styled Normal Button didn't work !! if I maximize window by clicking window's maximize button then my styled normal button didn't work.So if i click my styled maximize button my styled normal button work again. whats wrong ?

<Window x:Class="MyTestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyTestApp"
        StateChanged="ss_StateChanged"
        mc:Ignorable="d"
        x:Name="ss"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="Button" x:Key="MaximizedButtonStyle">
            <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
            <Style.Triggers>              

                <EventTrigger RoutedEvent="Button.Click">
                    <BeginStoryboard>
                        <Storyboard >
                            <ObjectAnimationUsingKeyFrames  Storyboard.TargetProperty="Tag.WindowState"                        >
                                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                    <DiscreteObjectKeyFrame.Value>
                                        <WindowState>Maximized</WindowState>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>

                </EventTrigger>
            </Style.Triggers>
        </Style>

        <Style TargetType="Button" x:Key="NormalButtonStyle">
            <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
            <Style.Triggers>              
                <EventTrigger RoutedEvent="Button.Click">
                    <BeginStoryboard>
                        <Storyboard >
                            <ObjectAnimationUsingKeyFrames  Storyboard.TargetProperty="Tag.WindowState"                        >
                                <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                    <DiscreteObjectKeyFrame.Value>
                                        <WindowState>Normal</WindowState>
                                    </DiscreteObjectKeyFrame.Value>
                                </DiscreteObjectKeyFrame>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>

                </EventTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <StackPanel Width="200" Height="200" Background="Aqua">
            <Button x:Name="b1" Style="{StaticResource NormalButtonStyle}" Content="Normal Click me !" Width="100" Height="50" />
            <Button x:Name="b2" Style="{StaticResource MaximizedButtonStyle}" Content="maximize eClick me !" Width="100" Height="50" />            
        </StackPanel>
    </Grid>
</Window> 

Upvotes: 0

Views: 218

Answers (1)

If you look in the Output pane in Visual Studio, you'll see that RelativeSource is failing. I think it may be failing because the Storyboard is out of the visual tree. The binding ends up looking for WindowState on the Button itself.

Here's a slightly ugly solution that's working for me: Inside the Storyboard, all the binding can "see" is the Button, not the rest of the visual tree. So we'll smuggle the Window into a property of the Button. A more respectable way to do this would be with a BindingProxy. Binding proxies are a useful technique, and worth getting acquainted with.

<Style TargetType="Button" x:Key="MinimizeButtonStyle">
    <Setter 
        Property="Tag" 
        Value="{Binding RelativeSource={RelativeSource AncestorType=Window}}" 
        />
    <Style.Triggers>
        <EventTrigger RoutedEvent="Button.Click">
            <BeginStoryboard>
                <Storyboard >
                    <ObjectAnimationUsingKeyFrames 
                        Storyboard.TargetProperty="Tag.WindowState"
                        >

    <!-- the rest is the same as what you've got -->

Here are the errors I'm seeing in Output with your original code:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''. BindingExpression:(no path); DataItem=null; target element is 'ObjectAnimationUsingKeyFrames' (HashCode=51442863); target property is 'Target' (type 'DependencyObject')

System.Windows.Data Error: 40 : BindingExpression path error: 'WindowState' property not found on 'object' ''Button' (Name='')'. null

Exception thrown: 'System.InvalidOperationException' in PresentationFramework.dll

An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll

Cannot resolve all property references in the property path 'WindowState'. Verify that applicable objects support the properties.

Upvotes: 1

Related Questions