首页 > 解决方案 > WPF 绑定到 DependencyProperty 问题与窗口内的自定义用户控件

问题描述

我需要一些帮助。我创建了一个自定义用户控件,并将其插入到主窗口中。但是,我无法将窗口中的属性绑定到用户控件中的 DependencyProperty。

这是用户控制代码。XAML:

<UserControl x:Class="SomeExample.UCFullName"
         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:SomeExample"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Margin="0,0,0,0" Orientation="Vertical" >
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <StackPanel Orientation="Vertical">
            <Label BorderBrush="White" BorderThickness="1" Content="First Name :" FontSize="14" FontWeight="SemiBold" Foreground="White" Height="30" HorizontalAlignment="Left" Margin="0,2,0,0" VerticalAlignment="Top" Width="100"/>
        </StackPanel>
        <Grid>
            <TextBox Name="FirstName" BorderBrush="Black" BorderThickness="1" FontSize="14" FontWeight="SemiBold" Height="30" HorizontalAlignment="Left" Margin="2,2,0,0" MaxLength="20" VerticalAlignment="Top" Width="100" TextChanged="TxtBlock_TextChanged"/>
        </Grid>
    </StackPanel>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <StackPanel Orientation="Vertical">
            <Label BorderBrush="White" BorderThickness="1" Content="Last Name :" FontSize="14" FontWeight="SemiBold" Foreground="White" Height="30" HorizontalAlignment="Left" Margin="0,2,0,0" VerticalAlignment="Top" Width="100"/>
        </StackPanel>
        <Grid>
            <TextBox Name="LastName" BorderBrush="Black" BorderThickness="1" FontSize="14" FontWeight="SemiBold" Height="30" HorizontalAlignment="Left" Margin="2,2,0,0" MaxLength="20" VerticalAlignment="Top" Width="100" TextChanged="TxtBlock_TextChanged"/>
        </Grid>
    </StackPanel>
</StackPanel>

这是背后的代码

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

namespace SomeExample
{
    public partial class UCFullName : UserControl, INotifyPropertyChanged
    {
        #region INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged;

        protected void Notify(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion INotifyPropertyChanged implementation


        public string ValueFullName
        {
            get { return (string)GetValue(ValueFullNameProperty); }
            set
            {
                SetValue(ValueFullNameProperty, value);
                Notify("ValueFullName");
            }
        }

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueFullNameProperty =
            DependencyProperty.Register("ValueFullName", typeof(string), typeof(UCFullName), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));


        public UCFullName()
        {
            InitializeComponent();
        }

        private void TxtBlock_TextChanged(object sender, TextChangedEventArgs e)
        {
            ValueFullName = FirstName.Text + " " + LastName.Text;
        }
    }
}

这是它的外观:

用户控制

这是主窗口的代码:

<Window x:Class="SomeExample.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:SomeExample"
    mc:Ignorable="d"
    Title="Some Example" Height="200" Width="400">
<StackPanel Margin="0,0,0,0" Orientation="Vertical" Name="SpManual" Background="Black">
    <GroupBox Header="Name" Foreground="White" FontSize="14" Name="groupBoxCoordinateStart" >
        <local:UCFullName ValueFullName="{Binding Path = PropertyFullName, Mode = TwoWay, RelativeSource={RelativeSource AncestorType=UserControl}}"></local:UCFullName>
    </GroupBox>
    <StackPanel Name="SpBtnInsert" Orientation="Horizontal" HorizontalAlignment="Center" Visibility="Visible">
        <Button Name="btnShowFullName" BorderBrush="White" BorderThickness="1" FontSize="14" FontWeight="SemiBold" Height="30" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="2,2,0,0" Background="Transparent" Content="Show Name" Foreground="White" Width="98" Click="BtnShowFullName_Click"></Button>
    </StackPanel>
</StackPanel>

以及背后的代码:

using System.Windows;

namespace SomeExample
{
    /// <summary>
    /// Lógica de interacción para MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public string PropertyFullName { get; set; }
        public MainWindow()
        {
            InitializeComponent();
        }

        private void BtnShowFullName_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Current full name :" + PropertyFullName);
        }
    }
}

主窗口

当然,我希望当我按下按钮时,会收到一条消息,其中包含用户输入的全名。然而,我一无所获。

应用

编辑:这是问题的解决方案,适用于访问此页面时遇到类似问题的人。

<local:UCFullName ValueFullName="{Binding Path = PropertyFullName, RelativeSource={RelativeSource AncestorType=Window}}"></local:UCFullName>

标签: c#wpf

解决方案


你绑定错了AncestorType。而不是UserControl类型必须是WindowWindow延伸Control但不延伸UserControl

<local:UCFullName ValueFullName="{Binding Path=PropertyFullName, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=Window}}" />

此外,由于您将 设置Binding.ModeTwoWay,绑定源PropertyFullName必须能够通知绑定目标ValueFullName有关值的更改。为此,您需要实现PropertyFullNameDependencyProperty启用双向绑定。

作为旁注:以下代码可能有问题

public string ValueFullName
{
    get { return (string)GetValue(ValueFullNameProperty); }
    set
    {
        SetValue(ValueFullNameProperty, value);
        Notify("ValueFullName"); // This line might never get called
    }
}

这只是实际的 CLR 包装器,DependencyProperty不会被框架调用。在此属性上使用绑定时,包装器将永远不会被调用,因此事件将永远不会被引发。


推荐阅读