将 wpf 用户控件绑定到父属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42659813/
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 14:02:01  来源:igfitidea点击:

Binding wpf user control to parent property

wpfdata-binding

提问by user7134019

I've got a simple user control that contains an image whose source I want to change based on a property in the parent (which could be another UC or a Window). A simplified version of the UC looks like this

我有一个简单的用户控件,其中包含一个图像,我想根据父级中的属性(可能是另一个 UC 或窗口)更改其来源。UC 的简化版本如下所示

<UserControl x:Class="Test.Controls.DualStateButton" ... x:Name="root">
    <Grid>
        <Image Height="{Binding Height, ElementName=root}" Stretch="Fill" Width="{Binding Width, ElementName=root}">
            <Image.Style>
                <Style TargetType="{x:Type Image}">
                    <Setter Property="Source" Value="{Binding ImageOff, ElementName=root}"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding State}" Value="True">
                            <Setter Property="Source" Value="{Binding ImageOn, ElementName=root}"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Image.Style>
        </Image>
    </Grid>
</UserControl>

Height, Width, ImageOff, ImageOn, and State are all dependency properties on the UC. The UC has no DataContext set, so it should be inheriting the parent. What I'm trying to do is something like the following where the State in the UC is bound to the DualState property of the Window.

Height、Width、ImageOff、ImageOn 和 State 都是 UC 上的依赖属性。UC 没有设置 DataContext,所以它应该继承父级。我想要做的是类似于下面的事情,其中​​ UC 中的状态绑定到窗口的 DualState 属性。

<Window x:Class="Test.MainWindow" DataContext="{Binding RelativeSource={RelativeSource Self}}">
...
    <Grid>
        <local:DualStateButton State="{Binding DualState}" Height="100" ImageOff="{StaticResource ButtonUp}" ImageOn="{StaticResource ButtonDown}" Width="100"/>
    </Grid>
</Window>

What I get, however, is a error saying that 'State' property not found on 'object' ''MainWindow', so it appears to be taking the binding 'State' in the UC literally and not assigning it to the DualState property of the Window. Can someone shed some insight on what I'm doing wrong?

然而,我得到的是一个错误,说在“对象”“MainWindow”上找不到“状态”属性,因此它似乎是在 UC 中从字面上获取绑定“状态”,而不是将其分配给 DualState 属性窗户。有人可以了解我做错了什么吗?

If I set the State property on the UC either through code or XAML (as a bool value) it works fine. The State DP is defined as follows.

如果我通过代码或 XAML(作为 bool 值)在 UC 上设置 State 属性,它工作正常。状态 DP 定义如下。

public static readonly DependencyProperty StateProperty =
    DependencyProperty.Register("State", typeof(bool), typeof(DualStateButton),
    new PropertyMetadata(false));

public bool State
{
    get { return (bool)GetValue(StateProperty); }
    set { SetValue(StateProperty, value); }
}

Does it data type need to be a binding or something in order for this to work?

它的数据类型是否需要是绑定或其他东西才能使其工作?

回答by J.H.

The DataContext for the DataTrigger is set to the window, that's why it looks at the window for "State". You just need to tell the binding that State is on the user control. Try this:

DataTrigger 的 DataContext 设置为窗口,这就是它查看“状态”窗口的原因。您只需要告诉绑定状态在用户控件上。尝试这个:

<DataTrigger Binding="{Binding Path=State, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" Value="True">


Here is a complete example:

这是一个完整的例子:

MainWindow.xaml

主窗口.xaml

<Window x:Class="WpfApplication89.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication89"
        mc:Ignorable="d"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <local:UserControl1 State="{Binding Path=DualState}" />
        <CheckBox Content="DualState" IsChecked="{Binding DualState}" />
    </StackPanel>
</Window>

MainWindow.xaml.cs

主窗口.xaml.cs

using System.Windows;

namespace WpfApplication89
{
    public partial class MainWindow : Window
    {
        public static readonly DependencyProperty DualStateProperty = DependencyProperty.Register("DualState", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));

        public bool DualState
        {
            get { return (bool)GetValue(DualStateProperty); }
            set { SetValue(DualStateProperty, value); }
        }

        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

UserControl1.xaml

用户控件1.xaml

<UserControl x:Class="WpfApplication89.UserControl1"
             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" 
             xmlns:local="clr-namespace:WpfApplication89"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Text="User Control 1">
            <TextBlock.Style>
                <Style TargetType="TextBlock">
                    <Setter Property="Background" Value="Beige" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=State, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" Value="true">
                            <Setter Property="Background" Value="Red" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBlock.Style>
        </TextBlock>
    </Grid>
</UserControl>

UserControl1.xaml.cs

用户控件1.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace WpfApplication89
{
    public partial class UserControl1 : UserControl
    {
        public static readonly DependencyProperty StateProperty = DependencyProperty.Register("State", typeof(bool), typeof(UserControl1), new PropertyMetadata(false));

        public bool State
        {
            get { return (bool)GetValue(StateProperty); }
            set { SetValue(StateProperty, value); }
        }

        public UserControl1()
        {
            InitializeComponent();
        }
    }
}


MainWindow.xaml.cs (INotifyPropertyChanged version)

MainWindow.xaml.cs(INotifyPropertyChanged 版本)

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApplication89
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T field, T value, [CallerMemberName]string name = null)
        {
            if (Equals(field, value))
            {
                return false;
            }
            field = value;
            this.OnPropertyChanged(name);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName]string name = null)
        {
            var handler = this.PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        #endregion

        #region Property bool DualState
        private bool _DualState;
        public bool DualState { get { return _DualState; } set { SetProperty(ref _DualState, value); } }
        #endregion


        public MainWindow()
        {
            InitializeComponent();
        }
    }
}