带有自定义镶边的 WPF 窗口在右侧和底部有不需要的轮廓 [英] WPF window with custom chrome has unwanted outline on right and bottom

查看:18
本文介绍了带有自定义镶边的 WPF 窗口在右侧和底部有不需要的轮廓的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Microsoft.Windows.Shell dll 创建了一个带有自定义镶边的 WPF 窗口.代码如下:

I have created a WPF window with custom chrome using the Microsoft.Windows.Shell dll. Here is the code for that:

<Style TargetType="Window" x:Key="ChromeLessWindowStyle">
        <Setter Property="shell:WindowChrome.WindowChrome">
            <Setter.Value>
                <shell:WindowChrome
           GlassFrameThickness="0"
          ResizeBorderThickness="5"          
          CornerRadius="5"
          CaptionHeight="30">
                </shell:WindowChrome>
            </Setter.Value>
        </Setter>
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Grid>
                            <Grid Background="#FF595959" >
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <Border Grid.Row="0" Height="30" Background="#FF393939">
                                    <DockPanel LastChildFill="False" Margin="0,1,5,0">
                                        <TextBlock DockPanel.Dock="Left" Style="{DynamicResource {x:Static coreKeys:TextBlockKeys.Default}}" FontWeight="Bold" Text="{TemplateBinding Title}" Margin="10,0,0,0" VerticalAlignment="Center"/>
                                        <!--Buttons-->
                                        <Button DockPanel.Dock="Right" behaviors:WindowCommandBehaviors.IsCloseButton="True" Style="{DynamicResource {x:Static coreKeys:ButtonKeys.Close}}" shell:WindowChrome.IsHitTestVisibleInChrome="True"/>
                                        <Button DockPanel.Dock="Right" behaviors:WindowCommandBehaviors.IsMaximizeButton="True" Style="{DynamicResource {x:Static coreKeys:ButtonKeys.Maximize}}" Visibility="{TemplateBinding WindowState,Converter={StaticResource WindowStateToVisibilityConverter},ConverterParameter=MaximizeButton }" shell:WindowChrome.IsHitTestVisibleInChrome="True" />
                                        <Button DockPanel.Dock="Right" behaviors:WindowCommandBehaviors.IsMaximizeButton="True" Style="{DynamicResource {x:Static coreKeys:ButtonKeys.Restore}}"  Visibility="{TemplateBinding WindowState,Converter={StaticResource WindowStateToVisibilityConverter}, ConverterParameter=RestoreButton }" shell:WindowChrome.IsHitTestVisibleInChrome="True" />
                                        <Button DockPanel.Dock="Right" behaviors:WindowCommandBehaviors.IsMinimizeButton="True" Style="{DynamicResource {x:Static coreKeys:ButtonKeys.Minimize}}" shell:WindowChrome.IsHitTestVisibleInChrome="True"/>
                                    </DockPanel>
                                </Border>
                                <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}"/>
                            </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

这在正常情况下非常有效,直到我需要使用 C# 代码使用窗口时,我才能发现问题.我有一个消息服务:

This works perfect in normal scenarios and I could not discover a problem until I had a requirement of using the window using C# code. I have a messaging service that:

  1. 创建一个模态窗口.
  2. 使用 WPF 用户控件填充其内容.
  3. 将窗口的数据上下文设置为适当的 ViewModel.
  4. 显示窗口

代码如下:

var userControl = viewRegistry.GetViewByKey(viewKey_); // Get the UserControl.
var modalWindow = new ModalCustomMessageDialog
{
    // Set the content of the window as the user control
    DataContext = viewModel_,
    // Set the data context of the window as the ViewModel
    Owner = Util.AppMainWindow,
    // Set the owner of the modal window to the app window.
    WindowStartupLocation = WindowStartupLocation.CenterOwner,
    //Title = viewModel.TitleText ?? "",
    ShowInTaskbar = false,
    Content = userControl,
    SizeToContent = SizeToContent.WidthAndHeight
};
if (showAsToolWindow_)
{
    modalWindow.ResizeMode = ResizeMode.NoResize;
    modalWindow.WindowStyle = WindowStyle.ToolWindow;
}
modalWindow.Loaded += modalWindow_Loaded;
modalWindow.Closed += CleanModalWindow;
modalWindow.Show();

