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