MOnsDaR
MOnsDaR

Reputation: 8666

Switching between states in UserControls

My application shows a UserControl to add a new object. Once the object has been added, it shows the attributes of the created object.

State 1: Empty UserControl
Empty UserInput

State 2: Filled UserControl
Filled UserInput

I figured there's 2 ways I could realize something like this:

  1. Create 1 UserControl with 2 different visual states - Switch between states depending on if the control holds an instance of the object or not
  2. Create 2 UserControls without a state and show the one that is currently needed. This needs some higher level control mechanism to add/remove the right control.

What is the best practice in a case like this? What are the dis/advantages to do the one or the other? Are there other ways that I hadn't thought of yet?

Upvotes: 0

Views: 132

Answers (2)

I would create two datatemplates in UserControl.Resources and swap them with a trigger. CreateUserTemplate just has a button bound to a CreateUserCommand, or a click event. EditUserTemplate is the user editing template. Content="{Binding}" without a path uses the DataContext as the Content. If I had the exact details of your viewmodel stuff I could give you more specifics about how you're getting the content in here.

I'm also assuming that the viewmodel has a nullable UserID property.

<ContentControl
    Content="{Binding}"
    >
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <!-- Default has to go in a setter in the Style, not an 
                 attribute on the ContentControl tag -->
            <Setter 
                Property="ContentTemplate" 
                Value="{StaticResource EditUserTemplate}" 
                />
            <Style.Triggers>
                <DataTrigger Binding="{Binding UserID}" Value="{x:Null}">
                    <Setter 
                        Property="ContentTemplate" 
                        Value="{StaticResource CreateUserTemplate}" 
                        />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>

You could write a DataTemplateSelector instead but for this trivial kind of thing, I find it easier to do everything in XAML.

Upvotes: 1

AnjumSKhan
AnjumSKhan

Reputation: 9827

For this specific purpose WPF provides VisualStateManager.

<UserControl ...>
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="States">
                <VisualState x:Name="WithoutObject">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="WithoutObjectPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Visible</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="WithObjectPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Collapsed</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="WithObject">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="WithoutObjectPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Collapsed</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="WithObjectPanel" Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0:0:0">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Visible</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <StackPanel x:Name="WithoutObjectPanel" Visibility="Hidden">
            <TextBlock Text="Without object :("/>
        </StackPanel>

        <StackPanel x:Name="WithObjectPanel" Visibility="Visible">
            <TextBlock Text="With object :) !!!!"/>
        </StackPanel>
    </Grid>
</UserControl>

UserControl.cs

public partial class UserControl1 : UserControl
{
    object _anObject;
    public object AnObject 
    { 
        get { return _anObject; } 
        set { _anObject = value; 
            if(value == null) VisualStateManager.GoToState(this, "WithoutObject", true);
            else VisualStateManager.GoToState(this, "WithObject", true); 
        } 
    }
    ...
}

Upvotes: 1

Related Questions