Click here to Skip to main content
16,009,847 members
Please Sign up or sign in to vote.
3.00/5 (1 vote)
See more:
Dear all
As you know it is very easy to use a ListControl like e.g. ComboBox with self developed classes.
We only have to supply a datasource which does support IList to the ComboBox and set some ComboBox’s properties:

C#
comboBoxGloss.DataSource    = anyting which supports IList;
comboBoxGloss.DisplayMember = "DisplayPropertyName";
comboBoxGloss.ValueMember   = "ValuePropertyName";

Last but not least to control the selected item we can simply add a DataBinding which binds ComboBox’s “SelectedValue” top a suitable property of our own class.

C#
comboBoxGloss.DataBindings.Add("SelectedValue", myClass, "MyValue");

class MyClass
{
  public int MyValue { get; set; }
}


=> So .NET hooks into the "set" method of myclass.MyValue and this in a way in which I do not have to support or pay attention to anything.

My question:
Can I hook in the same way like .NET’s DataBinding and implement my own “property change event sink”? And this without implementing anything in the “set” method of the respective property? Additionally I'm looking for a solution which is completely UI independed.

Sorry for my english, thanks in advance.
Regards
Posted
Updated 17-Jul-12 1:56am
v2

Unfortunately the data binding mechanism is hooked quite deeply into controls, so you will have to implement something yourself. Fortunately, this is quite easy to do in the simple case (where you are binding to a simple property and the source supports INotifyPropertyChanged as the notification mechanism):

public class DataBinding : IDisposable {
 public INotifyPropertyChanged Source { get; private set; }
 public string SourceProperty { get; private set; }
 public object Target { get; private set; }
 public string TargetProperty { get; private set; }
 
 private PropertyInfo sourcePropertyInfo, targetPropertyInfo;

 public DataBinding(INotifyPropertyChanged source, string sourceProperty, object target, string targetProperty){
  Source = source; SourceProperty = sourceProperty;
  Target = target; TargetProperty = targetProperty;

  sourcePropertyInfo = source.GetType().GetProperty(sourceProperty);
  targetPropertyInfo = target.GetType().GetProperty(targetProperty);
 }

 public void Attach(){ 
  Detach(); // to stop double attachment
  source.PropertyChanged += SourceEventHandler;
  Refresh();
 }

 public void Detach() {
  source.PropertyChanged -= SourceEventHandler;
 }

 public void Dispose(){ Detach(); }

 private void SourceEventHandler(object sender, PropertyChangedEventArgs args){
  if(args.PropertyName == SourceProperty || args.PropertyName == null)
   Refresh();
 }

 public void Refresh(){
  targetPropertyInfo.SetValue(target, sourcePropertyInfo.GetValue(source));
 }

}


You can then use this in a way analogous to

var myBinding = new DataBinding(myClass, "MyValue", myComboBox, "SelectedValue");
myBinding.Attach();


... to bind anything to anything else.

You could also put the attachment code in the constructor, but that seems unnatural to me.

(Disclaimer: this is just typed into the posting box, so there might be minor mistakes.)
 
Share this answer
 
Comments
[no name] 17-Jul-12 13:06pm    
Thank you very much for your answer.
This solution I already know. I’m still asking me, is it not possible without implementing INotifyPropertyChanged in MyClass and furthermore also pay attention in the set method of the respective property.

Anyway thanks again.
Regards
BobJanova 17-Jul-12 17:18pm    
You always need to implement INotifyPropertyChanged in the source of a data binding, even using the built-in mechanisms, if you want the target to be updated when the source changes. That's true now when you are binding to a combo, if you want the combo to update when you set MyClass.MyValue.

I wonder if you want the binding the other way around, i.e. something is bound to an instance of MyClass. That's most directly analogous to the combo situation you give, and while a Control doesn't directly support INotifyPropertyChanged, the data binding mechanism is similar, just all done internally instead of through interfaces.

Note that the -target- of a binding doesn't need to know anything about the binding, it will just have its property setter called sometimes.
[no name] 18-Jul-12 3:01am    
Now I’m completely confused.I made my own class:class MyClass{

public int MyValue { get; set; }}

I did not implement anything more then the above. I bind MyClass.MyValue to the combobox’s SelectedValue and everything works fine.

a.) The combobox reflects the selected item according to MyClass.MyValue

b.) If I change in the combobox, MyClass.MyValue will be updated without any further code from my side.

So for me the internal mechanism will handle everything, without pushing me to implement INotifyPropertyChanged and also without implementing anything in “MyClass.MyValue {set}”.

Binding the other way around:

I do not want to bind in the other way. I simply look for a lazy way to get “change events” from a property. Something like MyOtherClass can bind to MyClass.MyValue to get informed about changes.

Finally I found a way. See my Solution 3.


Thank you very much for your timeRegards
BobJanova 18-Jul-12 10:30am    
I didn't know that data binding on a control hooks onto changes for classes that don't implement INotifyPropertyChanged. I'm going to have to play with this later because I'm sure I have done something similar and it didn't work. Your solution is interesting and new to me.
Now I found a way, but I'm not sure whether it is a clean solution (style, performance, ...). Of course I will encapsulate the example below in a class...later... perhaps.

Comments/warnings are welcome.
Regards

Some hours later:
It has side effects, respectively it does only work under some rare/unacceptable circumstances :(

It works only, if the “MyValue” property is bound to a ListControl.
It does only fire the change event if the ListControl does change “MyValue”
It does _not_ work if “MyValue” will be changed programmatically (myClass.MyValue= 2)


C#
// Nothing  special to implement, simply a class with a common auto property

class MyClass
{
  // For this property I like to install a "change listener"
  public int MyValue { get; set; }
}


C#
// Register an "change listener" to a property

class MyApplicationClass
{
  MyClass myClass= new MyClass();

  public MyApplicationClass()
  {
    // Add Listener to a specific object's property. In this case it is myClass.MyValue
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(myClass);
    System.ComponentModel.PropertyDescriptor property = properties.Find("MyValue",
                                                                        false);
    property.AddValueChanged(myClass, new EventHandler(PropValueChanged)); 
  }

  private void PropValueChanged(object sender, EventArgs e)
  {
    // Here I will be informed about changes of MyClass.MyValue
  }
}
 
Share this answer
 
v3
Comments
BobJanova 18-Jul-12 10:29am    
Oh that is nice, I didn't know that was possible.
[no name] 18-Jul-12 12:00pm    
Maybe with a lot of side effects...but let's see, time will show it ;)
N.B: To come to this solution I downloaded the source code from .net and had a look inside how they do it.

Now I will test....


It has side effects, respectively it does only work under some rare/unacceptable circumstances :(

It works only, if the “MyValue” property is bound to a ListControl.
It does only fire the change event if the ListControl does change “MyValue”
It does _not_ work if “MyValue” will be changed programmatically (myClass.MyValue= 2)

All this I think is, because DataBinding relies on a form’s CurrencyManager (more or less)
comboBoxGloss.DataSource = anyting which supports IList;
comboBoxGloss.DisplayMember = "DisplayPropertyName";
comboBoxGloss.ValueMember = "ValuePropertyName";
comboBoxGloss.DataBind();
 
Share this answer
 
Comments
[no name] 17-Jul-12 8:53am    
Sorry, I know how to bind a comboBox. I want to hook in into the event _like_ a combobox.
Regards

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900