WPF通过窗口内的自定义用户控件绑定到DependencyProperty问题

时间:2019-07-08 22:05:34

标签: c# wpf

我需要一些帮助。我创建了一个自定义用户控件,并将其插入到主窗口中。但是,我无法将窗口中的属性绑定到用户控件中的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;
        }
    }
}

外观如下:

User Control

这是主窗口的代码:

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

Main Window

当然,我希望当我按下按钮时,会收到一条消息,其中包含用户输入的全名。但是,我什么也没得到。

Application

编辑:这是该问题的解决方案,适用于访问有类似问题的页面的人。

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

2 个答案:

答案 0 :(得分:1)

您绑定到错误的AncestorType。类型必须为UserControl,而不是WindowWindow扩展了Control,但没有扩展UserControl

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

此外,因为将Binding.Mode设置为TwoWay,所以绑定源PropertyFullName必须能够将值的变化通知绑定目标ValueFullName。为此,您需要将PropertyFullName作为DependencyProperty来实现双向绑定。

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

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

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

答案 1 :(得分:0)

正如BionicCode指出的那样,您可以更改AncestorType。另一种选择是设置窗口的DataContext

您可以在构造函数中完成

public MainWindow()
{
     InitializeComponent();
     DataContext = this;
}

或在XAML中。

<Window DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}">

这样,您不必在绑定中指定源(只要您绑定到代码隐藏属性即可)。