我的UserControl中的DependencyProperty无法更新ViewModel中绑定的属性

3

我制作了一个包含自定义行为的TextBox的用户控件,并且我想将Text属性绑定到ViewModel中的某个属性。

我已经将问题隔离到一个示例解决方案中,并成功使用ViewModel属性值更新了Text属性,但是当我写入文本框并离开文本框时,我的Person.Name属性没有被更新。

我的用户控件XAML:

<UserControl x:Class="WpfCustomUserControlBinding.TextBoxReadOnlyLooksDisabled"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Control.Resources>
    <Style x:Key="readOnlyTextbox">
        <Style.Triggers>
            <Trigger Property="TextBoxBase.IsReadOnly" Value="True">
                <Setter Property="TextBoxBase.Background" Value="WhiteSmoke" />
                <Setter Property="TextBoxBase.Foreground" Value="#FF6D6D6D" />
                <Setter Property="TextBox.BorderBrush" Value="DarkGray" />
                <Setter Property="TextBoxBase.BorderThickness" Value="1,1,1,1" />
            </Trigger>
            <Trigger Property="TextBoxBase.IsReadOnly" Value="False">
                <Setter Property="TextBoxBase.Background" Value="White" />
                <Setter Property="TextBoxBase.Foreground" Value="Black" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Control.Resources>

<TextBox Style="{StaticResource readOnlyTextbox}" x:Name="txtTextBoxBase" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />

代码后端代码:

public partial class TextBoxReadOnlyLooksDisabled
{
    public TextBoxReadOnlyLooksDisabled()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof (string)
                                                                                         , typeof (TextBoxReadOnlyLooksDisabled)
                                                                                         ,new PropertyMetadata(OnTextChange));

    private static void OnTextChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBoxReadOnlyLooksDisabled = (TextBoxReadOnlyLooksDisabled) d;
        textBoxReadOnlyLooksDisabled.txtTextBoxBase.Text = (string) e.NewValue;
    }

    public string Text
    {
        get { return (string) GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
}

我尝试让样例工作的窗口:

<Window x:Class="WpfCustomUserControlBinding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:src="clr-namespace:WpfCustomUserControlBinding" Title="MainWindow" Height="153" Width="525">
<Window.Resources>
    <src:Person x:Key="myDataSource"/>        
</Window.Resources>
<Grid >
    <Label Content="Plain vanilla" Height="26" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" Width="143" />
    <Label Content="Messed up version" Height="26" HorizontalAlignment="Left" Margin="12,61,0,0" Name="label2" VerticalAlignment="Top" Width="143" />
    <TextBox Height="23" HorizontalAlignment="Left" Margin="152,15,0,0" x:Name="txtVanlig" VerticalAlignment="Top" Width="251" Text="{Binding Source={StaticResource myDataSource}, Path=Name, Mode=TwoWay}"/>

    <src:TextBoxReadOnlyLooksDisabled Height="23" HorizontalAlignment="Left" Margin="152,61,0,0" x:Name="txtVrien" VerticalAlignment="Top" Width="251" Text="{Binding Source={StaticResource myDataSource}, Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>

样例值类:

 public class Person
{
    private string _name = "King Chaos";

    public string Name{get{return _name;}set{_name = value;}}
}

感谢您的提前帮助。 ;)
编辑:添加INotifyPropertyChanged并不能解决问题,因为当更新自定义文本框时,Name属性的set方法不会被访问到。
3个回答

4
问题在于,您的TextBoxReadOnlyLooksDisabled用户控件中的文本框没有与Text属性进行双向绑定 - 只有在属性值更改时才会以编程方式更新文本框(在OnTextChanged处理程序中),但反之则不然。
为什么不完全放弃更改处理程序,改为添加绑定,如下所示:
<UserControl x:Class="WpfCustomUserControlBinding.TextBoxReadOnlyLooksDisabled"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Control.Resources>        
  //...
</Control.Resources>

<TextBox Style="{StaticResource readOnlyTextbox}"
         x:Name="txtTextBoxBase"
         HorizontalAlignment="Stretch"
         VerticalAlignment="Stretch"
         Text="{Binding Path=Text, Mode=TwoWay}"/>

不要忘记相应地设置DataContext:

同时也要设置DataContext:

public partial class TextBoxReadOnlyLooksDisabled : UserControl
{
    public TextBoxReadOnlyLooksDisabled()
    {
        InitializeComponent();
        DataContext = this;
    }

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string),
                                                                                         typeof(TextBoxReadOnlyLooksDisabled));

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
}

1

嗯,您遇到的问题是由于您自定义的TextBoxReadOnlyLooksDisabled中的TextBoxText依赖属性实际上没有绑定到您的“ViewModel”(即Person类),因此当您在txtTextBoxBase中写入内容时,它的Text dp会发生变化,但该变化不会传播回ViewModel。 您可以使用以下代码将嵌套的TextBoxText dp与自定义控件的Text dp连接起来:

<TextBox x:Name="txtTextBoxBase"
         Text={Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBoxReadOnlyLooksDisabled}}} />

如果我理解正确的话,您找到了问题所在,但是您的示例代码并没有解决问题。因此,悬赏将授予gstercken。感谢您的回答。 - Slampen
啊,是的,我忘记添加双向绑定模式了。如果你添加了它,应该可以使用我假设的绑定方式工作,而不必像gstercken建议的那样“烧毁”你的TextBoxReadOnlyLooksDisabled的DataContext。 - xenry

-2
public class Person : INotifyPropertyChanged
{ 
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name = "King Chaos"; 

    public string Name{
       get{
          return _name;
       }
       set{
          _name = value;
          if (PropertyChanged != null)
              PropertyChanged(this, new 
                 PropertyChangedEventArgs("Name"));
       }
    } 
} 

简单来说,您的模型必须实现INotifyPropertyChanged接口,并在每次设置属性时引发属性更改事件,以便XAML检测到更改并刷新其值。


可能是一个错误,但并没有起作用。当我更新自定义文本框时,Name属性的setter没有被访问到。 - Slampen
1
你在发布前验证了你的解决方案吗? - Slampen
我没有义务测试这个,你是在寻求帮助,人们会指引你方向,但没有人会为你测试和解决问题。 - Akash Kava

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接