DataWrapper and DataValue change notifications

Feb 28, 2010 at 4:21 PM

Hello Sacha,

I have been using Cinch for quite some time now and I am pretty happy with it. This week-end I started using DataWrappers as I am in a situation where I need certain properties to be editable and others not.

Yet, by doing this, I have been facing a new problem. Before I was relying on callbacks (the one generated by the code generator) to perform certain actions. For example, I have a WizardViewModel with several pages. When I change the CurrentPage, in the callback (CurrentPageChanged), I modify the DisplayName property. Now, I cannot do this anymore because the callback is not called (which is logical since the object didn't change, only its DataValue property changed).

What would you do in such a case? Is there a way to be notified when the DataValue has changed? Should I just stop using DataWrappers when I need this notification?

Thanks in advance for your input.

 

Damien

Mar 14, 2010 at 11:50 AM

I found out that you can simply use the PropertyChanged event from the DataWrapper or the ViewModel itself. I'm still not sure why you wouldn't call the callback in this case though...

Damien

Coordinator
May 2, 2010 at 8:26 AM

When a DataWrapper<T> datavalue changes it does raise a change notification to parent. Ill look into this one though.

Coordinator
May 4, 2010 at 9:16 AM
Damien I have done this now
May 4, 2010 at 10:29 AM

OK Sacha, thank you for notifying me (and all the others on the other threads). I am glad to see you back on Cinch. Can't wait for v2 to be honest!

Coordinator
May 7, 2010 at 5:31 PM

It will be better, but it will break a lot around the services area, but it will be so much better

May 8, 2010 at 8:30 AM

I don't really mind about breaking changes, as long as we can figure them out (in one of your articles, during compilation, in the change set shown by CodePlex...). But it is true that I don't use it in a production application, I use it for personal projects. It is not as critical for me as it might be for others...
Speaking of change sets, I have been wondering about something since you added Cinch in CodePlex. Why do you check in bin and obj folders, ReSharper files, *.user files...? I think it just makes change sets harder to read and archives bigger to download... but maybe I am missing something...

Coordinator
May 9, 2010 at 7:02 AM

Yeah you are right I should get rid of all the crap really, Ill try and clean before I submit in future

Jun 28, 2010 at 8:12 AM

Hello Sacha,

 

I too have been trying to use the callback functions with DataWrappers without success.

I have Cinch 38112 and I can't really upgrade, so I'm trying to find precisely what patch corrected this.

But I just can't seem to find it.  Could you help me ?

 Thanks in advance.

Coordinator
Jul 8, 2010 at 9:40 PM
Oooh to be honest it was a while ago, but I can not remember exactly what build fixed it,. it is in release notes on codeplex comments though. Just do a diff
Jul 9, 2010 at 4:03 PM

Soory, me again.

Obviously I've done a diff and I couldn't identify the patch.

Here's what's written In the release notes of cinch 46013

Cinch Discussions:

DataWrapper and DataValue change notifications, this should work now

 

These have worked for ages. Working as expected.

Does it mean that it's normal that the callback functions are not called when the datavalue of a datawrapper is modified ?

Thanks

 

 

 

 

Coordinator
Jul 9, 2010 at 4:20 PM

No its not normal, but that feature definitely works, and has done for ages. The last chap you complained released he had code error, and I have tried it before after he reported it and it did work. Have a look at the demo code, its all there.

Coordinator
Jul 9, 2010 at 9:22 PM
Edited Jul 9, 2010 at 9:23 PM
Have just tested it and its all ok in CinchV2 as well as V1. Here is what I created using CinchV2.WPF, I created a test VM with a DataWrapper in it, and then a test console app. Here is VM code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using Cinch;

namespace WrapperTest
{
    public class MainWindowViewModel : ViewModelBase
    {
        private Cinch.DataWrapper<Int32> customerId;
        

        public MainWindowViewModel ()
	{
            CustomerId = new DataWrapper<Int32>(this, customerIdChangeArgs);

            PropertyObserver<Cinch.DataWrapper<Int32>> wrapperObserver=new PropertyObserver<DataWrapper<int>>(CustomerId);
            wrapperObserver.RegisterHandler(n => n.DataValue, n => ShowPropertyChangedMessage("DataValue"));
            wrapperObserver.RegisterHandler(n => n.IsEditable, n => ShowPropertyChangedMessage("IsEditable"));



	}


        private void ShowPropertyChangedMessage(string wrapperPropChanged)
        {
            Console.WriteLine(string.Format("Wrapper property {0} changed, DataValue = {1}, IsEditable={2}", 
                wrapperPropChanged, CustomerId.DataValue, CustomerId.IsEditable));
        }


        /// <summary>
        /// CustomerId
        /// </summary>
        static PropertyChangedEventArgs customerIdChangeArgs =
            ObservableHelper.CreateArgs<MainWindowViewModel>(x => x.CustomerId);

        public Cinch.DataWrapper<Int32> CustomerId
        {
            get { return customerId; }
            private set
            {
                customerId = value;
                NotifyPropertyChanged(customerIdChangeArgs);
            }
        }
    }
}
And here is test console code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WrapperTest
{
    public class TestHarness
    {
        [STAThread]
        public static void Main(string[] args)
        {

            StringBuilder sb = new StringBuilder();
            Console.SetOut(new StringWriter(sb));

            MainWindowViewModel vm = new MainWindowViewModel();
            Console.WriteLine("Is Datawrapper dirty " + vm.CustomerId.IsDirty);
            
            //now change DataWrapper, should see outpu that prop has changed
            vm.CustomerId.DataValue = 5;

            vm.CustomerId.BeginEdit();
            vm.CustomerId.DataValue = 6;

            //show BE dirty
            Console.WriteLine("Is Datawrapper dirty " + vm.CustomerId.IsDirty);

            vm.CustomerId.CancelEdit();

            //now change DataWrapper, should see outpu that prop has changed
            vm.CustomerId.DataValue = 11;

            //show NOT be dirty
            Console.WriteLine("Is Datawrapper dirty " + vm.CustomerId.IsDirty);

            //now change DataWrapper, should see outpu that prop has changed
            vm.CustomerId.IsEditable = true;

            Console.ReadLine();

        }
    }
}
And here is the console output
Is Datawrapper dirty False
Wrapper property DataValue changed, DataValue = 5, IsEditable=False
Wrapper property DataValue changed, DataValue = 6, IsEditable=False
Is Datawrapper dirty True
Wrapper property DataValue changed, DataValue = 11, IsEditable=False
Is Datawrapper dirty False
Wrapper property IsEditable changed, DataValue = 11, IsEditable=True
So I am happy that all is totally ok, it must be problem your end
Coordinator
Jul 9, 2010 at 9:24 PM
What exactly do you mean by callback functions, that is something for the generated code partial classes, or do you mean something different
Jul 21, 2010 at 8:23 AM
Edited Jul 21, 2010 at 8:26 AM

Yes, I was trying to use with with datawrapped values, the callBack functions created by the code generator.

They were never called.  The callback functions are called in the set of the DataWrapper : <font size="2">

 public Cinch.DataWrapper<CentreTraitement> CentreTraitement

{
 

get { return centreTraitement; }

 private set 

 

centreTraitement =value;  

//class with notification, when an auto generated property value changes 

Action callback = null;

 if (autoPartPropertyCallBacks.TryGetValue(centreTraitementChangeArgs.PropertyName,out callback))

 

{

callback();

}

}

}

