VisualStates в Silverlight или управление состоянием из ViewModel (MVVM) продолжение

WPF, MVVM, Silverlight | создано: 08.01.2011 | опубликовано: 08.01.2011 | обновлено: 13.01.2024 | просмотров: 4517

В прошлой статье я рассказал как можно управлять состоянием представления (View) из кода (ViewModel). В этой статье хочется показать еще один способ.

Речь пойдет на этот раз об Expression Studio 4.0, которая не так давно увидела свет, привнеся с собой кучу разных полезных нововведений и улучшений. Одним из таких нововведений стал класс, а точнее элемент управления поведением (behavior) который называется DataStateBehavior.

Этот класс позволяет декларативно (в XAML) выполнить привязку (binding) к визуальному представлению (View) из модели представления (ViewModel).

Для начала надо подключить необходимые для работы namespace

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

Пусть есть ViewModel, который имеет следующий вид... Хотя нет. На этот раз буду использовать библиотеки Prism вместо свой библиотеки. Просто для разнообразия. Добавляем сборку Microsoft.Practices.Prism к проекту, чтобы реализовать паттерн MVVM. Подключим необходимые простраства имен:

using Microsoft.Practices.Prism.ViewModel;
using Microsoft.Practices.Prism.Commands;

А теперь приведу код простейшего класса:

public class MainPageViewModel: NotificationObject
{
    #region свойство IsRectangle

    /// <summary>
    /// поле для хранения значений свойства <see cref="IsRectangle"/>
    /// </summary>
    private bool isRectangle;

    /// <summary>
    /// свойство информирует о видимости квадрата.
    /// </summary>
    public bool IsRectangle
    {
        get
        {
            return isRectangle;
        }
        set
        {
            isRectangle = value;
            RaisePropertyChanged(() => this.IsRectangle);
        }
    }

    #endregion свойство IsRectangle

    #region команда ChangeStateCommand

    /// <summary>
    /// Команда ChangeStateCommand
    /// </summary>
    public DelegateCommand ChangeStateCommand
    {

        get
        {
            return new DelegateCommand(() => this.ChangeStateCommandExecute());
        }
    }

    /// <summary>
    /// Процедура выполняет команды ChangeStateCommand
    /// </summary>
    private void ChangeStateCommandExecute()
    {
        // выполнение команды ChangeState
        this.IsRectangle = !this.IsRectangle;
    }
    #endregion // end команда ChangeStateCommand
}

А теперь подключим этот ViewModel к нашему представлению. Подключение можно осуществить многими способами, а я на этот раз выберу способ, который "дружит" с понятием blendability. В файле MainPage.xaml потребуется добавить namespace текущего приложения:

xmlns:vm="clr-namespace:SilverlightApplication3"

А теперь используем его:

<UserControl.DataContext>
      <vm:MainPageViewModel />
</UserControl.DataContext>

Настал черед показать как выглядят два состояния, которые мы будем менять при нажатии на (Button) кнопку или CheckBox:

<VisualStateManager.VisualStateGroups>
   <VisualStateGroup
      x:Name="VisualStateGroup">
      <VisualStateGroup.Transitions>
         <VisualTransition
            GeneratedDuration="0:0:0.4" />
      </VisualStateGroup.Transitions>
      <VisualState
         x:Name="EllipseState" />
      <VisualState
         x:Name="RectangleState">
         <Storyboard>
            <ObjectAnimationUsingKeyFrames
               Storyboard.TargetProperty="(UIElement.Visibility)"
               Storyboard.TargetName="rectangle">
               <DiscreteObjectKeyFrame
                  KeyTime="0">
                  <DiscreteObjectKeyFrame.Value>
                     <Visibility>Visible</Visibility>
                  </DiscreteObjectKeyFrame.Value>
               </DiscreteObjectKeyFrame>
            </ObjectAnimationUsingKeyFrames>
            <DoubleAnimation
               Duration="0"
               To="-214.5"
               Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
               Storyboard.TargetName="ellipse"
               d:IsOptimized="True" />
            <DoubleAnimation
               Duration="0"
               To="-214.5"
               Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
               Storyboard.TargetName="rectangle"
               d:IsOptimized="True" />
            <ObjectAnimationUsingKeyFrames
               Storyboard.TargetProperty="(UIElement.Visibility)"
               Storyboard.TargetName="ellipse">
               <DiscreteObjectKeyFrame
                  KeyTime="0">
                  <DiscreteObjectKeyFrame.Value>
                     <Visibility>Visible</Visibility>
                  </DiscreteObjectKeyFrame.Value>
               </DiscreteObjectKeyFrame>
            </ObjectAnimationUsingKeyFrames>
         </Storyboard>
      </VisualState>
   </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

 Названия состояний, как видно из кода: EllipseState и RectangleState. А вот теперь то, ради чего была задумана эта статья. Воспользуемся классом DataStateBehavior, который довершит начатое:

<i:Interaction.Behaviors>
         <ei:DataStateBehavior
            Binding="{Binding IsRectangle}"
            Value="True"
            TrueState="RectangleState"
            FalseState="EllipseState" />
</i:Interaction.Behaviors>

Этот класс выбирает (устанавливает) одно из двух состояний на основании значения (value), выбранного  свойства (IsRectangle). Вот и всё.