Search code examples
silverlightxamlsilverlight-4.0visualstatemanagersilverlightcontrols

How to dynamically change the Visual Behavior of a control in XAML


How to change the visual behavior dynamically through VisualStateManager without changing visual structure (Appearance) of an existing control.

I have a scenario where i have a DataTemplate defined in ItemsControl to generate list of CheckBoxes and associated TextBoxes.

XAML:

<DataTemplate>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="0.2*" />
      <ColumnDefinition Width="0.8*" />
    </Grid.ColumnDefinitions>                        
    <CheckBox Grid.Column="0" x:Name="chkBox" />
    <TextBox Grid.Column="1" x:Name="txtBox" />
  </Grid>
</DataTemplate>

I wanted to hide associated TextBoxes initially but later when CheckBox is Checked the associated TextBox should appear. So i wrote VisualStateManager but i don't have exact idea how can i use it or achieve the desired behavior.

VisualStateManager:

<vsm:VisualStateManager.VisualStateGroups>
  <vsm:VisualStateGroup x:Name="CheckStates">
    <vsm:VisualState x:Name="Checked">
      <Storyboard>
        <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="txtBox" Storyboard.TargetProperty="Visibility">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <vsm:Visibility>Collapsed</vsm:Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
         </ObjectAnimationUsingKeyFrames>
      </Storyboard>
      </vsm:VisualState>
      <vsm:VisualState x:Name="Unchecked">
        <Storyboard>
          <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="txtBox" Storyboard.TargetProperty="Visibility">
          <DiscreteObjectKeyFrame KeyTime="0">
            <DiscreteObjectKeyFrame.Value>
              <vsm:Visibility>Visible</vsm:Visibility>
            </DiscreteObjectKeyFrame.Value>
          </DiscreteObjectKeyFrame>
        </ObjectAnimationUsingKeyFrames>
      </Storyboard>
    </vsm:VisualState>
  </vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>

Solution

  • I don't know if you can target another control's properties with Visual States - it may be possible, but I'm not sure if you can.

    Have you tried using Interactivity?

    For this to work you need a reference to the System.Windows.Interactivity DLL (not sure where that is located - it might come with Microsoft Expression Blend/Studio). You also need to import these:

    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"             
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    

    And then this code should work to show the textbox:

    <CheckBox Grid.Column="0" x:Name="chkBox">
      <i:Interaction.Triggers>
        <i:EventTrigger EventName="Checked">
           <ei:ChangePropertyAction TargetObject="{Binding ElementName=txtBox}" PropertyName="Visibility" Value="Visible"/>
       </i:EventTrigger>
     </i:Interaction.Triggers>
    </Checkbox>
    

    and to change it back:

    <i:EventTrigger EventName="UnChecked">
       <ei:ChangePropertyAction TargetObject="{Binding ElementName=txtBox}" PropertyName="Visibility" Value="Collapsed"/>
    </i:EventTrigger>
    

    Both triggers should be inside the checkbox < checkbox >HERE< /checkbox >. This code is not tested, so it may not be exactly correct. If it doesn't work, just search on ChangePropertyAction and you'll find better examples than this one. I'm not sure how this will react inside of an itemscontrol... but I believe it will work.