【问题标题】:Binding wpf user control to parent property将 wpf 用户控件绑定到父属性
【发布时间】:2017-03-07 22:47:45
【问题描述】:

我有一个简单的用户控件,其中包含一个图像,我想根据父级(可能是另一个 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 和 State 都是 UC 上的依赖属性。 UC 没有设置 DataContext,所以它应该继承父级。我正在尝试做的是类似于以下内容,其中 UC 中的 State 绑定到 Window 的 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>

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

如果我通过代码或 XAML(作为布尔值)在 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); }
}

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

【问题讨论】:

  • DualState 属性在哪里? DualState 是 Window 的属性吗?还是它是其他视图模型的属性?
  • 查看 FindAncestor
  • 是的,DualState 是 window 的一个属性。由于错误说在“对象”“主窗口”上找不到“状态”属性,因此 DataContext 是正确的(即它正在查看窗口)。问题是它正在寻找“状态”而不是“双重状态”
  • 当你绑定到 State... 时,它应该如何寻找 DualState?

标签: wpf data-binding


【解决方案1】:

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

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

这是一个完整的例子:

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

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

<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

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 版本)

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

【讨论】:

  • 问题不在于数据上下文,因为我希望它查看窗口。问题是路径。它在字面上使用“状态”,而不是使用状态依赖属性的值,即“双状态”。
  • 我并不是要暗示问题出在数据上下文上。您想绑定到用户控件上的 State 属性,对吗?如果是这样,请尝试答案。
  • 我仍然遇到同样的错误。我实际上想绑定窗口的 DualState 属性。如果我按如下方式放置数据触发器,它可以工作,但我不想对其进行硬编码,而是将属性名称传递给 UC。
  • 检查更新的答案。 UserControl.State 绑定到 MainWindow.xaml 中的 DualState。而在 UserControl1.xaml 中,DataTrigger 绑定到 UserControl 上的 State。
  • JH - 感谢您抽出宝贵时间提供更多详细信息。除了我没有 DualState 作为 MainWindow 上的依赖属性之外,我的一切都与您相同。当我添加它时,它解决了问题。谢谢!你能帮我理解为什么这是必要的吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-29
  • 1970-01-01
  • 2011-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多