WPF: TextBox Text is not updating
Asked Answered
C

4

8

I have a user control that i am using inside a DataTemplate, this UserControl contains a TextBox which is binded with Value property(declared as a DependencyProperty) of my UserControl. In data template I bind this Value property with my actual property say Name (also a DependencyProperty). It works properly, I assign a value to Name property while loading and my TextBox displays it, i change the value from TextBox and it updates my Name property also. Now the problem comes while I add a PropertyChangedEventHandler in the dependency property, I check for the value if it is valid, do nothing if valid and assign old value if not valid. In case of value not valid, when I assign it that old value, property updates but it is not displaying updated value in my TextBox of UserControl. Can anyone tell me why?

XAML of my UserControl:

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

In code behind Value is a DependencyProperty

I am using this in my 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>

This template I am using in a TreeView. Inside TreeView I enter value in the TextBox which updates the Value property of my UserControl, that in turn updates Name property of myClass I am assigning a PropertyChangedCallback to my Name Property in myClass, performing some validation and reassigning the OldValue if the validation fails. It in turn updates Value property also, but i am still seeing that the TextBox has the same value that i entered earlier not the updated one.

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
    }
Cabby answered 30/10, 2009 at 9:26 Comment(3)
Without seeing your code, this is going to be a difficult one to properly comment on. Could you post your code please?Poulard
it is too much, it can't be posted. You can ask if you want more explanation.Cabby
Nope, you can write minimal code piece to reproduce... Otherwise, we will be guessing, not answering. Nobody likes uncertainty. Especially programmers..Credential
C
8

After days of looking around and a lot of search i found the solution of my problem

After all validation done and assigning old value and updating the dependecy property, i need to cal UpdateTarget() method, to Update the value in my TextBox.

This is what explains the solution better

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

Cabby answered 13/11, 2009 at 12:57 Comment(1)
Link is not valid anymore (also not found in archive). Could you maybe try to explain ?Addendum
C
1

I know this question was about TextBox but for RichTextBox you would use UpdateLayout().

rtb.AppendText("Text");
rtb.ScrollToEnd();
rtb.UpdateLayout();
Cheque answered 6/12, 2011 at 17:37 Comment(0)
C
0

It looks like you are breaking binding when you set property value directly from code behind.

You shouldn't modify property that way. Use value coercion mechanism and validate input in the Coerce value callback.

Credential answered 30/10, 2009 at 9:44 Comment(2)
i used this way also but still same problem, value of my textbox doesn't updates.Cabby
i hav updated my question, can u suggest me anything? sorry for delayCabby
N
0

Anurag,

There are a lot of assumptions I have to make here, but I'll give it a shot.

You probably have something like this...

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

}

This is definitely not the best approach to validate data. There are other, more efficient approaches that will give you more flexibility.

  1. Apply a ValidationRule on your TexBox. This is my first recommendation because it will give you control on displaying the error when validation fails. If you're after a simple validation, check out my article.
  2. Listen for the TextBox.TextChanged event. This is cumbersome and is not re-usable at most hacked.
  3. Don't use DependecyPropertyChanged callback method. Use a registered string Property and in your setter, apply logic, e.g.

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

Once again, as you can see from my answer that you can still show code in your question to help others answer your question no matter how complex your solution may be (if you want a good answer, you need to put in the effort to ask a good question). My answer may not work for you but maybe it might give you some "Googling" directions. Hope it helps.

Nipple answered 31/10, 2009 at 1:36 Comment(2)
i hav updated my question, sorry for delay why is it happening with my textbox?Cabby
The validation added to the setter in your example will not occur when WPF updates the property through binding or a setter or through other such mechanisms. It is recommended never to put anything in your accessors or mutators when using dependency properties.Constitutional

© 2022 - 2024 — McMap. All rights reserved.