Добавление нового визуального состояния в CommonStates в унаследованных элементах управления
Я наследую DatePicker, чтобы добавить поведение IsReadOnly и InputRequired. сделали соответствующие визуальные состояния для обоих в CommonStates. Причина, по которой я поместил его в CommonStates, заключается в том, что они оба являются взаимоисключающими с состоянием Normal (я проверил TextBox и это та же самая реализация для IsReadOnly).
Проблема, с которой я сталкиваюсь, заключается в том, что даже если я применяю состояние InputRequired в OnApplyTemplate, оно фактически не обновляет внешний вид. Это происходит, однако, после события MouseEnter, что приводит к выводу, что это только начальная конструкция / рендеринг.
Из изучения исходного кода элемента Control видно, что в OnPostApplyTemplate он вызывает внутренний виртуальный метод UpdateVisualState, который переопределяется в DatePicker и который применяет состояние "Normal", что означает, что мое обновление визуального состояния в OnApplyTemplate перезаписывается Control,
В качестве обходного пути я могу обновить визуальное состояние в событии Loaded, а также сделать его отдельной VisualStateGroup и иметь более сложную логику в коде, чтобы определить, применяется ли визуальное состояние (например, inputrequired не следует применять с отключенным / только для чтения), но оба они чувствуют себя немного взломанными.
Итак, мои вопросы: есть ли правильный способ для добавления новых визуальных состояний в CommonStates элемента управления таким образом? Или это лучший способ прослушать событие Loaded и обновить визуальное состояние здесь (и есть ли какие-либо ошибки в этом случае)?
Визуальные состояния:
<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 в коде позади
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);
}
}