简体   繁体   English

如何刷新VisualStateManager的“聚焦” VisualState的样式效果?

[英]How to refresh style effects of 'Focused' VisualState of VisualStateManager?

I have the ListBoxItem's style as follows and a problem with loosing 'Focused' visual effects when the listBoxItem remains in mentioned VisualState. 我具有ListBoxItem的样式,如下所示,并且当listBoxItem保留在提到的VisualState中时,失去了“焦点”视觉效果的问题。 How to force appropriate visual effects to appear on 'Focused' ListBoxItem? 如何强制适当的视觉效果出现在“关注的” ListBoxItem上?

The scenario to achieve a bug: 实现错误的场景:

1) Click the ListBoxItem -> it receive the focus and styles(ok). 1)单击ListBoxItem->它获得焦点和样式(确定)。

2) Move the pointer over this ListBoxItem -> it's still focused and receive the styles for 'MouseOver' (it is within a separate VisualStateGroup 'CommonStates' as suggested here: https://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem%28v=vs.95%29.aspx )(ok). 2)将指针移到该ListBoxItem上->它仍然聚焦并接收'MouseOver'的样式(如此处建议的,它位于单独的VisualStateGroup'CommonStates'中: https : //msdn.microsoft.com/zh-cn/library /system.windows.controls.listboxitem%28v=vs.95%29.aspx )(确定)。

3) Make the mouse leave the ListBoxItem's bounds -> it loses the style for MouseOver(ok). 3)使鼠标离开ListBoxItem的边界->它失去MouseOver(ok)的样式。

4) Now, the ListBoxItem is in 'Normal' state of 'CommonStates' and is also 'Focused', but doesn't have the stylish for 'Focused'(it is my problem). 4)现在,ListBoxItem处于“ CommonStates”的“正常”状态,并且也是“关注”状态,但是没有针对“关注”的时尚外观(这是我的问题)。

5) Attampting to click this ListBoxItem has no effect 5)尝试单击此ListBoxItem无效

Could you give me some advice, how to deal with it? 您能给我一些建议,如何处理?

I'm using Silverlight, so triggers are forbidden 4 me. 我正在使用Silverlight,所以禁止触发器4我。

Here is my style: 这是我的风格:

    <Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
    <Setter Property="HorizontalContentAlignment" Value="Center" />
    <Setter Property="HorizontalAlignment" Value="Left" />
    <Setter Property="ContentControl.Foreground" Value="{StaticResource ViewModeButtonForeground}" />
    <Setter Property="Focusable" Value="True" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Border x:Name="RootElement">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="(ContentControl.Foreground)">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource ViewModeButtonForeground}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="CheckOuterBorder" Storyboard.TargetProperty="BorderBrush">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource ViewModeButtonOuterBorder_MouseOver}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="CheckOuterBorder" Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource ViewModeButtonBackground_MouseOver}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="(ContentControl.Foreground)">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource ViewModeButtonForeground_Focused}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="CheckOuterBorder" Storyboard.TargetProperty="BorderBrush">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource ViewModeButtonOuterBorder_Focused}" />
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="CheckOuterBorder" Storyboard.TargetProperty="Background">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{StaticResource ViewModeButtonBackground_Normal}" />
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unfocused"></VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid>
                        <Border x:Name="CheckOuterBorder" CornerRadius="2" BorderThickness="1" BorderBrush="Transparent" Background="Transparent">
                        </Border>
                        <Grid x:Name="GridContent" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Width="Auto">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <Image Grid.Column="0" Width="16" Height="16" VerticalAlignment="Center" HorizontalAlignment="Left" Source="{Binding ImgSource, Mode=OneWay}"/>
                            <ContentControl x:Name="Content" Grid.Column="1" Margin="3,0,0,0" Foreground="{TemplateBinding Foreground}" Content="{Binding Title}" ContentTemplate="{TemplateBinding ContentTemplate}"  VerticalAlignment="Center" Width="Auto"/>
                        </Grid>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style x:Key="ViewModeSelectionListBoxStyle" TargetType="ListBox">
    <Setter Property="BorderThickness" Value="0" />
    <Setter Property="IsTabStop" Value="True" />
    <Setter Property="ItemContainerStyle" Value="{StaticResource ListBoxItemStyle1}" />
    <Setter Property="Focusable" Value="True" />
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>    

If I change my VisualStateGroup from 'FocusStates' into SelectionStates it behaves the same. 如果我将VisualStateGroup从“ FocusStates”更改为SelectionStates,则其行为相同。 I want it to be associated with focus rather than the selection, because there can be visual mismatch in the UI if user clicks somewhere and another control will have similar border too. 我希望它与焦点而不是选择相关联,因为如果用户单击某处并且另一个控件也将具有相似的边框,则UI中可能存在视觉不匹配。

BTW: On another msdn site I've read: 'The control is always in one state for each VisualStateGroup that is defined in its ControlTemplate and only leaves a state when it goes into another state from the same VisualStateGroup.' 顺便说一句:在另一个msdn站点上,我读到:“对于在其ControlTemplate中定义的每个VisualStateGroup,该控件始终处于一种状态,并且只有当它从同一VisualStateGroup进入另一种状态时,才保留该状态。” From my code-behind I have ensured that the listBoxItem has still the focus on. 从我的代码背后,我确保了listBoxItem仍然是重点。 Besides, I was trying to enforce going to that state after the mouse leaving my listBoxItem – with no results (simplifying: ActiveViewDefinition is an replacement for the actually focused item in the listbox): 此外,我试图在鼠标离开我的listBoxItem之后强制进入该状态-无结果(简化:ActiveViewDefinition替代了listbox中实际关注的项目):

        private void It_MouseLeave(object sender, MouseEventArgs e)
        {
            ListBoxItem lbItem = sender as System.Windows.Controls.ListBoxItem;
            if (lbItem != null && lbItem.Content == ActiveViewDefinition)
            {
                VisualStateManager.GoToState(lbItem, "Focused", true);
            }
        }

