DependencyProperty в моем UserControl не может обновить привязанное свойство в ViewModel - PullRequest
3 голосов
/ 17 декабря 2010

Я создал usercontrol, который содержит TextBox с некоторыми пользовательскими настройками, и я хочу связать свойство Text со свойством в моей ViewModel.

Я выделил проблему в пример решения и смог обновитьсвойство Text со значением свойства ViewModel, но когда я пишу в текстовое поле и покидаю текстовое поле, мое свойство Person.Name не обновляется.

Мой usercontrol 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 не помогает, поскольку метод set Name не доступен при обновлении моего пользовательского TextBox.

Ответы [ 3 ]

4 голосов
/ 21 декабря 2010

Проблема в том, что TextBox внутри вашего TextBoxReadOnlyLooksDisabled UserControl не имеет двусторонней привязки к свойству Text - вы обновляете TextBox только программно (в обработчике 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 соответственно:

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 голос
/ 20 декабря 2010

Ну, проблема, с которой вы столкнулись, вызвана тем, что свойство зависимостей Text TextBox внутри вашего пользовательского TextBoxReadOnlyLooksDisabled на самом деле не привязано к вашей "ViewModel" (классу Person), и поэтому, когда вынапишите что-нибудь, что txtTextBoxBase его Text dp изменено, но это изменение не передается обратно в ViewModel.Что вы можете сделать, это подключить Text dp вложенного TextBox к Text dp вашего пользовательского элемента управления с помощью:

<TextBox x:Name="txtTextBoxBase"
         Text={Binding Path=Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBoxReadOnlyLooksDisabled}}} />
0 голосов
/ 17 декабря 2010
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 обнаружил изменение и обновил его значение.

...