【问题标题】:UserControl hosted in Panel面板中托管的用户控件
【发布时间】:2012-08-22 09:10:27
【问题描述】:

我花了很多时间来解决这个问题。我在 wpf 中有自定义用户控件,它是带有 10 个按钮的工具栏。此工具栏添加在 Panel(winform panel) panel.Controls.Add(usercontrol) 中。我想要的是,从面板响应 MouseLeave 事件。 我试过 panel.MouseLeave += MouseLeaveEvent,但没有引发事件。没有一个事件没有引发(MouseMove 等)。是否有任何解决方案,如何实现,将引发 MouseLeave 事件? 非常感谢。

编辑

这里是代码。

CustomToolbar = new AxisMediaControlToolbarViewModel(this);
                    var toolbarView = new AxisMediaControlToolbarView { ViewModel = CustomToolbar };
                    var elementHost = new ElementHost { Dock = DockStyle.Fill, Child = toolbarView };
                    toolbarPanel.Controls.Add(elementHost);

【问题讨论】:

  • 请更正主题的标题和标签。 WinForms 是自 .Net1.1/2.0 以来在 .Net 中的“旧框架”。 WPF 是新的框架。你似乎只指 WPF,所以 WinForms 不应该在这里。此外,标题没有描述问题所在。问题是“我在 UserControl 中的 WPF 面板看不到鼠标事件”等等!

标签: wpf


【解决方案1】:

this thread 中提到了很多原因:

  • 设置 UserControl 的背景
  • 使画布具有焦点
  • 注意 RenderTransforms

编辑

我做了一个测试,只要 WPF 元素没有覆盖面板,它就可以正常工作。鼠标必须直接在面板上才能生成事件。 DockStyle.Fill 可能是您的问题的原因。

【讨论】:

  • 但是我想引发Panel的mouseleaveevent,没有WPFusercontrol的事件
  • 当 WPF 元素覆盖面板时,MouseLeave 事件只会在 WPF 元素上引发,不会冒泡到 WinForms 面板。 ElementHost 不知道子事件。您能否发布一张显示 ElementHost 和 WPF 控件的图片?
  • 我做了一个测试,只要 WPF 元素没有覆盖面板,它就可以正常工作。鼠标必须直接在面板上才能生成事件。
  • 是的,当 WPF 元素不在面板中时,会触发鼠标事件。
  • 当我没有使用 DockStyle.Fill 时,它可以工作,但只能在控件不占用空间的地方使用。当我移过用户控件并离开时,不会触发事件。
【解决方案2】:

其中一个原因可能是您的面板的背景没有设置。

如果你不设置背景,那么控件就像“它的区域不被照顾”并且实际上它是透明的,因为它没有被绘制。然而,它有更多的后果:它的区域不仅没有被绘制,而且它也没有被跟踪,即鼠标事件。

对于初学者,请尝试设置 Background="Transparent"。这可能没什么意义,因为它已经是透明的,但这样一来,Panel 控件将拥有背景,如果没有其他问题,它可能会立即开始看到鼠标事件。

编辑:快速示例:

UserControl.xaml

