2017-12-08 3 views
0

VisualStateManager를 사용하는 사용자 정의 컨트롤에 문제가 있습니다.VisualState의 초기 값 설정

상태 전환은 예상대로 작동하지만 초기 상태 설정 방법을 이해하지 못합니다.

나는이 문제를 설명하기 위해 완전한 예를 제시했다. 이 예제에서는 ButtonBase를 기반으로하는 사용자 지정 컨트롤을 사용합니다.

컨트롤에는 두 개의 상태 "확인 됨"과 "선택 취소됨"이있는 VisualState 그룹이 있습니다. 이것은 컨트롤의 C# 코드입니다.

using System.Windows; 
using System.Windows.Controls.Primitives; 

namespace VisualStateTest 
{ 
    [TemplateVisualStateAttribute(Name = "Checked",   GroupName = "CheckStates")] 
    [TemplateVisualStateAttribute(Name = "Unchecked",   GroupName = "CheckStates")] 
    public class CustomButton : ButtonBase 
    { 
    public static readonly DependencyProperty IsCheckedProperty = 
     DependencyProperty.Register ("IsChecked", 
             typeof(bool), 
             typeof(CustomButton), 
             new FrameworkPropertyMetadata (false, 
                     FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
                     OnCheckedChanged)) ; 

    static CustomButton() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomButton), new FrameworkPropertyMetadata(typeof(CustomButton))); 
    } 

    public bool IsChecked 
    { 
     get { return (bool)GetValue(IsCheckedProperty); } 
     set { SetValue(IsCheckedProperty, value); } 
    } 

    public static void OnCheckedChanged (DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var button = d as CustomButton ; 

     if ((bool)e.NewValue) 
     { 
     VisualStateManager.GoToState(button, "Checked", true); 
     } 
     else 
     { 
     VisualStateManager.GoToState(button, "Unchecked", true); 
     } 
    } 

    } 
} 

컨트롤 템플릿은 IsChecked 속성이 설정되면 왼쪽과 위쪽에 음영을 표시합니다.

(나는 디자인이 가난한 것을 알고 있지만,이 그래픽 디자인에 대한 질문이 없습니다.)

이것은 컨트롤 템플릿입니다 : 나는 뷰 모델로 정의한이 테스트에 대한

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:VisualStateTest"> 

    <Style TargetType="{x:Type local:CustomButton}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
     <ControlTemplate TargetType="{x:Type local:CustomButton}"> 

      <Border x:Name="outerborder" 
        Background="{TemplateBinding Background}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"> 

      <VisualStateManager.VisualStateGroups> 

       <VisualStateGroup x:Name="CheckStates"> 

       <VisualState x:Name="Checked"> 
        <Storyboard> 

        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" 
               Storyboard.TargetName="topshadow" 
               Storyboard.TargetProperty="(UIElement.Opacity)"> 
         <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1.0"/> 
        </DoubleAnimationUsingKeyFrames> 

        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" 
               Storyboard.TargetName="leftshadow" 
               Storyboard.TargetProperty="(UIElement.Opacity)"> 
         <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="1.0"/> 
        </DoubleAnimationUsingKeyFrames> 

        </Storyboard> 
       </VisualState> 

       <VisualState x:Name="Unchecked"> 
        <Storyboard> 

        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" 
               Storyboard.TargetName="topshadow" 
               Storyboard.TargetProperty="(UIElement.Opacity)"> 
         <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/> 
        </DoubleAnimationUsingKeyFrames> 

        <DoubleAnimationUsingKeyFrames BeginTime="0:0:0" 
               Storyboard.TargetName="leftshadow" 
               Storyboard.TargetProperty="(UIElement.Opacity)"> 
         <SplineDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/> 
        </DoubleAnimationUsingKeyFrames> 

        </Storyboard> 
       </VisualState> 

       </VisualStateGroup> 

      </VisualStateManager.VisualStateGroups> 

      <Grid Cursor="Hand" ClipToBounds="True"> 

       <Grid.RowDefinitions> 
       <RowDefinition Height="10"/> 
       <RowDefinition Height="*"/> 
       </Grid.RowDefinitions> 
       <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="10"/> 
       <ColumnDefinition Width="*"/> 
       </Grid.ColumnDefinitions> 

       <Rectangle x:Name="lineargradient" 
         Grid.RowSpan="2" Grid.ColumnSpan="2" 
         Stroke="#7F000000" 
         StrokeThickness="0"> 
       <Rectangle.Fill> 
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> 
        <GradientStop Color="#20808080"/> 
        <GradientStop Color="#008A8A8A" Offset="0.5"/> 
        <GradientStop Color="#20000000" Offset="1"/> 
        </LinearGradientBrush> 
       </Rectangle.Fill> 
       </Rectangle> 

       <ContentPresenter HorizontalAlignment="Center" 
           x:Name="contentPresenter" 
           Grid.RowSpan="2" Grid.ColumnSpan="2" 
           VerticalAlignment="Center" /> 

       <Rectangle x:Name="topshadow" Fill="#40000000" Grid.Row="0" Grid.ColumnSpan="2" Opacity="0"> 
       <Rectangle.Effect> 
        <BlurEffect Radius="3"/> 
       </Rectangle.Effect> 
       </Rectangle> 
       <Rectangle x:Name="leftshadow" Fill="#40000000" Grid.Row="1" Grid.Column="0" Opacity="0"> 
       <Rectangle.Effect> 
        <BlurEffect Radius="3"/> 
       </Rectangle.Effect> 
       </Rectangle> 

      </Grid> 

      </Border> 

     </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
    </Style> 