And when a datawrapped value is changed this set function is not called since only its datavalue is changed.

NotifyPropertyChanged(centreTraitementChangeArgs);

 //Use callback to provide non auto generated part of partial

 

Does this mean I must add PropertyObservers in the generated code ?

Coordinator
Jul 21, 2010 at 4:44 PM
Edited Jul 21, 2010 at 4:47 PM

OK so I think you are getting confused, The DataWrapper callbacks as generated by the code generator will be called whenever a new DataWrapper<T> is assigned to the property. But as I show in the example code I posted above, whenever an internal value within the DataWrapper<T> itself changes the parent INPC property of the hosting object will fire. This is not the same as the callback at all, as that WILL only fire whenever a brand new DataWrapper<T> is assigned to a DataWrapper<T> property in the code generator. 

If this is something you require and still want to use the generator I think you would also need to pass in a callback into a modified DataWrapper that would additinally call back a Action delegate, it would not take that much effort to modify the DataWrapper code to do that, but I just do not have time right now, I will put it on my list.

You could listen for INPC changes (again not the same as the generator call backs) from the DataWrapper<T> within the non generated portion of the code, that would be ok too I guess. Yes do it in the NON generated part, otherwise it will get wiped out every time you use the code generator again.

 

Like I say Ill put it on my list of things to do ok.

 

Coordinator
Jul 22, 2010 at 11:23 AM

CROM

 

I have been thinking about this, and you could do this easily. So grab the DataWrapper<T> code, and put it in your project, and simply add a constructor that takes an Action, store that as a field (field starts as null), and when the DataValue or IsEditable change, check for that Action (pass in on constructor) not being call, call it.

 

This would mean your g.cs and .cs generated parts would need to use your own specialised DataWrapper<T> until I get this change into CInch codebase, which may be a while as I am saving up any changes until I have a big chunk to do.

 

But you can modify the generated code to full qualify the code produces to use your own DataWrapper<T> objects instead of Cinch, so where they are declared you would have something like CROB.DataWrapper<T> instead of Cinch.DataWrapper<T>

 

And you could then do something like this in your non generated code

 

Action somePropCallback = new Action(SomePropChanged);
SomeProp = new Cinch.DataWrapper<Person>(this,somePropChangeArgs, somePropCallback );
private void SomePropChanged()
		{
		      //You can insert code here that needs to run 
		      //when the SomeProp property changes
		}