【问题标题】:How can you set IsHitTestVisible to True on a child of something where it's set to false?如何将 IsHitTestVisible 设置为设置为 false 的子对象的 True?
【发布时间】:2012-08-22 07:31:06
【问题描述】:

我有一条消息在边框内并显示在 MDI 客户区前面。因为它只是一条消息,所以我将它的 IsHitTestVisible 设置为 false。为方便起见,我还在其中包含了一个按钮,因此用户只需单击该按钮即可开始新图表。

但是,由于边框将其IsHitTestVisible 设置为False,它会缩短按钮的True 值,因此用户无法单击按钮。

也就是说,如何使控件对鼠标不可见,同时仍允许其子级之一接收鼠标事件?

截图如下:

我们希望带有文本的蓝色区域在命中测试中不可见,但我们希望按钮仍然可以被按下。想法? (是的,我已经知道将这两个项目堆叠在一个网格中,但这会影响布局。

【问题讨论】:

  • 我认为你会更幸运地弄清楚如何使用 Grid 来修复你的布局,其中两个控件相互堆叠,而不是找到一种设置 IsHitTestVisible=true 但允许命中的方法无论如何都要对子项目进行测试。你有什么样的布局?
  • 您可以覆盖 HitTestCore...来确定您的 UIElement 的点击行为(假设您已经创建了一个 UserControl)......但就像 Rachel 说的......使用 Grid 或不同的布局。
  • 是的,我已经有了一个重量更轻的控件,称为 LayerPanel,它可以简单地将东西堆叠在一起。从网格中删除所有测量值等,这是众所周知的性能差。尽管如此,我还是讨厌必须对事物进行分层,因为当文本更改以进行本地化时,它会推动布局,现在您必须担心在未连接的事物前面对齐某些内容。不好玩。可行,但不好玩。

标签: wpf layout hittest


【解决方案1】:

AFAIK 你不能。 但是,您可以使用 IsEnabledProperty 来做到这一点,并且仍然需要一些解决方法。 你必须像这样创建自己的按钮:

2013 年 9 月 1 日编辑:

 public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        DataContext = this;
    }

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("hello");
    }
}

public class MyButton : Button
{
    static MyButton()
    {
        IsEnabledProperty.OverrideMetadata(typeof(MyButton),
        new UIPropertyMetadata(true,(o, args) => { },(o, value) => value));
    }
}

XAML:

<BorderIsEnabled="False">
    <wpfApplication2:MyButton Margin="61,95,88,100" Click="ButtonBase_OnClick">Open a new diagram</wpfApplication2:MyButton>
</Border>

【讨论】:

  • 没有真正遵循您要在此处显示的内容。您似乎已经定义了 PropertyChanged 和 Coercion 匿名委托,但两者都只执行默认行为,那么为什么要指定它们呢?就此而言,您将默认值设置为 True,这已经是 IsEnabled 的默认值,这就引出了一个问题,为什么您首先要覆盖元数据?同样,不要真正遵循您试图通过此实现的目标,因为它实际上似乎没有改变任何东西。
  • IsEnabledProperty 的默认行为是将其值从容器级联到其子级,一旦覆盖并在父级中设置 IsEnabled=False,它将不会影响子级。
  • 嗯...但是你不能把孩子中的 IsEnabled 设置为 True 而不必继承任何东西吗?我的意思是,如果如您所说,IsEnabled 的默认行为是由其子级继承,那么您所要做的就是直接在子级上设置 IsEnabled,而不需要子类,不是吗?
【解决方案2】:

好的,看起来问题无法按要求解决,因此看起来我们必须恢复到分层方法。在这种情况下,为了补偿文本变化,您必须将按钮的垂直对齐方式设置为底部,并确保在边框的底部边缘或 TextBlock 的底部边缘有额外的填充)以确保标签始终浮动在按钮。您使用相同的原则管理两者的边距/填充。

这将为我们提供我们所追求的,但看起来很麻烦。同样,我希望有某种方法可以指定 IsHitTestVisible(或 IsEnabled),并以某种方式将它们(及以下)重新确立为行为的所有者。一个人可以做梦。在那之前……层层叠叠!

【讨论】:

  • 这并不能真正回答我的问题,而且您也在使用 IsEnabled ,它可以并且经常改变控件的外观。另外,它需要子类化,这意味着您不能将它用于现有控件。
【解决方案3】:

免责声明:看起来它不能解决 OP 的确切问题,但我会保留它,因为它可能对其他有类似问题的人有所帮助。

单击网格不应在网格上注册任何鼠标事件。

<Grid Background="{x:Null}">
   <Button/>
<Grid/>

编辑:当您希望背景可见时,我会建议这样做:为了演示,我在边框上设置 cursor="hand"

<Canvas>
    <Border Height="300" Width="300" Background="Red" Cursor="Hand" IsHitTestVisible="False"/>
    <Button Content="click"/>
</Canvas>

<Grid>
    <Border  Background="Red" Cursor="Hand" IsHitTestVisible="False" />
    <Button Content="click" HorizontalAlignment="Center"/>
</Grid>

这两种情况的诀窍是控件(按钮)不是 IsHitTestVisible="False" 的父控件的子控件,它只是与背景控件重叠

【讨论】:

  • 这使得网格不可见。我只希望它对鼠标不可见,而不是用户。
  • 是的,正如我在最初的问题中提到的,我已经熟悉这种技术,但由于按钮不在边界内,你必须做额外的计算才能弄清楚如何“填充” ' 按钮使它看起来仍然在边界内。但我想这是唯一的方法。
  • 这实际上帮助了我很多类似的问题。我以为将背景设置为透明或 x:Null 是一样的,但尝试后发现它不一样。对我来说,这是一个面板,我可以在上面放置可点击的元素,但是没有击中子元素的点击仍然会传递到后面的内容。该解决方案适用于此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
相关资源
最近更新 更多