WPF: текст TextBox не обновляется

у меня есть пользовательский элемент управления, который я использую внутри DataTemplate этот UserControl содержит TextBox который связан с стоимостью свойство (объявлено как DependencyProperty) моего UserControl. В шаблоне данных я связываю это стоимостью свойство с моей фактической собственностью сказать имя (также a DependencyProperty). Он работает правильно, я присваиваю значение имя свойство при загрузке и мой TextBox отображает его, я меняю значение с TextBox и он обновляет мой имя собственность. Теперь проблема возникает, когда я добавляю PropertyChangedEventHandler в свойстве зависимостей я проверяю значение, если оно допустимо, ничего не делаю, если допустимо, и назначаю старое значение, если оно недопустимо. В случае недопустимого значения, когда я назначаю ему это старое значение, свойство обновляется, но оно не отображает обновленное значение в my TextBox of UserControl. Кто-нибудь может сказать мне, почему?

XAML моего UserControl:

<UserControl x:Name="usercontrol">
   <StackPanel>
      <TextBlock ......./>
      <TextBox Binding={Binding ElementName=usercontrol, Path=Value, Mode=TwoWay}/>
   </StackPanel>
</UserControl>

в коде позади стоимостью это DependencyProperty

я использую это в моем DataTemplate:

<HierarchicalDataTemplate DataType="{x:Type myLib:myClass}" ItemsSource="{Binding Children}">
    <Expander Header="{Binding}">
        <WrapPanel>
            <edproperty:TextPropertyEditor Caption="Name" Value="{Binding Name, Mode=TwoWay}"/>
            <edproperty:TextPropertyEditor .................../>
            <edproperty:TextPropertyEditor .................../>
            <edproperty:TextPropertyEditor ...................../>
        </WrapPanel>
    </Expander>
</HierarchicalDataTemplate>

этот шаблон я использую в TreeView. Внутри TreeView я ввожу значение в TextBox обновляющий стоимостью свойства моего UserControl, что в свою очередь обновления имя собственность myClass я назначение PropertyChangedCallback мой имя в собственность myClass, выполняя некоторую проверку и переназначение OldValue если проверка неудачи. Он в свою очередь обновляет стоимостью свойство также, но я все еще вижу, что TextBox имеет то же значение, которое я ввел ранее не обновленный.

public string Name
    {
        get
        {
            return (string)GetValue(NameProperty);
        }
        set
        {
            SetValue(NameProperty, value);
        }
    }

    // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty NameProperty =
        DependencyProperty.Register("Name", typeof(string), typeof(myClass), new UIPropertyMetadata(null, OnNameChanged));

    protected static void OnNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        if(checkRequired && !IsValid(e.NewValue.ToString()))
        {
            checkRequired=false;
            (sender as myClass).Name = args.OldValue.ToString();
        }
    }

    private static bool IsValid(string name)
    {
         .............some logic here
    }

4 ответов


после нескольких дней поиска и большого поиска я нашел решение своей проблемы

после завершения проверки и назначения старого значения и обновления свойства dependecy мне нужно cal UpdateTarget() метод, чтобы обновить значение в моем текстовом поле.

Это то, что объясняет решение лучше

http://social.msdn.microsoft.com/forums/en-US/wpf/thread/c404360c-8e31-4a85-9762-0324ed8812ef/


Я знаю, что этот вопрос был о TextBox, но для RichTextBox вы бы использовали UpdateLayout ().

rtb.AppendText("Text");
rtb.ScrollToEnd();
rtb.UpdateLayout();

похоже, что вы нарушаете привязку, когда вы устанавливаете значение свойства непосредственно из кода позади.

вы не должны изменять свойство таким образом. Использовать механизм принуждения значения и проверить ввод в обратном вызове значения принуждения.


Анураг,

есть много предположений, которые я должен сделать здесь, но я дам ему шанс.

у вас, вероятно, есть что-то вроде этого...

// ...
public static string GetValue(Dependency obj)
{
   // ...
}

// ...
public static void SetValue(DependencyObject obj, string value)
{
    // ...
}

// Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
    DependencyProperty.RegisterAttached("Value", typeof(string), typeof(MyCustomControl), new UIPropertyMetadata(OnValuePropertyChanged));

public static void OnValuePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    string newValue = e.NewValue as string;

    // You validate your value here,
    // Then if fails, revert to old value.
    if(!SomeCondtion(newValue)) SetValue(obj,e.OldValue as string);

}

это определенно не лучший подход для проверки данных. Есть и другие, более эффективные подходы, которые дадут вам больше гибкости.

  1. применить ValidationRule на вашем TexBox. Это моя первая рекомендация, потому что она даст вам контроль над отображением ошибки, когда проверка не выполняется. Если вы после простой проверки, проверьте мой статьи.
  2. слушать для TextBox.Событие TextChanged. Это громоздко и не повторно использовать в большинстве взломан.
  3. Не используйте метод обратного вызова DependecyPropertyChanged. Используйте зарегистрированное строковое свойство и в сеттере применяйте логику, например

    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(UserControlWithTextBox));
    
    
    private string _oldValue;
    public string Value
    {
        get { return GetValue(ValueProperty) as string; }
        set
        {
            // Check if the value passes your validation logic
            if(SomeCondtion(value))
            {
                // If yes, then set the value, and record down the old value.
                SetValue(ValueProperty, value);
                _oldValue = value;
            }
            else
            {
                // Else logic fails, set the value to old value.
                SetValue(ValueProperty, _oldValue);
            }
            // Implement INotifyPropertyChanged to update the TextBox.
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
    }
    

еще раз, как вы можете видеть из моего ответа, что вы все еще можете показать код в ваш вопрос помогите другим ответить на ваш вопрос независимо от того, насколько сложным может быть ваше решение (если вы хотите получить хороший ответ, вам нужно приложить усилия, чтобы задать хороший вопрос). Мой ответ может не работать для вас, но, возможно, он может дать вам некоторые "гуглить" направления. Надеюсь, это поможет.