WPF — управление VisualState из пользовательского элемента управления

У меня есть два визуальных состояния, определенных в моей сетке LayoutRoot MainWindow следующим образом:

<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>

Он отлично работает, переключаясь из одного состояния в другое, продуманное в программном коде MainWindow, например:

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

Но теперь мне нужно иметь возможность переключать состояния из пользовательского элемента управления внутри MainWindow...

Я пробовал это:

    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);
    }

И это дает мне следующее исключение:

Исключение System.NullReferenceException не было обработано. Message="Ссылка на объект не указывает на экземпляр объекта." Источник="WPFToolkit"

Кто-нибудь знает, как переключать состояния из пользовательского управления?

Спасибо,

Джози


person Learning Xamarin    schedule 07.03.2010    source источник


Ответы (2)


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

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

Возможный интерфейс:

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

Вы можете реализовать этот интерфейс в MainWindow:

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

Тогда ваш элемент управления, следуя вашему примеру, может сделать это:

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

Создайте публичное событие в пользовательском элементе управления, на которое родитель может подписаться; затем событие можно использовать в качестве триггера для перехода состояния.

person Jay    schedule 08.03.2010