Tono Nam
Tono Nam

Reputation: 36048

Bind control to property not working

I am creating an application that uses several threads as a result I want to try to use UIControls in my code behind as few as possible. The way I do it is by binding the controls to a property in my code behind that way I will be able to update the control by changing that property it does not matter if that property is updated on a different thread. Anyways I am creating the following code in order for the class to create the bindings form me.

public static class MyExtensionMethods 
{

    public static TextBoxBind<T> BindTextBox<T>(this TextBox textbox, string property=null)
    {
        return new TextBoxBind<T>(textbox,property);
    }
}



public class TextBoxBind<T> : INotifyPropertyChanged
{
    string property;

    protected T _Value;
    public T Value
    {
        get { return _Value; }
        set { _Value = value; OnPropertyChanged(property); }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    protected void OnPropertyChanged(string propertyName){
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public TextBoxBind(TextBox textbox, string property)
    {
        if (property == null)
        {
            property = "Value";
        }
        this.property = property;

        Binding b = new Binding(property)
       {
            Source = this
       };

        b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        textbox.SetBinding(TextBox.TextProperty, b);
    }
}

And on my XAML I have:

 <TextBox  Name="textBox2"  />

Therefore I will be able to use the first code that I posted as:

        var newTextBox2 = textBox2.BindTextBox<int>();
        newTextBox2.Value = 50; // this will update the textBox2.Text = "2"
        // also every time I update the value of textBox2  newTextBox2.Value will update as well

The problem is when I try to bind it to a custom object. Take this code for example:

    public class Person 
    {
        public string Name { get; set; }
        public string Age { get; set; }

        public override string ToString()
        {
            return Age.ToString();
        }            

    }

    void LogIn_Loaded(object sender, RoutedEventArgs e)
    {
        txtUsuario.Focus();

        var newTextBox2 = textBox2.BindTextBox<Person>("Age");

        // here newTextBox2 never updates....


    }

Upvotes: 0

Views: 454

Answers (2)

Silvermind
Silvermind

Reputation: 5944

OnPropertyChanged(property); should be pointing to Value, since that's the Name of your Property. This should not be pointing to the type T. So this code is not right:

if (property == null) 
{ 
  property = "Value"; 
}

because property should always be "Value"

public T Value     
{     
    get { return _Value; }     
    set { _Value = value; OnPropertyChanged("Value"); }     
}  

Upvotes: 0

EvAlex
EvAlex

Reputation: 2938

When it comes to data binding one should update an object (doesn't matter CLR property or DependencyObject) from the same thread, as the UI is running at. If you have a UI element bound to something in code, updating that from a separate thread will lead to exception. However, you can always retrieve your UI thread and perform property update there. Here's a piece of code, that I am using in a similar situation as you have:

ThreadStart updateLogs = delegate()
{
    ObservableCollection<LogMessage> newLogs = this._parcer.Parce();
    foreach (LogMessage log in newLogs)
        LogMessages.Add(log);
};
App.Current.Dispatcher.BeginInvoke(updateLogs, null);

This block of code is running in a thread different to one UI is running at. So I extract the code, that actually updates the binding source (which is LogMessages) into a delegate updateLogs and then run this delegate in a UI thread, passing it to the application dispatcher.

Nevertheless, WPF application can have more than one Dispather if, for example, you create separate windows in separate threads, although this approach is rare. But just in case, DependencyObject class has a Dispatcher property, which references the Dispather that owns this object.

Upvotes: 1

Related Questions