如何从XAML设置WPF用户控件属性?

5

我将尝试从XAML中设置多个相同用户控件的填充属性以区分它们。我在控件的C#代码后台中使用一个依赖属性,并在实例化控件时在XAML中引用该属性。下面是我尝试的简化示例,首先是用户控件的XAML:

<UserControl x:Class="RectangleFillUserControlTest.RectangleFillTest"
             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="50" d:DesignWidth="150">
    <Grid>
        <Rectangle x:Name="rect" HorizontalAlignment="Left" Height="50" Stroke="Black" VerticalAlignment="Top" Width="150"/>
    </Grid>
</UserControl>

现在是代码后端:

namespace RectangleFillUserControlTest
{
    public partial class RectangleFillTest : UserControl
    {
        SolidColorBrush fillBrush;

        public static readonly DependencyProperty FillColourProperty = DependencyProperty.Register
            ("FillColour", typeof(string), typeof(RectangleFillTest), new PropertyMetadata(string.Empty));

        public string FillColour
        {
            get { return (string)GetValue(FillColourProperty); }

            set
            {
                SetValue(FillColourProperty, value);
                if (value == "red") fillBrush = new SolidColorBrush(Colors.Red);
                else fillBrush = new SolidColorBrush(Colors.Green);
                rect.Fill = fillBrush;
            }
        }

        public RectangleFillTest()
        {
            InitializeComponent();
        }
    }
}

我在主窗口实例化控件并尝试将填充颜色设置为红色:

<Window x:Class="RectangleFillUserControlTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:RectangleFillUserControlTest"
        Title="MainWindow" Height="350" Width="525">
    <Grid Background="#FF1D2CC3">
        <local:RectangleFillTest FillColour="red"/>
    </Grid>
</Window>

但是即使我运行项目,矩形仍然没有填充。有人能帮忙吗?
谢谢,
Tim
3个回答

9
你的依赖属性有两个问题。
首先,它的类型应该是Brush而不是字符串,因为WPF控件的属性(如Shape.Fill或Control.Background)使用的就是Brush类型。WPF提供了从XAML中的字符串(如“Red”或“#FFFF0000”)自动转换为Brush类型的功能。
其次,在CLR包装器的setter方法中,除了调用SetValue之外,你不应该有任何其他内容。原因在MSDN的XAML Loading and Dependency Properties文章中有解释:
“由于当前WPF实现的XAML处理器行为绕过了包装器,直接进行属性设置,所以您不应该将任何附加逻辑放入自定义依赖属性的包装器set定义中。如果在set定义中放置这样的逻辑,则当属性在XAML中而不是在代码中设置时,逻辑将不会被执行。”
因此,你的依赖属性声明应该如下所示:
public static readonly DependencyProperty FillBrushProperty =
    DependencyProperty.Register(
        "FillBrush", typeof(Brush), typeof(RectangleFillTest));

public Brush FillBrush
{
    get { return (Brush)GetValue(FillBrushProperty); }
    set { SetValue(FillBrushProperty, value); }
}

为了响应属性更改,您现在可以使用属性元数据注册 PropertyChangedCallback。但是在这里您不需要这样做,因为您可以在 UserControl 的 XAML 中像这样简单地绑定属性:
<Rectangle Fill="{Binding FillBrush,
    RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" ... />

感谢您提供高质量的解释、优秀的代码以及绑定信息。很快会有更多关于如何将哪个绑定到哪里的问题,敬请期待。 - Tim Butler
你好Clemens,我尝试了这两个解决方案,都完全解决了我的问题。在这种情况下我不确定应该接受哪个答案,所以我接受了Juan的答案,他可以从额外的声望中受益更多。希望这样做可以。再次感谢你的时间和努力。 - Tim Butler
你应该接受帮助你最多、你认为最好的答案。仅仅因为你认为作者可以从声望点数中受益而接受一个答案是错误的,可能会误导其他人。 - Clemens
好的,我接受了Juan的答案,因为它不需要深入绑定。你的答案可能更好,但我不太有资格评判,而且我是英国人,不喜欢通过说我更喜欢其中之一来惹人生气。希望这能消除任何困惑,并希望在不久的将来再次从你的帮助中受益。干杯... - Tim Butler

8
我会解释为什么它不起作用以及如何解决。
1. 依赖属性只有在用户控件中具有该依赖属性的可视树时才被调用。
如果您想以这种方式执行操作,例如,您需要添加以下内容:
new PropertyMetadata(string.Empty, ValueChanged));

并在那里更改值:

public static readonly DependencyProperty FillColourProperty = DependencyProperty.Register
        ("FillColour", typeof(string), typeof(RectangleFillTest), new PropertyMetadata(string.Empty, ValueChanged));

    private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var control = d as RectangleFillTest;
        var fillBrush = new SolidColorBrush();
        if (control.FillColour == "red")
            fillBrush = new SolidColorBrush(Colors.Red);
        else
            fillBrush = new SolidColorBrush(Colors.Green);
        control.rect.Fill = fillBrush;
    }

    public string FillColour
    {
        get
        {
            return (string)GetValue(FillColourProperty);
        }

        set
        {
            SetValue(FillColourProperty, value);

        }
    }

如果您需要更通用的代码以使用绑定将属性绑定到矩形,则这对于您的逻辑是明确的,请告诉我。


在搜索了几个小时后,这最终为我解决了问题。非常感谢您指出了ValueChanged回调函数! - jettatore

0
你需要在用户控件的XAML中将依赖属性绑定到矩形的填充属性。你会得到类似这样的代码:
<Rectangle x:Name="rect" Fill="{Binding FillColour, RelativeSource={RelativeSource FindAncestor, AncestorType=RectangleFillTest}}" HorizontalAlignment="Left" Height="50" Stroke="Black" VerticalAlignment="Top" Width="150"/>

此外,在您的依赖属性中,其类型应该是Brush而不是String。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接