注意这一行

SizeToContent = SizeToContent.WidthAndHeight

这负责调整窗口大小以符合用户控件的宽度和高度.这样生成的模态窗口在窗口的右侧和底部都有一个粗黑的轮廓.像这样:

This takes care of resizing the window to honour the Width and Height of the user control. The modal window thus produced has a thick black outline on the right and bottom of the window. Like so:

窗口应该像这样(并且在调整大小之后变成)像这样:

The window should be like (and after resize becomes) like this:

有几点值得注意:

  1. 调整窗口大小后,黑色轮廓就会消失.

  1. This black outline disappears as soon as the window is resized.

如果将 SizeToContent 设置为 SizeToContent.Height 或 SizeToContent.Width,则不会出现此轮廓.但随后它会分别吹掉模态窗口的宽度或高度.

This outline doesnt appear if the SizeToContent is set to either SizeToContent.Height or SizeToContent.Width. But then it blows off either the Width or Height of the modal window respectively.

我认为窗口重绘可能存在一些问题.所以我尝试了以下代码来重绘窗口:

I thought there might be some issue with window getting redrawn. So I tried the following code to redraw the window:

private const int WmPaint = 0x000F;

[DllImport("User32.dll")]
public static extern Int64 SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
 ......................
//Inside the Loaded event handler of the modalWindow
var windowHandle = new WindowInteropHelper(modalWindow).Handle;
SendMessage(windowHandle, WmPaint, IntPtr.Zero, IntPtr.Zero);

这没有效果.

如果我为填充窗口的用户控件固定了高度和宽度属性,则不会出现此问题.但是,我不能总是那样做.

This problem does not appear if I have fixed Height and Width property given to the User Control that populates the window. However, I can't do that always.

消息服务已经存在很久了,这个幽灵轮廓最近在自定义 chrome 更改后出现.

The messaging service has been in place since ages and this ghost outline has made its appearance recently after the custom chrome change.

有人遇到过类似的情况吗?任何帮助将不胜感激.

Has anybody faced a similar situation? Any help will be appreciated.

推荐答案

我最近在包含动态生成元素的窗口上使用自定义窗口镶边时遇到了这个问题.

I recently hit on this problem when using a custom window chrome on a window which contains dynamically generated elements.

为什么会这样?

如果我们使用带有静态内容的窗口,则该窗口可以在初始化时知道​​包含其子元素所需的最大宽度/高度.

If we are using a window with static contents, the window can be aware upon initialization what will be with maximum width/height required to contain its child elements.

如果我们想要使用具有自动缩放功能的动态元素,例如使用 MVVM 模式的视图,我们需要在所有绑定(例如视图)都已解析后请求窗口更新其视觉状态.

In the case that we want to use dynamic elements with automatic scaling, such as Views if using the MVVM pattern, we need to request the window update its visual state once all its bindngs (Views, for example) have been resolved.

解决方案

为了执行我们上面推理的行为,我们需要使用窗口的 ContentRendered 事件,并将其用于 InvalidateVisual().

To enforce the behaviour we've reasoned about above, we need to use the window's ContentRendered event, and use it to InvalidateVisual().

在您遇到问题的窗口的 XAML 中:

In the XAML of the window you're experiencing the problem:

ContentRendered="Window_OnContentRendered"

在代码隐藏中:

private void Window_OnContentRendered(object sender, EventArgs e)
{
    InvalidateVisual();
}

祝你好运.

这篇关于带有自定义镶边的 WPF 窗口在右侧和底部有不需要的轮廓的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