views:

239

answers:

2

Hi, I have two Visual States defined in my MainWindow's LayoutRoot Grid as following:

<Grid x:Name="LayoutRoot" Background="#FF434343" ShowGridLines="True">

<Grid.RowDefinitions>
    <RowDefinition Height="100"/>
    <RowDefinition Height="*"/>
</Grid.RowDefinitions>


    <VisualStateManager.CustomVisualStateManager>
        <ic:ExtendedVisualStateManager/>
    </VisualStateManager.CustomVisualStateManager>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="VisualStateLogin">
            <VisualStateGroup.Transitions>
                <VisualTransition GeneratedDuration="00:00:00.6000000"/>
            </VisualStateGroup.Transitions>
            <VisualState x:Name="LoggedOn">
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="{x:Null}" Storyboard.TargetProperty="(Window.WindowStyle)">
                        <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static WindowStyle.None}"/>
                    </ObjectAnimationUsingKeyFrames>
                    <BooleanAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="{x:Null}" Storyboard.TargetProperty="(Window.AllowsTransparency)">
                        <DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="True"/>
                    </BooleanAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="LoggedOff">
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="brdContent" Storyboard.TargetProperty="(UIElement.Opacity)">
                        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.1"/>
                    </DoubleAnimationUsingKeyFrames>
                    <BooleanAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="brdContent" Storyboard.TargetProperty="(UIElement.IsEnabled)">
                        <DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False"/>
                    </BooleanAnimationUsingKeyFrames>
                    <BooleanAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ucTabButtons" Storyboard.TargetProperty="(UIElement.IsEnabled)">
                        <DiscreteBooleanKeyFrame KeyTime="00:00:00" Value="False"/>
                    </BooleanAnimationUsingKeyFrames>
                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ucTabButtons" Storyboard.TargetProperty="(UIElement.Opacity)">
                        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0.4"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

It works fine switching from one state to another thoughtout the MainWindow codebehind, like that:

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        //ExtendedVisualStateManager.GoToElementState(this.LayoutRoot as FrameworkElement, "LoggedOff", false);        
    }

But now, I need to be able to switching states from an usercontrol inside the MainWindow...

I have tryed that:

    private void btnOk_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        MainWindow parent = new MainWindow();
        Grid root = new Grid();
        root = (Grid)parent.FindName("LayoutRoot");
        ExtendedVisualStateManager.GoToElementState(root as FrameworkElement, "LoggedOn", true);
    }

And it gives me the following exception:

System.NullReferenceException was unhandled Message="Object reference not set to an instance of an object." Source="WPFToolkit"

Does someone know how to switch states from an usercontrol?

ThankYou,

Josi

A: 

I recommend defining an interface for switching between states. The form can implement the interface and it can either explicitly pass the interface to the control or the control can query its parent to see if the interface is implemented. This way the user control is not tightly coupled to its container, only to the behavior that it expects the container to provide.

On a side note, having a user control modify the state of its container is an unusual design. You might want to consider if there is an alternate way to structure the requirement.

A possible interface:

public interface IStateChanger
{
    void GoToElementState(string state);    
}

You can have your MainWindow implement this interface:

    void IStateChanger.GoToElementState(string state)
    {
        ExtendedVisualStateManager.GoToElementState(this.LayoutRoot as FrameworkElement, state, false);        
    }

Then your control, following your example, can do this:

    private void btnOk_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        MainWindow parent = new MainWindow();
        if (parent is IStateChanger)
            ((IStateChanger)parent).GoToElementState("LoggedOn");
    }
Dan Bryant
A: 

Create a public event on your user control to which the parent can subscribe; the event can then be used as a trigger for the state transition.

Jay