Easy. 简单。 Your VisualStates from different groups manipulate the same properties of the same elements. 来自不同组的VisualState操纵相同元素的相同属性。 You always need to have separate elements (or use separate properties of shared elements) to indicate states from different groups, otherwise they will naturally clash and mess with each others settings (as you have observed). 您始终需要使用单独的元素(或使用共享元素的单独属性)来指示不同组中的状态,否则它们自然会与其他设置发生冲突和混乱(如您所观察到的)。

An example in pseudo-xaml: 伪xaml中的示例:

<VisualStateGroup x:Name="CommonStates">
    <VisualState x:Name="Normal"><NoChange/></VisualState>
    <VisualState x:Name="MouseOver"><Change What="TheBorder" Color="Red"/></VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
    <VisualState x:Name="Focused"><Change What="TheBorder" Color="Blue"/></VisualState>
</VisualStateGroup>

<Border x:Name="TheBorder" Color="Transparent"/>

Initially the border is Transparent. 最初,边框是透明的。 Now what happens when we move the mouse over the Border? 现在,当我们将鼠标移到边框上时会发生什么? The mouseOver state changes it to red. mouseOver状态将其更改为红色。 Now we click our control (let's assume it gets selected and can be focused). 现在,我们单击控件(假设它已被选中并且可以集中显示)。 The focusState changes it to blue. focusState将其更改为蓝色。 Now we move the mouse away from it. 现在我们将鼠标移开。 The normalState changes it to its initial state: Transparent. normalState将其更改为其初始状态:透明。 The focusState effect is lost. focusState效果丢失。

Let's have a look at the modified example: 让我们看一下修改后的示例:

<VisualStateGroup x:Name="CommonStates">
    <VisualState x:Name="Normal"><NoChange/></VisualState>
    <VisualState x:Name="MouseOver"><Change What="TheMouseoverBorder" Color="Red"/></VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
    <VisualState x:Name="Focused"><Change What="TheFocusBorder" Color="Blue"/></VisualState>
</VisualStateGroup>

<Border x:Name="TheFocusBorder" Color="Transparent"/>
<Border x:Name="TheMouseoverBorder" Color="Transparent"/>

Initially both borders are transparent. 最初,两个边界都是透明的。 Now what happens when we move the mouse over them? 现在,当我们将鼠标移到它们上方时会发生什么? The mouseOver state changes the TheMouseoverBorder to red. mouseOver状态将TheMouseoverBorder更改为红色。 Now we click our control (let's assume it gets selected and can be focused). 现在,我们单击控件(假设它已被选中并且可以集中显示)。 The focusState changes TheFocusBorder to blue. focusState将TheFocusBorder更改为蓝色。 Now we move the mouse away from it. 现在我们将鼠标移开。 The normalState changes TheMouseoverBorder back to transparent. normalState将TheMouseoverBorder更改回透明状态。 The focusState is still visible because the TheFocusBorder is uneffected by other state changes and still blue. focusState仍然可见,因为TheFocusBorder不受其他状态更改的影响,并且仍为蓝色。

[Edit] [编辑]

If you absolutely must modify the same property of the same element from separate VisualStateGroups, you can either use some kind of aggregator that has a resulting output property, or use some kind of fallthrough mechanism. 如果绝对必须从单独的VisualStateGroups修改同一元素的相同属性,则可以使用某种具有结果输出属性的聚合器,也可以使用某种穿透机制。

I can think of several possible solutions to modify the same Foreground property from separate VisualStateGroups. 我可以想到几种从单独的VisualStateGroups修改同一Foreground属性的解决方案。 You can try those and see if they work. 您可以尝试一下,看看它们是否有效。

Fallthrough 跌倒

<VisualState x:Name="MouseOver"><Change What="Outer" ForegroundColor="Red"/></VisualState>
...
<VisualState x:Name="Focused"><Change What="Inner" ForegroundColor="Blue"/></VisualState>

<ContentControl x:Name="Outer">
    <ContentControl x:Name="Inner">
    ...
    </ContentControl>
</ContentControl>

In theory: if both states are active the inner state wins (focused: blue), if only the mouseover state is active the property is not explicitly set on the inner and will be inherited from the outer. 理论上:如果两个状态都处于活动状态,则内部状态将获胜(焦点:蓝色),如果仅鼠标悬停状态处于活动状态,则该属性不会在内部显式设置,而是将从外部继承。 Not tested. 未经测试。 Try it. 试试吧。

Aggregator 聚合器

<VisualState x:Name="MouseOver"><Change What="Aggregator" MouseOverColor="Red"/></VisualState>
...
<VisualState x:Name="Focused"><Change What="Aggregator" FocusedColor="Blue"/></VisualState>

<InvisibleAggregator x:Name="Aggregator"/>
<ContentControl Foreground="{Binding ElementName=Aggregator, Path=EffectiveColor}"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM