VisualStateManager в Silverlight: установка начального состояния - PullRequest
5 голосов
/ 01 марта 2012

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

В таком случае обычно «исходящее» состояние должно быть исходным. Насколько я понимаю, нет никакого способа определить начальное состояние в SL, кроме "base", который на самом деле не является состоянием вообще, но обозначает, как выглядит менеджер состояния, который еще не активен (раскадровки состояний не выполняются для изменить внешний вид элемента управления).

Конечно, вы можете сделать так, чтобы "base" выглядела как "подальше", но это означает, что внешний вид по умолчанию в Expression Blend невидим (вы также не можете "закрепить" состояние постоянно).

Чтобы изменить начальное состояние, которое я пытался

  • установка состояния в ctor элемента управления, который ничего не делает и
  • установка состояния в отправленном вызове из ctor или события Loaded, которые оба показывают неправильное состояние в течение доли секунды.

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

(Установка свойства непосредственно для bootstrap - это еще один вариант, конечно, но он работает только для UserControls: в шаблонных элементах управления мне пришлось бы вводить еще одну депропроп, чтобы связать шаблон с шаблоном элемента управления, с которого, как я полагаю, начинается избыточное уничтожение. )

Полагаю, я все это рассмотрел, и мне просто нужно жить с невидимым базовым состоянием?

Я использую SL4.

1 Ответ

6 голосов
/ 23 апреля 2012

Я столкнулся с подобной проблемой при разработке UserControl для WPF в Expression Blend (Примечание: если вы разрабатываете пользовательский элемент управления вместо этого, см. Мой следующий раздел). В этом UserControl у меня был дочерний элемент, который я хотел добавить и создать как наложение. Как и в вашей ситуации, в моем рабочем процессе имело смысл сначала спроектировать оверлейный элемент в его «полностью выросшем и видимом» состоянии, а затем уменьшить его и установить непрозрачность для «скрытого» состояния. При этом наложение отображается в состоянии Base, но мне нужно, чтобы начальное состояние UserControl было скрытым. На данный момент у меня было три основных соответствующих состояния: Базовое, «Скрытое» и «Видимое» (последние два являются частью группы состояний).

Вот как я решил проблему с начальным состоянием . Сначала я применил GoToStateAction к корневому элементу (к UserControl), который вызывается событием Loaded. Он говорит UserControl перейти прямо в состояние «Hidden»:

enter image description here

<i:Interaction.Triggers>
  <i:EventTrigger>
    <ei:GoToStateAction TargetObject="{Binding ElementName=userControl}" StateName="Hidden"/>
  </i:EventTrigger>
</i:Interaction.Triggers>

Во-вторых, я сделал соответствующие настройки перехода в группе состояний для наложения. Вероятно, есть несколько способов сделать это, но вот как я это сделал. Сначала я установил «Переход по умолчанию» на приятную настройку, скажем 0,4 секунды. Затем я установил время перехода от любого элемента (значок звезды в Blend) к этому «скрытому» состоянию равным 0 секундам (это позволяет вышеупомянутому GoToStateAction установить «начальное» состояние без того, чтобы пользователь знал что-либо другое). Затем я установил переход из состояния «Видимый» в состояние «Скрытый» в качестве соответствующего параметра (скажем, 0,4 секунды). В основном это охватывало все основания для переходов. Ключ заключался в том, чтобы убедиться, что «переход» из «любого элемента» в «скрытое» состояние был немедленным, а затем переопределить этот немедленный переход в случае перехода из «видимого» в «скрытое» состояние наложения.

enter image description here


Установка начального VisualState для Пользовательский элемент управления

Если вы разрабатываете пользовательский элемент управления (а не UserControl) и, таким образом, определяете свой VisualStateManager в шаблоне элемента управления, приведенный выше метод (инициирование изменения VisualState на основе события Loaded), вероятно, будет не работа. Это связано с тем, что визуальное дерево вашего элемента управления (определенное в файле стиля) применяется к вашему элементу управления непосредственно перед вызовом переопределения OnApplyTemplate(), что обычно происходит после первого события Loaded. Поэтому, если вы попытаетесь инициировать изменение VisualState в ответ на событие Loaded для пользовательского элемента управления, скорее всего, ничего не произойдет. Вместо этого вам нужно будет инициировать изменение состояния в коде OnApplyTemplate() переопределения:

public class MyCustomControl : ContentControl
{
    // ... other code ....


    public MyCustomControl()
    {
        // avoid designer errors
        if (DesignerProperties.GetIsInDesignMode(this))
            return;

        Loaded += new RoutedEventHandlerMyCustomControl_Loaded);
    }

    // This probably won't be called until AFTER OnApplyTemplate() gets
    //  called, so don't expect for your control to even have a visual tree
    //  yet when your control is first being contructed at runtime.
    private void MyCustomControl_Loaded(object sender, RoutedEventArgs e)
    {

    }

    public override void OnApplyTemplate()
    {
        // Avoid Visual Studio 2010 designer exceptions
        // (Visual Studio can't handle the VisualState change at design-time)
        if (DesignerProperties.GetIsInDesignMode(this))
            return;

        base.OnApplyTemplate();

        // Now we know that the template has been applied, we have a visual tree,
        //  so state changes will work
        VisualStateManager.GoToState(this, "MyInitialState", false);
    }
}
...