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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30215659/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:07:44  来源:igfitidea点击:

How to set a WPF usercontrol property from XAML?

c#wpfxamluser-controls

提问by Tim Butler

I'm trying to set the fill property of several instances of the same usercontrol from XAML in order to distinguish them. I'm using a dependency property in the C# codebehind of the control and referring to that in the XAML when I instantiate the control. Here's a simplified example of what I've tried, first the XAML of the user control:

我正在尝试从 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>

Now the codebehind:

现在代码隐藏:

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();
        }
    }
}

I instantiate the control in the main window and try to set the fill colour to red:

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

<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>

But the rectangle remains unfilled, even when I run the project. Can anyone help please?

但是矩形仍未填充,即使我运行该项目也是如此。有人可以帮忙吗?

Cheers,

干杯,

Tim

蒂姆

回答by Clemens

There are two things wrong with your dependency property.

您的依赖属性有两个问题。

First, its type should be Brush, not string, because that is the type used by properties of WPF controls like Shape.Fillor Control.Background. WPF provides automatic type conversion from strings like "Red" or "#FFFF0000" in XAML to type Brush.

首先,它的类型应该是Brush,而不是字符串,因为这是 WPF 控件的属性使用的类型,例如Shape.FillControl.Background。WPF 提供从 XAML 中的“Red”或“#FFFF0000”等字符串到 Brush 类型的自动类型转换。

Second, you should not have anything else than a call to SetValuein the setter method of the CLR wrapper. The reason is explained in the XAML Loading and Dependency Propertiesarticle on MSDN:

其次,除了SetValue在 CLR 包装器的 setter 方法中调用之外,您不应有任何其他内容。MSDN 上的XAML 加载和依赖属性文章中解释了原因:

Because the current WPF implementation of the XAML processor behavior for property setting bypasses the wrappers entirely, you should not put any additional logic into the set definitions of the wrapper for your custom dependency property. If you put such logic in the set definition, then the logic will not be executed when the property is set in XAML rather than in code.

由于属性设置的 XAML 处理器行为的当前 WPF 实现完全绕过包装器,因此不应将任何其他逻辑放入自定义依赖项属性的包装器的集合定义中。如果将此类逻辑放在集合定义中,则在 XAML 而非代码中设置属性时,将不会执行该逻辑。

So your dependency property declaration should look like this:

所以你的依赖属性声明应该是这样的:

public static readonly DependencyProperty FillBrushProperty =
    DependencyProperty.Register(
        "FillBrush", typeof(Brush), typeof(RectangleFillTest));

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

To react to property changes, you would now register a PropertyChangedCallback with property metadata. But you don't need to do that here, because you could simply bind the property in the UserControl's XAML like this:

为了对属性更改做出反应,您现在将使用属性元数据注册一个 PropertyChangedCallback。但是您不需要在这里这样做,因为您可以像这样简单地在 UserControl 的 XAML 中绑定属性:

<Rectangle Fill="{Binding FillBrush,
    RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" ... />

回答by Juan Pablo Garcia Coello

I will explain why is is not working and how to solve.

我将解释为什么不起作用以及如何解决。

1.- A Dependency Property is only called when the usercontrol has that dependency property in the visual tree.

1.- 仅当用户控件在可视化树中具有依赖属性时才会调用依赖属性。

In case you want to do in that way, you need to add for instance :

如果你想这样做,你需要添加例如:

new PropertyMetadata(string.Empty, ValueChanged));

and there change the value:

并更改值:

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);

        }
    }

That is explicit for your logic, in case you need a more generic code for any color, etc using binding the property to the rectangle, just tell me.

这对您的逻辑来说是明确的,如果您需要使用将属性绑定到矩形的任何颜色等更通用的代码,请告诉我。

回答by mgarant

You need to bind your Dependency Property to the Fill property of your Rectangle in the xaml of your UserControl. You'll have Something like this :

您需要在 UserControl 的 xaml 中将您的 Dependency 属性绑定到您的 Rectangle 的 Fill 属性。你会有这样的东西:

<Rectangle x:Name="rect" Fill="{Binding FillColour, RelativeSource={RelativeSource FindAncestor, AncestorType=RectangleFillTest}}" HorizontalAlignment="Left" Height="50" Stroke="Black" VerticalAlignment="Top" Width="150"/>

Also, in your dependency property, it's type should be Brush, and not String.

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