【问题标题】:WPF: How do I make a custom modal dialog flash?WPF:如何使自定义模式对话框闪烁?
【发布时间】:2016-01-26 13:24:58
【问题描述】:

通常,当您打开模态对话框并尝试单击其父窗口时,模态对话框的标题栏会闪烁。在 WPF 中创建自定义、无边框、无边框的窗口时,您将失去所有功能,必须自己重建它。我看起来高高在低,我一生都无法弄清楚如何让我的模态窗口闪烁。虽然它仍然发出哔哔声......

我想我将不得不在 WndProc 中观察一些我必须处理的事件,但我不知道是哪个事件或如何去做。我试过观察窗口改变和窗口改变事件以及 WM_ACTIVATE 事件无济于事。我确定我只是缺少一些简单的东西,但我将不胜感激。谢谢!

【问题讨论】:

  • 这是 WM_NCACTIVATE 消息。 Spy++ 实用程序可以告诉你这些事情。
  • 我使用了 spy++,但据我所知,WM_NCACTIVATE 无论是失去焦点的模态窗口还是非模态窗口都会发送相同的确切消息。这似乎不是很有帮助。它也只是告诉我窗口正在被激活,我不知道如何判断,我需要 FLASH 标题栏,而不仅仅是绘制一个活动的标题栏。你能说得更具体点吗?
  • 重点是多次发送消息。从而使其闪烁。
  • 哦哦哦。我明白了......显然仅仅因为发送了停用消息并不意味着窗口的 IsActive 属性实际上发生了变化。
  • 不是停用消息,而是 WM_ACTIVATE。 “NC”消息是“窗口的框架应该是什么样子”消息。 "NC" == 非客户端。

标签: c# wpf window custom-controls wndproc


【解决方案1】:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        var retVal = IntPtr.Zero;

        switch (msg)
        {
            case UnsafeNativeConstants.WM_NCACTIVATE:
                retVal = UnsafeNativeMethods.DefWindowProc(hwnd, UnsafeNativeConstants.WM_NCACTIVATE, new IntPtr(1), new IntPtr(-1));
                AssociatedObject.UpdateTitlebar((int)wParam == 1 ? true : false);
                handled = true;
                break;
        }

        return retVal;
    }

我已将 WndProc 连接到附加到我的窗口的自定义行为中。它在我的窗口上调用一个内部方法,该方法将适当地更新标题栏的颜色。

感谢@Hans Passant 为我指明了正确的方向。

【讨论】:

    【解决方案2】:

    如果您没有准确找到您要查找的内容,可以使用一种解决方法,即根本不使用模式窗口。

    你可以这样做:

    1. 创建一个名为 MainContentUC 的用户控件并将 MainWindow 的内容放入其中
    2. 创建另一个名为 MessageBoxUC 的用户控件并将消息框的内容放入其中

      <UserControl x:Name="root" Visibility="{Binding ElementName=root, Path=IsOpen}">
          <Grid Background="#4FFF"/>
              <Border HorizontalAlignment="Center" VerticalAlignment="Center" 
                      x:Name="border" Background="White"/>
              <Grid.Triggers>
                  <EventTrigger RoutedEvent="MouseDown">
                      <BeginStoryboard>
                          <Storyboard Duration="0:0:1">
                              <ColorAnimation 
                                   Storyboard.TargetName="border" 
                                   Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" 
                                   To="Black" Duration="0:0:.2" RepeatBehavior="Forever"/>
                          </Storyboard>
                      </BeginStoryboard>
                  </EventTrigger>
              </Grid.Triggers>
          </Grid>
      </UserControl>
      
    3. 在 MessageBoxUC 中添加一个名为 IsOpen (default=false) 的布尔依赖属性

    4. 编写主窗口的xaml代码如下:

      <Window xmlns:local="clr-namespace:MyWpfApplication">
          <Grid>
              <local:MainContentsUC/>
              <local:MessageBoxUC/>
          </Grid>
      </Window>
      

    这样,当 MessageBoxUC 打开时,它将阻止 MainContentsUC 被单击。当你点击后面的区域(颜色设置为#4FFF)时,触发器会运行情节提要并闪烁。

    如果您有多个窗口,您可以实现不同的控件模板并使用模板选择器在它们之间进行选择。所以你将拥有而不是&lt;local:MainContentsUC/&gt;

    &lt;ContentPresenter ContentTemplateSelector="{StaticResource mySelector}"/&gt;

    【讨论】:

    • 我希望它是一个新窗口,而不仅仅是一个控件。 @Hans Passant 让我指出了正确的方向。不过感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2021-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多