简体   繁体   English

如何在 C# WPF 中将属性从 CustomControl 传递到它的 UserControls?

[英]How do I pass Properties from a CustomControl to it's UserControls in C# WPF?

I currently have a problem with some DependencyProperties in my code.我目前在我的代码中遇到一些DependencyProperties问题。 I made my own Control which is supposed to be used in many instances of my app.我制作了自己的Control ,它应该在我的应用程序的许多实例中使用。 I was able to bind a boolean DependencyProperty and use it's value in the control itself.我能够绑定一个布尔值DependencyProperty并在控件本身中使用它的值。 Now I need to bind a Style to it's children.现在我需要将Style绑定到它的子项。

Here is how I want to bind the property:这是我想绑定属性的方式:

<Window>
    <Window.Resources>
        <Style x:Key="style" TargetType="Button">
            <Setter Property="Background" Value="Red" />
        </Style>
    </Window.Resources>
    
    <Grid>
        <local:MyControl ButtonStyle="{StaticResource style}"/>
    </Grid>
</Window>

The value will be set in MyControl.cs this way:该值将以这种方式在 MyControl.cs 中设置:

public class MyControl : Control
{
    public static readonly DependencyProperty ButtonStyleProperty= DependencyProperty.Register(
        "ButtonStyle", typeof(Style), typeof(MyControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));

    static MyControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
    }

    public Style ButtonStyle
    {
        get => (Style)GetValue(ButtonStyleProperty);
        set => SetValue(ButtonStyleProperty, value);
    }
}

The Generic.xaml of my custom control owns an UserControl which needs the ButtonStyle .我的自定义控件的 Generic.xaml 拥有一个需要ButtonStyleUserControl I'm trying to pass it in the Generic.xaml like this:我试图像这样在 Generic.xaml 中传递它:

<controller:ControllerView ButtonStyle="{Binding ButtonStyle}"/>

Here is the code-behind for the ControllerView .这是ControllerView的代码隐藏。 For some reason the setter is never accessed.由于某种原因,设置器永远不会被访问。

public partial class ControllerView : UserControl
{
    public static readonly DependencyProperty ButtonStyleProperty = DependencyProperty.Register(
        "ButtonStyle", typeof(Style), typeof(ControllerView), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public ControllerView()
    {
        InitializeComponent();
    }

    public Style ButtonStyle
    {
        get => (Style)GetValue(ButtonStyleProperty);
        set => SetValue(ButtonStyleProperty, value);
    }
}

And it's supposed to be used in the ControllerView.xaml like this:它应该像这样在 ControllerView.xaml 中使用:

<Button Name="Button" Style="{Binding ButtonStyle}"
        Content="{Binding Text, Mode=OneTime}" Command="{Binding Command, Mode=OneTime}"
        Margin="1" FontSize="24">

If anyone could tell me why it doesn't work this way and maybe suggest a solution to my code or can tell me how one would normally do this, that'd be great.如果有人能告诉我为什么它不能以这种方式工作并且可能会建议我的代码的解决方案或者可以告诉我通常如何这样做,那就太好了。

A Binding will use the DataContext as source by default, from the documentation :默认情况下, Binding将使用DataContext作为源,来自文档

By default, bindings inherit the data context specified by the DataContext property, if one has been set.默认情况下,绑定会继承DataContext属性指定的数据上下文(如果已设置的话)。

Dependency properties are not part of the DataContext .依赖属性不是DataContext的一部分。 They are defined on controls.它们在控件上定义。 You can use a RelativeSource binding or in some cases an ElementName to refer to another control for binding.您可以使用RelativeSource绑定或在某些情况下使用ElementName来引用另一个控件进行绑定。

If I understood your decription correctly, MyControl contains a ControllerView and its ButtonStyle property should be bound to the ButtonStyle property of the parent MyControl .如果我对你的描述理解正确, MyControl包含一个ControllerView并且它的ButtonStyle属性应该绑定到父MyControlButtonStyle属性。

<controller:ControllerView ButtonStyle="{Binding ButtonStyle, RelativeSource={RelativeSource AncestorType={x:Type local:MyControl}}}"/>

It's not working because your ControllerView is trying to reference its own data from the wrong DataContext.它不起作用,因为您的 ControllerView 试图从错误的 DataContext 引用它自己的数据。

I like the approach shown in this tutorial:我喜欢本教程中显示的方法:

https://blog.scottlogic.com/2012/02/06/a-simple-pattern-for-creating-re-useable-usercontrols-in-wpf-silverlight.html https://blog.scottlogic.com/2012/02/06/a-simple-pattern-for-creating-re-useable-usercontrols-in-wpf-silverlight.html

Doing external binds to a UserControl's properties doesn't really work by default since that requires the use of two different DataContexts;默认情况下,对 UserControl 的属性进行外部绑定实际上不起作用,因为这需要使用两个不同的 DataContext; if you try to bind assuming your default DataContext for your view then it won't work because the DataContext doesn't have any understanding of what is contained within your UserControl, and conversely if you try to just set the DataContext of the UserControl to itself then it won't have any understanding of the external data you're trying to pass in.如果您尝试假设您的视图使用默认的 DataContext 进行绑定,那么它将无法工作,因为 DataContext 不了解您的 UserControl 中包含的内容,相反,如果您尝试将 UserControl 的 DataContext 设置为其自身那么它就不会理解你试图传入的外部数据。

The solution is to set the control's DataContext to itself, but not immediately on the whole thing;解决方案是将控件的 DataContext 设置为自身,但不是立即设置; instead nest it one level deep to your control's main containing panel.而是将它嵌套到控件的主包含面板的深处一层。 So if you had所以如果你有

<UserControl>
    <Grid x:Name="LayoutRoot">
    //control contents go here
    </Grid>
<UserControl>

in that UserControl's code-behind you could enter在该 UserControl 的代码隐藏中,您可以输入

public UserControlName()
{
    InitializeComponent();
    LayoutRoot.DataContext = this;
}

and the end result is that you will be able to bind to this control using data from another DataContext, and then the control will use its own DataContext (now containing the bound data from the other DataContext) within itself.最终结果是您将能够使用来自另一个 DataContext 的数据绑定到此控件,然后该控件将在其自身内部使用自己的 DataContext(现在包含来自其他 DataContext 的绑定数据)。

If you cooked up some dependency properties for that UserControl, you can now easily reference them, as well;如果您为该 UserControl 编写了一些依赖属性,您现在也可以轻松地引用它们; your <controller:ControllerView ButtonStyle="{Binding ButtonStyle}"/> line would work perfectly.您的<controller:ControllerView ButtonStyle="{Binding ButtonStyle}"/>行将完美运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM