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>

В коде за Value стоит 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, которое, в свою очередь, обновляет свойство Name myClass. Я назначаю PropertyChangedCallback моему Name Свойство в 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
    }

person viky    schedule 30.10.2009    source источник
comment
Не видя вашего кода, будет сложно его правильно прокомментировать. Не могли бы вы опубликовать свой код, пожалуйста?   -  person Pete OHanlon    schedule 30.10.2009
comment
это слишком много, это не может быть опубликовано. Вы можете спросить, хотите ли вы больше объяснений.   -  person viky    schedule 30.10.2009
comment
Нет, можно написать минимальный кусок кода для воспроизведения... Иначе будем гадать, а не отвечать. Никто не любит неопределенности. Особенно программисты..   -  person Anvaka    schedule 30.10.2009


Ответы (4)


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

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

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

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

person viky    schedule 13.11.2009
comment
Благодарю вас! Вы спасли мою жизнь!! - person Yoo Matsuo; 30.07.2010

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

rtb.AppendText("Text");
rtb.ScrollToEnd();
rtb.UpdateLayout();
person mxgg250    schedule 06.12.2011

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

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

person Anvaka    schedule 30.10.2009
comment
я тоже использовал этот способ, но все та же проблема, значение моего текстового поля не обновляется. - person viky; 30.10.2009
comment
Я обновил свой вопрос, можете ли вы мне что-нибудь предложить? Извините за задержку - person viky; 10.11.2009

Анураг,

Здесь я должен сделать много предположений, но я попробую.

У вас, наверное, что-то подобное...

// ...
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"));
        }
    }
    

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

person Tri Q Tran    schedule 31.10.2009
comment
я обновил свой вопрос, извините за задержку, почему это происходит с моим текстовым полем? - person viky; 10.11.2009
comment
Проверка, добавленная в установщик в вашем примере, не будет выполняться, когда WPF обновляет свойство с помощью привязки, установщика или других подобных механизмов. При использовании свойств зависимостей рекомендуется никогда ничего не помещать в ваши средства доступа или мутаторы. - person jpierson; 08.12.2010