【问题标题】:Separate event in control单独控制事件
【发布时间】:2026-02-26 02:10:01
【问题描述】:

我想知道是否可以让控件中的单个组件具有事件。例如,我创建了自己的控件,并且使用 VisualStateManager 我能够处理为整个控件触发的多个事件,我只希望控件中的切换按钮触发鼠标悬停事件。目前,鼠标悬停的控件的任何区域都会触发鼠标悬停,这会破坏我想要获得的色彩动画效果,我希望只有当切换按钮鼠标悬停时才会发生色彩动画,我的控件有一个 contentpresent 允许其他内容,我不希望那件作品触发事件。

我在下面的 generic.xaml 文件中讨论的示例。

<Style TargetType="local:MyControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyControl">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="ViewStates">

                            <VisualState x:Name="Expanded">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="ContentScaleTransform" Storyboard.TargetProperty="ScaleY" To="1" Duration="0"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Collapsed">
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="ContentScaleTransform" Storyboard.TargetProperty="ScaleY" To="0" Duration="0"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <!-- This fires for any part of the control, is it possible to just create a mouseover for the ToggleButton below? -->
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" Background="{TemplateBinding Background}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <Grid Margin="3">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <ToggleButton Grid.Column="0" Content="{TemplateBinding HeaderContent}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"  RenderTransformOrigin="0.5,0.5" Margin="1" x:Name="ExpandCollapseButton">

                                </ToggleButton>
                            </Grid>
                            <ContentPresenter Grid.Row="1" Margin="5" Content="{TemplateBinding Content}" x:Name="Content">
                                <ContentPresenter.RenderTransform>
                                    <ScaleTransform x:Name="ContentScaleTransform"/>
                                </ContentPresenter.RenderTransform>
                            </ContentPresenter>
                        </Grid>
                    </Border>

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【问题讨论】:

    标签: c# silverlight mouseover visualstatemanager


    【解决方案1】:

    Bob,您可以像这样从您的班级访问切换按钮:

    ToggleButton myToggleButton = GetTemplateChild("toggleButton") as ToggleButton;

    在课堂上创建您想要的活动。您可能需要覆盖 OnApplyTemplate 方法并在那里创建您的事件,我仍在研究这部分并且还没有完全理解它,您将不得不使用它。我确实覆盖了我的 OnApplyTemplate,它对我有用。

    ToggleButton myToggleButton;
    public override void OnApplyTemplate() {
        base.OnApplyTemplate();
        myToggleButton = GetTemplateChild("toggleButton") as ToggleButton;
        myToggleButton.MouseEnter += new MouseEventHandler(myToggleButton_MouseEnter);
    }
    void myToggleButton_MouseEnter(object sender, MouseEventArgs e) {
            VisualStateManager.GoToState(this, "MouseEnter", true);
        }
    

    还要确保在顶部设置您的模板:

    [TemplateVisualState(Name = "MouseEnter", GroupName = "ViewStates")]
    

    VisualState 可以存在于您设置其他视觉状态的 generic.xaml 文件中,而不必位于内部 ToggleButton 中。

    <VisualState x:Name="MouseEnter">
        <Storyboard>
            <ColorAnimation Storyboard.TargetName="toggleButton" Storyboard.TargetProperty="(ToggleButton.SomeProperty).(SolidColorBrush.Color)" To="SomeColor"/>
        </Storyboard>
    </VisualState>
    

    【讨论】:

      【解决方案2】:

      首先让我们的术语正确,您不是在谈论“事件”,而是在谈论“视觉状态”。 “MouseOver”是一种视觉状态。它由控件内的代码负责决定控件处于哪种视觉状态。

      控件中的代码通常会使用 MouseEnter 和 MouseLeave 事件来设置一个布尔值以指示鼠标在控件上,然后调用一些 UpdateStates 方法,开发人员将在其中包含逻辑以确定控​​件的哪些视觉状态目前应该在。

      在您的情况下,而不是使用控件 MouseEnterMouseLeave 事件,而是将这些处理程序附加到您的内部 ToggleButton

      【讨论】:

      • 您的意思是向内部切换按钮添加视觉状态?
      • @Bob:不,我的意思是您需要编写代码并将该代码作为事件处理程序附加到 ToggleButton 的 MouseEnter 和 MouseLeave 事件。这段代码将使用VisualStateManager.GotoState 来指定您的控件应该处于什么视觉状态。我很好奇这种混乱是如何产生的,MyControl 是从哪个基类派生而来的?