WPF: TextBox Text не обновляется
У меня есть пользовательский элемент управления, который я использую внутри DataTemplate
, этот UserControl
содержит TextBox
который связан со свойством Value (объявлен как DependencyProperty
) моего UserControl
, В шаблоне данных я связываю это свойство Value с моим фактическим свойством, скажем, Name (также DependencyProperty
). Он работает правильно, я присваиваю значение свойству Name во время загрузки и мой TextBox
отображает его, я изменяю значение с TextBox
и это обновляет мое свойство Name также. Теперь проблема приходит, пока я добавляю PropertyChangedEventHandler
в свойстве зависимости я проверяю значение, если оно допустимо, ничего не делаю, если оно действительно, и назначаю старое значение, если оно недействительно. Если значение недействительно, когда я присваиваю ему это старое значение, свойство обновляется, но оно не отображает обновленное значение в моем TextBox
из 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
который обновляет свойство Value моего UserControl
, что в свою очередь обновляет имя свойства myClass
Я назначаю PropertyChangedCallback
на мое имя собственности в myClass
, выполняя некоторую проверку и переназначая OldValue
если проверка не пройдена. Это, в свою очередь, обновляет свойство Value, но я все еще вижу, что 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 ответа
После нескольких дней осмотра и большого количества поисков я нашел решение своей проблемы
После всей проверки и присвоения старого значения и обновления свойства зависимости мне нужно вызвать метод UpdateTarget(), чтобы обновить значение в моем TextBox.
Это то, что лучше объясняет решение
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);
}
Это определенно не лучший подход для проверки данных. Есть и другие, более эффективные подходы, которые дадут вам больше гибкости.
- Примените ValidationRule к вашему TexBox. Это моя первая рекомендация, потому что она даст вам контроль над отображением ошибки при сбое проверки. Если вам нужна простая проверка, посмотрите мою статью.
- Прослушайте событие TextBox.TextChanged. Это громоздко и не может быть повторно использовано при взломе.
Не используйте метод обратного вызова DependecyPropertyChanged. Используйте зарегистрированную строку Property и в вашем установщике примените логику, например
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")); } }
Еще раз, как вы можете видеть из моего ответа, вы все равно можете показать код в своем вопросе, чтобы помочь другим ответить на ваш вопрос, независимо от того, насколько сложным может быть ваше решение (если вы хотите получить хороший ответ, вам нужно приложить усилия, чтобы спросить хороший вопрос). Мой ответ может не сработать для вас, но, возможно, он может дать вам некоторые указания "Googling". Надеюсь, поможет.
Похоже, что вы нарушаете привязку, когда устанавливаете значение свойства непосредственно из кода позади.
Вы не должны изменять свойство таким образом. Используйте механизм приведения значений и подтвердите ввод в обратном вызове значения Coerce.