</ResourceDictionary> 

두 개의 부울 속성 (Option1 및 Option2). 속성 중 하나에 초기 값 false가 있고 다른 하나는 true입니다.

두 개의 Custom Properties 컨트롤에 연결된 두 개의 CustomButton 컨트롤과 동일한 속성에 연결된 두 개의 확인란이있는 주 창이 있습니다. 사용자 정의 버튼 또는 중 하나를 클릭

이 뷰 모델의 전체 코드입니다 ...

using System; 
using System.ComponentModel; 
using System.Windows.Input; 

namespace VisualStateTest 
{ 
    public class ViewModel : INotifyPropertyChanged 
    { 
    // Events for INotifyPropertyChanged 
    public event PropertyChangedEventHandler PropertyChanged; 

    private bool  _option1 = false ; 
    private bool  _option2 = true ; 

    public ICommand Notify1Command { get; private set; } 
    public ICommand Notify2Command { get; private set; } 

    public ViewModel() 
    { 
     Notify1Command = new RelayCommand (new Action<object>(Execute_Notify1Command)); 
     Notify2Command = new RelayCommand (new Action<object>(Execute_Notify2Command)); 
    } 

    public bool Option1 
    { 
     get { return _option1 ; } 
     set 
     { 
     _option1 = value ; 
     NotifyPropertyChanged ("Option1") ; 
     } 
    } 

    public bool Option2 
    { 
     get { return _option2 ; } 
     set 
     { 
     _option2 = value ; 
     NotifyPropertyChanged ("Option2") ; 
     } 
    } 

    public void Execute_Notify1Command (object value) 
    { 
     Option1 = !Option1 ; 
    } 

    public void Execute_Notify2Command (object value) 
    { 
     Option2 = !Option2 ; 
    } 

    private void NotifyPropertyChanged (String propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
     this.PropertyChanged (this, new PropertyChangedEventArgs(propertyName)) ; 
     } 
    } 
    } 
} 

메인 창 ... 프로그램이 시작되면

<Window x:Class="VisualStateTest.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:VisualStateTest" 
     mc:Ignorable="d" 
     WindowStartupLocation="CenterScreen" 
     Title="MainWindow" Height="350" Width="525"> 

    <Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="*"/> 
     <RowDefinition Height="Auto"/> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="*"/> 
    </Grid.ColumnDefinitions> 

    <local:CustomButton Grid.Row="0" Grid.Column="0" 
         Command="{Binding Notify1Command}" 
         IsChecked="{Binding Option1, Mode=OneWay}" 
         Content="Option 1" 
         Margin="20"/> 

    <local:CustomButton Grid.Row="0" Grid.Column="1" 
         Command="{Binding Notify2Command}" 
         IsChecked="{Binding Option2, Mode=OneWay}" 
         Content="Option 2" 
         Margin="20"/> 

    <CheckBox Grid.Row="1" Grid.Column="0" 
       IsChecked="{Binding Option1}" 
       Content="Option 1" 
       Margin="20 5"/> 

    <CheckBox Grid.Row="1" Grid.Column="1" 
       IsChecked="{Binding Option2}" 
       Content="Option 2" 
       Margin="20 5"/> 

    </Grid> 

</Window> 

, 체크 박스는 옵션을 토글하고 그림자 효과를 표시하거나 숨 깁니다. 이 그것이 '정상'상태의 모습입니다

:

enter image description here

프로그램이 시작될 때 문제입니다. Option2가 true로 초기화되고 VisualStateManager.GoToState 함수가 호출되었지만 그림자 효과는 표시되지 않습니다.

이것은 시작시의 모습입니다.

enter image description here

오른쪽에있는 체크 박스에 해당 옵션이 사실을 나타냅니다 만, 그림자 효과는 존재하지 않습니다.

저는 퍼즐의 작은 조각 하나가 빠졌다고 확신합니다. 도움이된다면 샘플 프로그램을 업로드 할 수 있습니다.

너무 자세히 설명해 주시면 죄송합니다.

답변

0

나는 대답을 찾았다 고 생각합니다.

내 사용자 지정 컨트롤에서 OnApplyTemplate() 함수를 재정의해야합니다.나는 다음과 같은 기능을 가진 CustomButton 클래스의 코드를 확장 한 : 나는 Microsoft documentation를 읽어에서이 정보를 발견

public override void OnApplyTemplate() 
{ 
    base.OnApplyTemplate(); 

    if (IsChecked) 
    { 
    VisualStateManager.GoToState(this, "Checked", true); 
    } 
    else 
    { 
    VisualStateManager.GoToState(this, "Unchecked", true); 
    } 
} 

. OnApplyTemplate 메서드를 참조하면 상태는

입니다. ControlTemplate의 FrameworkElement가 컨트롤에서 사용할 수있는 가장 빠른 버전입니다.