<UserControl x:Class="UserControlMouse.MyButtonPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             Background="LightBlue"
             Tag="You will never see this message">

    <StackPanel Margin="20" Background="LightGray"
                MouseEnter="handler_MouseEnter" MouseMove="handler_MouseMove" MouseLeave="handler_MouseLeave"
                Tag="StackPanel">
        <StackPanel.Resources>
            <Style TargetType="Border">
                <Setter Property="Margin" Value="2" />
                <Setter Property="Padding" Value="5" />
                <Setter Property="Background" Value="Gray" />
            </Style>
            <Style TargetType="TextBlock">
                <Setter Property="TextAlignment" Value="Center" />
                <Setter Property="Background" Value="WhiteSmoke" />
            </Style>
        </StackPanel.Resources>

        <Button Content="#1" MaxWidth="80" Tag="Button#1" />
        <Button Content="#2" MaxWidth="80" Tag="Button#2"
                MouseEnter="handler_MouseEnter" MouseMove="handler_MouseMove" MouseLeave="handler_MouseLeave"
                />
        <Button Content="#3" MaxWidth="80" Tag="Button#3" />
        <Button Content="#4" MaxWidth="80" Tag="Button#4" />
        <Button Content="#5" MaxWidth="80" Tag="Button#5"
                MouseEnter="handler_MouseEnter" MouseMove="handler_MouseMove" MouseLeave="handler_MouseLeave"
                />
        <Button Content="#6" MaxWidth="80" Tag="Button#6" />
        <Button Content="#7" MaxWidth="80" Tag="Button#7" />
        <Button Content="#8" MaxWidth="80" Tag="Button#8" />

        <TextBlock Margin="0,20,0,0" Tag="Comment TextBlock #1">
            <Run Text="Sender was: " />
            <Run Text="{Binding ReportingControl}" />
        </TextBlock>
        <TextBlock Tag="Comment TextBlock #2">
            <Run Text="Source was: " />
            <Run Text="{Binding ContainerControl}" />
        </TextBlock>
        <TextBlock Tag="Comment TextBlock #3">
            <Run Text="Now you are in: " />
            <Run Text="{Binding ControlUnderMouse}" />
        </TextBlock>

        <UniformGrid Columns="3" Tag="indicator UniformGrid">
            <Border Visibility="{Binding Visib_OnEnter}" Tag="indicator border #1">
                <TextBlock Text="Enter" />
            </Border>
            <Border Visibility="{Binding Visib_OnMove}" Tag="indicator border #2"
                    MouseEnter="handler_MouseEnter" MouseMove="handler_MouseMove" MouseLeave="handler_MouseLeave">
                <TextBlock Text="Move" />
            </Border>
            <Border Visibility="{Binding Visib_OnLeave}" Tag="indicator border #3">
                <TextBlock Text="Leave" />
            </Border>
        </UniformGrid>
    </StackPanel>

</UserControl>

