【问题标题】:WPF: GroupBox.SetResourceReference suddenly makes it inherit TemplateParent.ForegroundWPF:GroupBox.SetResourceReference 突然使其继承 TemplateParent.Foreground
【发布时间】:2023-07-18 15:14:01
【问题描述】:

当我发现这个奇怪的现象时,我正在制作一个 UserControl。如果我使用 C# 代码在 UserControl 的模板中放置一个 GroupBox,然后对 GroupBox 进行任何 SetResourceReference 调用,那么 GroupBox 突然继承了 TemplateParent(我的 UserControl)的前景。

到目前为止,我已经找到了针对这种情况的以下要求:

  • UserControl 基类型无关紧要
  • 受影响的子模板必须是 GroupBox(但不一定是第一个子模板)
  • GroupBox 的前景可以在模板中显式设置,覆盖继承
  • 必须使用来自 GroupBox 的某种引用调用
  • 似乎只有 Foreground 属性受到影响

这是我的示例代码:

MainWindow.xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="350">
    <Window.Resources>
        <Thickness x:Key="TestPadding">5</Thickness>
        <Style TargetType="{x:Type GroupBox}">
            <Setter Property="Foreground" Value="Red" />
            <Setter Property="Background" Value="Orange" />
        </Style>
    </Window.Resources>
    <Grid>
        <my:TestControl Foreground="Blue" Background="Purple" />
    </Grid>
</Window>

TestControl.cs:

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Markup;

namespace WpfApplication1
{
    public class TestControl : UserControl
    {
        public TestControl()
        {
            FrameworkElementFactory group = new FrameworkElementFactory(typeof(GroupBox));
            group.SetValue(GroupBox.ContentProperty, "My Child");
            group.SetResourceReference(GroupBox.MarginProperty, "TestPadding");
            this.SetValue(TestControl.TemplateProperty, new ControlTemplate(typeof(TestControl)) { VisualTree = group });
        }
    }
}


你们怎么看,这是我应该向 Microsoft 报告的错误吗?

【问题讨论】:

    标签: wpf foreground groupbox


    【解决方案1】:

    我认为这不是 Microsoft 的问题。事实上,我认为它工作正常。您正在为您的 TestControl 在代码后面定义一个模板,并且您正在将一个 GroupBox 设置为模板的根元素。这里发生的情况是您的 UserControl.Foreground 属性与作为模板根目录的 GroupBox 不同,然后 GroupBox(作为 GroupBox)将采用从资源(在本例中为窗口的资源)继承的前景。

    如果你想解决这个问题,你可以做一些类似“TemplateBindings”的事情,下面的代码会像 TemplateBinding 一样为你工作:

    namespace WpfApplication1
    {
        public class TestControl : UserControl
        {
            public TestControl()
            {
                FrameworkElementFactory group = new FrameworkElementFactory(typeof(GroupBox));
                group.SetValue(GroupBox.ContentProperty, "My Child");
                group.SetResourceReference(GroupBox.MarginProperty, "TestPadding");
    
                //This line will work as a TeplateBinding
                group.SetBinding(GroupBox.ForegroundProperty, new Binding() { Path = new PropertyPath("Foreground"), RelativeSource = RelativeSource.TemplatedParent });
    
                this.SetValue(TestControl.TemplateProperty, new ControlTemplate(typeof(TestControl)) { VisualTree = group });
            }
        }
    }
    

    希望这个答案对你有用。

    【讨论】:

    • 感谢您的评论,但您的问题倒过来了。它已经从 TemplateParent 继承,我不希望它继承。
    • 让我看看我是否理解,例如,您是否希望 GroupBox 的前景为蓝色(来自您的 TestControl 前景)?我对其从 ResourceDictionary 获得的所有其他属性进行了测试并工作。如果不是你想要的,请更好地向我解释。谢谢
    • 不,我希望 GroupBox 的前景为与样式一致的红色。如果 GroupBox 没有实现它自己的模板或者我没有使用 group.SetResourceReference,这将是真的。我只是不明白这些应该如何影响控件的前景。
    • 我完全测试了您上面的代码,并且 Group Box 获取了所有资源属性,然后我认为您的前景是蓝色的(在示例中)。然后我认为问题可能是您在上面的示例中没有考虑到的问题。请尝试找出可能的情况,然后我们可以帮助您...
    【解决方案2】:

    我已联系 Microsoft WPF 开发团队。他们承认这是一个错误,但已将其列为低优先级且不太可能修复。

    我对这个例子的解决方法: 使用另一个控件来调用 *.SetResourceReference 来执行填充,而不是使用 GroupBox。

    【讨论】: