WPF:如何将UserControl的TextBase绑定至Window代码后台
问题描述
尝试将自定义UserControl的TextBase字符串属性绑定到Window代码后台的Reame属性,目前可通过TextBox_Reame.TextBase直接取值,但希望通过数据绑定实现双向同步,且不想为该Window使用ViewModel。
UserControl XAML代码
<UserControl x:Class="PasswordManager.Helpers.Resource_UserDefined.TextBox_Hint" 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:local="clr-name" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Name="TextBoxUserWindow" d:DesignHeight="60" d:DesignWidth="800" mc:Ignorable="d"> <Grid Margin="20,0,20,0"> <TextBox Name="txtSearchBox" Padding="0,0,0,3" VerticalContentAlignment="Center" Background="{Binding Background, RelativeSource={RelativeSource AncestorType=UserControl}}" BorderBrush="{Binding BorderColorBrush, RelativeSource={RelativeSource AncestorType=UserControl}}" BorderThickness="{Binding BorderThickness, RelativeSource={RelativeSource AncestorType=UserControl}}" FontFamily="{Binding FontFamily, RelativeSource={RelativeSource AncestorType=UserControl}}" FontSize="{Binding FontSize, RelativeSource={RelativeSource AncestorType=UserControl}}" Text="{Binding TextBase, RelativeSource={RelativeSource AncestorType=UserControl}}" TextChanged="txtSearchBox_TextChanged" /> <TextBlock x:Name="txt_HintBox" Margin="3,0,0,0" VerticalAlignment="Center" Background="Transparent" FontFamily="{Binding FontFamily, RelativeSource={RelativeSource AncestorType=UserControl}}" FontSize="{Binding FontSize, RelativeSource={RelativeSource AncestorType=UserControl}}" FontStyle="{Binding FontStyle, RelativeSource={RelativeSource AncestorType=UserControl}}" Foreground="{Binding ForegroundColorOverlay, RelativeSource={RelativeSource AncestorType=UserControl}}" IsHitTestVisible="False" Text="{Binding Hint, ElementName=TextBoxUserWindow}" /> </Grid> </UserControl>
UserControl 后台代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace PasswordManager.Helpers.Resource_UserDefined { public partial class TextBox_Hint : UserControl, INotifyPropertyChanged { public TextBox_Hint() { InitializeComponent(); } public string TextBase { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); OnPropertyChanged(); } } // Using a DependencyProperty as the backing store for TextBase. This enables animation, styling, binding, etc... public static readonly DependencyProperty TextProperty = DependencyProperty.Register("TextBase", typeof(string), typeof(TextBox_Hint)); public string Hint { get { return (string)GetValue(HintProperty); } set { SetValue(HintProperty, value); } } // Using a DependencyProperty as the backing store for Hint. This enables animation, styling, binding, etc... public static readonly DependencyProperty HintProperty = DependencyProperty.Register("Hint", typeof(string), typeof(TextBox_Hint), new PropertyMetadata("")); public Brush Background { get { return (Brush)GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } // Using a DependencyProperty as the backing store for background. This enables animation, styling, binding, etc... public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register("Background", typeof(Brush), typeof(TextBox_Hint), new PropertyMetadata(Brushes.White)); public Brush BorderColorBrush { get { return (Brush)GetValue(BorderColorBrushProperty); } set { SetValue(BorderColorBrushProperty, value); } } // Using a DependencyProperty as the backing store for BorderColorBrush. This enables animation, styling, binding, etc... public static readonly DependencyProperty BorderColorBrushProperty = DependencyProperty.Register("BorderColorBrush", typeof(Brush), typeof(TextBox_Hint), new PropertyMetadata(Brushes.Black)); public Thickness BorderThickness { get { return (Thickness)GetValue(BorderThicknessProperty); } set { SetValue(BorderThicknessProperty, value); } } // Using a DependencyProperty as the backing store for BorderThickness. This enables animation, styling, binding, etc... public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(TextBox_Hint), new PropertyMetadata(new Thickness(1,1,1,1))); public Brush ForegroundColorOverlay { get { return (Brush)GetValue(ForegroundColorOverlayProperty); } set { SetValue(ForegroundColorOverlayProperty, value); } } // Usando un DependencyProperty come memorizzazione per ForegroundColorOverlay public static readonly DependencyProperty ForegroundColorOverlayProperty = DependencyProperty.Register("ForegroundColorOverlay", typeof(Brush), typeof(TextBox_Hint), new PropertyMetadata(Brushes.Gray)); public FontFamily FontFamily { get { return (FontFamily)GetValue(FontFamilyProperty); } set { SetValue(FontFamilyProperty, value); } } // Using a DependencyProperty as the backing store for FontFamily. This enables animation, styling, binding, etc... public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register("FontFamily", typeof(FontFamily), typeof(TextBox_Hint), new PropertyMetadata(new FontFamily("Arial"))); public FontStyle FontStyle { get { return (FontStyle)GetValue(FontStyleProperty); } set { SetValue(FontStyleProperty, value); } } // Using a DependencyProperty as the backing store for FontStyle. This enables animation, styling, binding, etc... public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register("FontStyle", typeof(FontStyle), typeof(TextBox_Hint), new PropertyMetadata(FontStyles.Normal)); public Double FontSize { get { return (Double)GetValue(FontSizeProperty); } set { SetValue(FontSizeProperty, value); } } // Using a DependencyProperty as the backing store for FontSize. This enables animation, styling, binding, etc... public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register("FontSize", typeof(Double), typeof(TextBox_Hint), new PropertyMetadata(20.0)); private void txtSearchBox_TextChanged(object sender, TextChangedEventArgs e) { if (string.IsNullOrEmpty(txtSearchBox.Text)) txt_HintBox.Visibility = Visibility.Visible; else txt_HintBox.Visibility = Visibility.Hidden; } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
Window中使用UserControl的原代码
<userControls:TextBox_Hint x:Name="TextBox_Reame" Height="40" BorderColorBrush="Black" BorderThickness="0,0,0,1" FontFamily="{DynamicResource Abel}" FontSize="20" FontStyle="Italic" ForegroundColorOverlay="Gray" Hint="Inserisci Il Reame" TextBase="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type userControls:TextBox_Hint}}, Path=TextBase}"> <userControls:TextBox_Hint.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> <GradientStop Offset="0.0" Color="White" /> <GradientStop Offset="0.5" Color="#FFE1FFE6" /> <GradientStop Offset="1.0" Color="White" /> </LinearGradientBrush> </userControls:TextBox_Hint.Background> </userControls:TextBox_Hint>
Window后台属性代码
private string _Reame; public string Reame { get { return _Reame; } set { _Reame = value; OnPropertyChanged(); } }
解决方案
步骤1:修正UserControl的TextBase依赖项属性定义
当前TextBase的CLR属性多余调用了OnPropertyChanged,依赖项属性本身自带变更通知机制;同时依赖项属性的注册名称需与CLR属性名匹配,避免混淆:
public string TextBase { get { return (string)GetValue(TextBaseProperty); } set { SetValue(TextBaseProperty, value); } } // 修正依赖项属性名称,与CLR属性名一致 public static readonly DependencyProperty TextBaseProperty = DependencyProperty.Register(nameof(TextBase), typeof(string), typeof(TextBox_Hint), new PropertyMetadata(string.Empty));
步骤2:将Window的DataContext设为自身
在Window的构造函数中添加代码,让绑定自动查找窗口自身的属性:
public YourWindowClassName() { InitializeComponent(); DataContext = this; }
步骤3:修改UserControl的绑定表达式
把TextBase的绑定指向窗口的Reame属性,并设置双向绑定+实时更新触发:
<userControls:TextBox_Hint x:Name="TextBox_Reame" Height="40" BorderColorBrush="Black" BorderThickness="0,0,0,1" FontFamily="{DynamicResource Abel}" FontSize="20" FontStyle="Italic" ForegroundColorOverlay="Gray" Hint="Inserisci Il Reame" TextBase="{Binding Reame, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> <userControls:TextBox_Hint.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> <GradientStop Offset="0.0" Color="White" /> <GradientStop Offset="0.5" Color="#FFE1FFE6" /> <GradientStop Offset="1.0" Color="White" /> </LinearGradientBrush> </userControls:TextBox_Hint.Background> </userControls:TextBox_Hint>
关键说明
Mode=TwoWay:确保TextBase与Reame双向同步,一方变更另一方自动更新UpdateSourceTrigger=PropertyChanged:文本内容变化时立即更新绑定源(默认是失去焦点时更新),实现实时同步
内容的提问来源于stack exchange,提问作者user27828246
相关产品推荐
相关产品推荐