usercontrol.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace UserControlMouse
{
    public partial class MyButtonPanel : UserControl
    {
        private SimpleDataObject theData = new SimpleDataObject();

        public MyButtonPanel()
        {
            InitializeComponent();
            this.DataContext = theData;
        }

        private const int COUNTER_LAG = 20;

        private int counter_enter = 0;
        private void handler_MouseEnter(object sender, MouseEventArgs e)
        {
            counter_enter = counter_mouse;

            theData.Visib_OnEnter = System.Windows.Visibility.Visible;
            theData.Visib_OnMove = System.Windows.Visibility.Hidden;
            theData.Visib_OnLeave = System.Windows.Visibility.Hidden;

            theData.ReportingControl = makeDescriptionOfControl(sender);
            theData.ContainerControl = makeDescriptionOfControl(e.Source);
            theData.ControlUnderMouse = makeDescriptionOfControl(null);
        }

        private int counter_mouse = 0;
        private void handler_MouseMove(object sender, MouseEventArgs e)
        {
            ++counter_mouse;

            if (counter_mouse > counter_enter + COUNTER_LAG) theData.Visib_OnEnter = System.Windows.Visibility.Hidden;
            theData.Visib_OnMove = System.Windows.Visibility.Visible;
            if (counter_mouse > counter_leave + COUNTER_LAG) theData.Visib_OnLeave = System.Windows.Visibility.Hidden;

            theData.ReportingControl = makeDescriptionOfControl(sender);
            theData.ContainerControl = makeDescriptionOfControl(e.Source);
            theData.ControlUnderMouse = makeDescriptionOfControl(null);
        }

        private int counter_leave = 0;
        private void handler_MouseLeave(object sender, MouseEventArgs e)
        {
            counter_leave = counter_mouse;

            theData.Visib_OnEnter = System.Windows.Visibility.Hidden;
            theData.Visib_OnMove = System.Windows.Visibility.Hidden;
            theData.Visib_OnLeave = System.Windows.Visibility.Visible;

            theData.ReportingControl = makeDescriptionOfControl(sender);
            theData.ContainerControl = makeDescriptionOfControl(e.Source);
            theData.ControlUnderMouse = makeDescriptionOfControl(null);
        }

        private string makeDescriptionOfControl(object uiobj)
        {
            if (uiobj == null)
                return "???";

            string text = uiobj.GetType().Name;

            var fe = uiobj as FrameworkElement;
            if (fe != null && fe.Tag != null)
                text += " (" + (string)((FrameworkElement)uiobj).Tag + ")";

            return text;
        }
    }

    public class SimpleDataObject : DependencyObject
    {
        public string ControlUnderMouse { get { return (string)GetValue(ControlUnderMouseProperty); } set { SetValue(ControlUnderMouseProperty, value); } }
        public static readonly DependencyProperty ControlUnderMouseProperty = DependencyProperty.Register("ControlUnderMouse", typeof(string), typeof(SimpleDataObject), new UIPropertyMetadata("???"));

        public string ReportingControl { get { return (string)GetValue(ReportingControlProperty); } set { SetValue(ReportingControlProperty, value); } }
        public static readonly DependencyProperty ReportingControlProperty = DependencyProperty.Register("ReportingControl", typeof(string), typeof(SimpleDataObject), new UIPropertyMetadata("???"));

        public string ContainerControl { get { return (string)GetValue(ContainerControlProperty); } set { SetValue(ContainerControlProperty, value); } }
        public static readonly DependencyProperty ContainerControlProperty = DependencyProperty.Register("ContainerControl", typeof(string), typeof(SimpleDataObject), new UIPropertyMetadata("???"));

        public Visibility Visib_OnEnter { get { return (Visibility)GetValue(Visib_OnEnterProperty); } set { SetValue(Visib_OnEnterProperty, value); } }
        public static readonly DependencyProperty Visib_OnEnterProperty = DependencyProperty.Register("Visib_OnEnter", typeof(Visibility), typeof(SimpleDataObject), new UIPropertyMetadata(Visibility.Hidden));

        public Visibility Visib_OnMove { get { return (Visibility)GetValue(Visib_OnMoveProperty); } set { SetValue(Visib_OnMoveProperty, value); } }
        public static readonly DependencyProperty Visib_OnMoveProperty = DependencyProperty.Register("Visib_OnMove", typeof(Visibility), typeof(SimpleDataObject), new UIPropertyMetadata(Visibility.Hidden));

        public Visibility Visib_OnLeave { get { return (Visibility)GetValue(Visib_OnLeaveProperty); } set { SetValue(Visib_OnLeaveProperty, value); } }
        public static readonly DependencyProperty Visib_OnLeaveProperty = DependencyProperty.Register("Visib_OnLeave", typeof(Visibility), typeof(SimpleDataObject), new UIPropertyMetadata(Visibility.Hidden));
    }
}

示例窗口

<Window x:Class="UserControlMouse.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:UserControlMouse"
        Title="MainWindow" Height="350" Width="525">
    <Grid Background="Red">
        <my:MyButtonPanel Margin="10" />
    </Grid>
</Window>

请运行它并使用它。

  • 观察事件是如何触发的以及哪些控件可以看到它们。注意 SENDER 和 SOURCE 的变化
  • 请注意,SENDER 始终是相同的,即鼠标捕获的根。改变的是源头
  • 请注意,只有按钮 #2 和按钮 #5 报告 ENTER/LEAVE(它们有直接处理程序,其他没有!)
  • 请注意,即使其他控件没有鼠标处理程序,也可以通过鼠标移动“检测到”其他控件 - 您可以使用没有任何鼠标捕获集的 Source 获取事件
  • 检查 OriginalSource(最后一个文本行) - 这是鼠标正下方的控件 - 通常它不是您想要注意的控件,因为它是某些模板或样式中的一些“叶控件”..

【讨论】:

  • 是的面板有背景 - 白色。但是事件没有触发。
  • 看我的例子。它是一个完整的窗口和一个自定义用户控件。该控件实时显示当前鼠标下的内容。鼠标事件报告三件事:Sender、Source 和leaf = OriginalSource。它还显示 Enter/Leave 事件何时发生稍有延迟,因为 Move 事件经常发生并且没有适当的延迟或样式,您根本看不到 Enter/Leave。
  • 该死!我已经为 UserControl 设置了背景,而不是 Panel,它终于可以工作了!!!谢谢大家
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 2013-02-07
  • 2016-11-26
相关资源
最近更新 更多