Adding new visual state to CommonStates in inherited controls
I'm inheriting DatePicker in order to add IsReadOnly and InputRequired behaviour. have made corresponding visual states for both in CommonStates. The reason I have put it in CommonStates, is that they are both mutually exclusive with the Normal state (I checked TextBox and it the same implementation for IsReadOnly).
The problem I encounter is that even if I apply the InputRequired state in OnApplyTemplate, it does not actually update the appearance. It does however after a MouseEnter event, leading my to conclude that it is only on the initial construction/rendering.
From looking into the source code of Control I can see that in OnPostApplyTemplate, it calls an internal virtual UpdateVisualState method, which is overridden in DatePicker, and which applies the "Normal" state, meaning that my visual state update in OnApplyTemplate is overwritten by Control.
As a workaround I can update the visual state in the Loaded event, and I can also make it a separate VisualStateGroup, and have some more complex logic in the code to determine wether the apply the visual state (e.g. inputrequired should not be applied with disabled/readonly), but both of these feel a little bit hacked.
So my questions is: is there a correct way to inject new visual states in the CommonStates of a control in this way? Or is the best way to listen for the Loaded event and update visual state here (and are there any gotchas in this case)?
Visual states:
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBorderColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="ReadOnly">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="ReadOnlyVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="InputRequired">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonRequiredBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="PART_DisabledVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
UpdateVisualState in codebehind
private void UpdateVisualState(bool useTransitions = true)
{
// Common states
if (IsEnabled == false)
{
VisualStateManager.GoToState(this, "Disabled", useTransitions);
}
else if (IsMouseOver)
{
VisualStateManager.GoToState(this, "MouseOver", useTransitions);
}
else if (IsReadOnly)
{
VisualStateManager.GoToState(this, "ReadOnly", useTransitions);
}
if (CheckInputRequired())
{
VisualStateManager.GoToState(this, "Required", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
if (IsKeyboardFocusWithin)
{
VisualStateManager.GoToState(this, "Focused", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unfocused", useTransitions);
}
// Clearable states
if (IsReadOnly == false && AllowNull && SelectedDate != null)
{
VisualStateManager.GoToState(this, "Clearable", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unclearable", useTransitions);
}
// Watermark states
if (IsKeyboardFocusWithin)
{
// When control has keyboard focus, always hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else if (string.IsNullOrWhiteSpace(_datePickerTextBox?.Text) == false)
{
// If datepicker has any text, hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Watermarked", useTransitions);
}
}
wpf-controls visualstatemanager visualstates visualstategroup
add a comment |
I'm inheriting DatePicker in order to add IsReadOnly and InputRequired behaviour. have made corresponding visual states for both in CommonStates. The reason I have put it in CommonStates, is that they are both mutually exclusive with the Normal state (I checked TextBox and it the same implementation for IsReadOnly).
The problem I encounter is that even if I apply the InputRequired state in OnApplyTemplate, it does not actually update the appearance. It does however after a MouseEnter event, leading my to conclude that it is only on the initial construction/rendering.
From looking into the source code of Control I can see that in OnPostApplyTemplate, it calls an internal virtual UpdateVisualState method, which is overridden in DatePicker, and which applies the "Normal" state, meaning that my visual state update in OnApplyTemplate is overwritten by Control.
As a workaround I can update the visual state in the Loaded event, and I can also make it a separate VisualStateGroup, and have some more complex logic in the code to determine wether the apply the visual state (e.g. inputrequired should not be applied with disabled/readonly), but both of these feel a little bit hacked.
So my questions is: is there a correct way to inject new visual states in the CommonStates of a control in this way? Or is the best way to listen for the Loaded event and update visual state here (and are there any gotchas in this case)?
Visual states:
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBorderColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="ReadOnly">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="ReadOnlyVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="InputRequired">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonRequiredBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="PART_DisabledVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
UpdateVisualState in codebehind
private void UpdateVisualState(bool useTransitions = true)
{
// Common states
if (IsEnabled == false)
{
VisualStateManager.GoToState(this, "Disabled", useTransitions);
}
else if (IsMouseOver)
{
VisualStateManager.GoToState(this, "MouseOver", useTransitions);
}
else if (IsReadOnly)
{
VisualStateManager.GoToState(this, "ReadOnly", useTransitions);
}
if (CheckInputRequired())
{
VisualStateManager.GoToState(this, "Required", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
if (IsKeyboardFocusWithin)
{
VisualStateManager.GoToState(this, "Focused", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unfocused", useTransitions);
}
// Clearable states
if (IsReadOnly == false && AllowNull && SelectedDate != null)
{
VisualStateManager.GoToState(this, "Clearable", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unclearable", useTransitions);
}
// Watermark states
if (IsKeyboardFocusWithin)
{
// When control has keyboard focus, always hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else if (string.IsNullOrWhiteSpace(_datePickerTextBox?.Text) == false)
{
// If datepicker has any text, hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Watermarked", useTransitions);
}
}
wpf-controls visualstatemanager visualstates visualstategroup
add a comment |
I'm inheriting DatePicker in order to add IsReadOnly and InputRequired behaviour. have made corresponding visual states for both in CommonStates. The reason I have put it in CommonStates, is that they are both mutually exclusive with the Normal state (I checked TextBox and it the same implementation for IsReadOnly).
The problem I encounter is that even if I apply the InputRequired state in OnApplyTemplate, it does not actually update the appearance. It does however after a MouseEnter event, leading my to conclude that it is only on the initial construction/rendering.
From looking into the source code of Control I can see that in OnPostApplyTemplate, it calls an internal virtual UpdateVisualState method, which is overridden in DatePicker, and which applies the "Normal" state, meaning that my visual state update in OnApplyTemplate is overwritten by Control.
As a workaround I can update the visual state in the Loaded event, and I can also make it a separate VisualStateGroup, and have some more complex logic in the code to determine wether the apply the visual state (e.g. inputrequired should not be applied with disabled/readonly), but both of these feel a little bit hacked.
So my questions is: is there a correct way to inject new visual states in the CommonStates of a control in this way? Or is the best way to listen for the Loaded event and update visual state here (and are there any gotchas in this case)?
Visual states:
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBorderColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="ReadOnly">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="ReadOnlyVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="InputRequired">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonRequiredBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="PART_DisabledVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
UpdateVisualState in codebehind
private void UpdateVisualState(bool useTransitions = true)
{
// Common states
if (IsEnabled == false)
{
VisualStateManager.GoToState(this, "Disabled", useTransitions);
}
else if (IsMouseOver)
{
VisualStateManager.GoToState(this, "MouseOver", useTransitions);
}
else if (IsReadOnly)
{
VisualStateManager.GoToState(this, "ReadOnly", useTransitions);
}
if (CheckInputRequired())
{
VisualStateManager.GoToState(this, "Required", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
if (IsKeyboardFocusWithin)
{
VisualStateManager.GoToState(this, "Focused", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unfocused", useTransitions);
}
// Clearable states
if (IsReadOnly == false && AllowNull && SelectedDate != null)
{
VisualStateManager.GoToState(this, "Clearable", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unclearable", useTransitions);
}
// Watermark states
if (IsKeyboardFocusWithin)
{
// When control has keyboard focus, always hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else if (string.IsNullOrWhiteSpace(_datePickerTextBox?.Text) == false)
{
// If datepicker has any text, hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Watermarked", useTransitions);
}
}
wpf-controls visualstatemanager visualstates visualstategroup
I'm inheriting DatePicker in order to add IsReadOnly and InputRequired behaviour. have made corresponding visual states for both in CommonStates. The reason I have put it in CommonStates, is that they are both mutually exclusive with the Normal state (I checked TextBox and it the same implementation for IsReadOnly).
The problem I encounter is that even if I apply the InputRequired state in OnApplyTemplate, it does not actually update the appearance. It does however after a MouseEnter event, leading my to conclude that it is only on the initial construction/rendering.
From looking into the source code of Control I can see that in OnPostApplyTemplate, it calls an internal virtual UpdateVisualState method, which is overridden in DatePicker, and which applies the "Normal" state, meaning that my visual state update in OnApplyTemplate is overwritten by Control.
As a workaround I can update the visual state in the Loaded event, and I can also make it a separate VisualStateGroup, and have some more complex logic in the code to determine wether the apply the visual state (e.g. inputrequired should not be applied with disabled/readonly), but both of these feel a little bit hacked.
So my questions is: is there a correct way to inject new visual states in the CommonStates of a control in this way? Or is the best way to listen for the Loaded event and update visual state here (and are there any gotchas in this case)?
Visual states:
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Stroke">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonHoverBorderColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="ReadOnly">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="ReadOnlyVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
<VisualState x:Name="InputRequired">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CommonRequiredBackgroundColor}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation To="1" Duration="0" Storyboard.TargetName="PART_DisabledVisual" Storyboard.TargetProperty="Opacity"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
UpdateVisualState in codebehind
private void UpdateVisualState(bool useTransitions = true)
{
// Common states
if (IsEnabled == false)
{
VisualStateManager.GoToState(this, "Disabled", useTransitions);
}
else if (IsMouseOver)
{
VisualStateManager.GoToState(this, "MouseOver", useTransitions);
}
else if (IsReadOnly)
{
VisualStateManager.GoToState(this, "ReadOnly", useTransitions);
}
if (CheckInputRequired())
{
VisualStateManager.GoToState(this, "Required", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
if (IsKeyboardFocusWithin)
{
VisualStateManager.GoToState(this, "Focused", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unfocused", useTransitions);
}
// Clearable states
if (IsReadOnly == false && AllowNull && SelectedDate != null)
{
VisualStateManager.GoToState(this, "Clearable", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unclearable", useTransitions);
}
// Watermark states
if (IsKeyboardFocusWithin)
{
// When control has keyboard focus, always hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else if (string.IsNullOrWhiteSpace(_datePickerTextBox?.Text) == false)
{
// If datepicker has any text, hide watermark.
VisualStateManager.GoToState(this, "Unwatermarked", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Watermarked", useTransitions);
}
}
wpf-controls visualstatemanager visualstates visualstategroup
wpf-controls visualstatemanager visualstates visualstategroup
asked Nov 14 '18 at 12:51
sondergardsondergard
2,3211020
2,3211020
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53300684%2fadding-new-visual-state-to-commonstates-in-inherited-controls%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53300684%2fadding-new-visual-state-to-commonstates-in-inherited-controls%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown