How is the PropertyChanged event used - mdriven

How is the PropertyChanged event used?
I'm wanting to evaluated the next state of a state machine whenever any property of the class is changed.
Regards Steve

PropertyChanged is part of the standard IPropertyNotifyChanged signaling.
If you want to create side effects if any change is done - consider setting "HasUserCode" on each attribute, Generate code, now you will find a partial method available for you to fill for Set and Get of attributes.
In a setter you can have side effects like running a trigger to step a state machine.

Related

Subscribing to Object value or associated change

Is there some doco on IAutoSubscriptionService.
How do I use using (ESP.GetEcoService().StartSubscribe(subscriber)) to trigger an event when an object changes. That is for any attribute of an object.
The StartSubscribe gives a IDisposable context back and it is typically used like this:
using (theAutoSubscriptionService.StartSubscribe(subscriber))
{
arbitrary c# code accessing model elements
- all access will be added to subscription!
A thing of beauty really!
}
When something later change - the ISubscriber.Receive will fire.
For adhoc usage consider the EventSubscriber class

Xamarin Sport App - What does IsDirty do?

I am looking through the Xamarin Sport app code and trying to understand some of the cool things they are doing in it. I cannot understand what IsDirty is being used for exactly. It gets defined here and implemented here and used in many places, such as here.
I read a little about and ICommand's IsDirty property so maybe it is a way to call an entire model as being dirty, but what implications does that have?
I also see it being used here which I am assuming is why they created it in the first place.
Thanks for y'all's insight into it.
They're just using it as a clever way to handle modification detection. Consider a "Save Changes" feature; you don't actually want to enable the "Save" button until something has changed, and you can key off the IsDirty property to test that.
Technically, you could handle this yourself by having a base class hook INotifyPropertyChanged.PropertyChanged and maintaining a dirty bit of your own (possibly in a base class), but rather than require all of their classes to have an IsDirty property that they may or may not need, they've made it an optional feature that a class can implement. For example, take a look at GameResult for an example of something that can't be changed, and therefore, can't be marked as dirty.
With this approach, you've minimized the amount of code you need to write to implement this functionality. All your derived classes need to do is derive from BaseNotify, implement IDirty, and call SetPropertyChanged(...) as the setter to set the private tracking field, signal to any observers that a property has changed, and automatically set the dirty bit.
NOTE: I did just make an interesting observation: while the implementation of the SetProperty extension method does set the IsDirty flag, the BaseNotify class' IsDirty implementation doesn't call anything to bubble up a PropertyChanged event for IsDirty, which means bindings against it won't get updated when it changes. I believe the fix would be for that extension method to invoke PropertyChanged with the property name "IsDirty":
if(dirty != null) {
dirty.IsDirty = true;
handler.Invoke(sender, new PropertyChangedEventArgs("IsDirty"));
// Yes, I'm a bad person for hard-coding the name.
}
Alternately, you could defer signaling the IsDirty change until after you signal the original property has changed. I just chose to keep it with the original logic.
I think it's relatively simple and you're on the right track: the purpose of that property is to have an easy way to know whether some property has been changed, so the whole object has to be saved. It's baked in to the way property changes are propagated, so you don't have to set it by yourself whenever a property value is being set.
tl;dr: You can use it to check if you your (view)model is worth a save operation ,-).

How to fix "EntityMemberChanged was called without first calling EntityMemberChanging"

This came up time and again for us. After reading such a message, there's nothing intuitive to do and debug.
What this poorly-documented error is trying to say is that you accidentally set up a system in which tracking changes causes more changes.
When Entity Framework changed a property on one of your entities, such as during SaveChanges with identity ID updates, you ran code that changed other tracked properties.
For example, the property that Entity Framework was setting triggered an event, perhaps INotifyPropertyChanged, which perhaps was subscribed to by a BindingSource or some binding list, whose ListChanged event handler was in the UI and triggered a calculation of some other property, and the change tracker detected the second property change.
The simple diagnosis is to place a breakpoint on the SaveChanges() call and immediately after the SaveChanges call(). When the first breakpoint is hit, place a breakpoint on each event handler that could possibly be triggered. (BindingSources are notorious for multiplying each other's events.) Continue debugging. If any breakpoint is hit other than the point immediately following SaveChanges, you know where the problem is.
The simple solution is to set a flag, such as IsSaving, on each side of the SaveChanges call. Then in each misbehaving event handler, do a simple check and do not modify any entities if the DbContext is in the process of saving. Make sure you use finally in case SaveChanges throws an exception that you catch at a higher level:
IsSaving = true;
try
{
await db.SaveChangesAsync()
}
finally
{
IsSaving = false;
}
(One other possibility is that you were changing the entity from multiple threads — never involve the change tracker in multiple threads!)
I had the exact same issue. I had wired to the INotifyPropertyChanged event that created the possibility for a property to change during the SaveChanges() call. I think it is a better practice to unwire the event handlers of you tracked entities when performing dbContext.SaveChanges(), Remove().
I'll explain my experience with this error, hoping it might help someone. And thanks to jnm2 for beautiful explanation.
I had Invoice and Receipt entities, and InvoiceViewModel.
Thie ViewModel was subscribed to Invoice property changed, inside which it was raising CanExecuteChanged events.
I added Receipt to Invoice navigation property and called SaveChanges(), which raised Invoice.ReceiptID property changed and triggered OnPropertyChanged event handler on the ViewModel, which in turn raised all kinds of CanExecuteChanged events.
The problem was that one of the CanCommandNameExecute methods was calling Context.ChangeTracker.HasChanges() which ultimately threw an exception.
How I fixed it?
I followed jnm2, I flagged VM with IsSaving and checked for the flag inside OnPropertyChanged event handler.
Once again, thanks jnm2, and hope someone finds this helpful as well.

How do I add trusted code to a plone 4.x product that can be used by or as a workflow transition script?

I am trying to construct a workflow that can be assigned to arbitrary containers and will have the following behavior. When the container makes the transition from state A -> A', the contents of the container should be checked for their state and moved to a new state that depends on their present state. In other words:
obj1: in state 'a' would be transitioned to 'a*'
obj2: in state 'b' would be transitioned to 'b*'
and so on...
obj1 and obj2 are following the same workflow that branches to a number of final states (approved, denied, alternate, etc...)
I know how to do this, if I can trigger my python code as trusted code. Unfortunately, I have not been able to figure out how or where to put the code in my product so this will work. I have found references to using "external methods", however that seems to be going away. Also I want the code to reside in my project.
I think this is probably simple and I am overlooking something. Help with how to put this in my project or another route to achieving the same goal would be welcome.
The scripts support for DCWorkflow only supports through-the-web-addable objects, which limits you to External Methods there.
A better bet is to use workflow events instead. For each workflow transition, two events are fired:
Products.DCWorkflow.interfaces.IAfterTransitionEvent
Products.DCWorkflow.interfaces.IBeforeTransitionEvent
If you subscribe to either of those events, you can then filter on the correct workflow and transistion to react to transitions from trusted code.
Each event fired has the following attributes:
object: the workflowed object
workflow: the current applicable workflow object
old_state: a Products.DCWorkflow.States.StateDefinition object
new_state: another Products.DCWorkflow.States.StateDefinition object
transition: a Products.DCWorkflow.Transititions.TransitionDefinition object
status: a dictionary with the current workflow variables
kwargs: a dictionary of extra arguments passed in to the change-transition call.
Register a subscriber using ZCML:
<subscriber
provides="zope.component.testfiles.adapter.IS"
factory=".youreventsmodule.aftertransition_handler"
for="Products.DCWorkflow.interfaces.IAfterTransitionEvent"
/>
or, because the transition events are object events, listen only to the transition event if it applies to your objects:
<subscriber
provides="zope.component.testfiles.adapter.IS"
factory=".youreventsmodule.container_aftertransition_handler"
for=".interfaces.IMyContainerType
Products.DCWorkflow.interfaces.IAfterTransitionEvent"
/>
which registers your handler only for transition events on objects with the IMyContainerType interface only.
The handler would be:
def aftertransition_handler(event):
# handle all transition events, ever
or, when limiting it to one object interface:
def aftertransition_handler(obj, event):
# handle all transition events for our container interface

Setting a dependency property's default value at design time in a Windows Workflow Foundation Custom Activity

I'm implementing a Custom Workflow and Activities to be reused in multiple projects and trying to get them to be as easy to use as possible. In this workflow I have a Property whose name is 'UserID' which I'd like to bind to a dependencyproperty in one of my activities. I can currently bind it at design time searching explicitly for the property each time I add one of these activities to the workflow, but I'd like for this activity to be binded automatically.
As far as i know (correct me if I'm wrong), to bind a dependency property at design time I need to specify a string of the form "Activity=NameOfWorkflow, Path=UserID" to the DefaultBindingProperty metadata tag, and I'd like the name of the workflow to be completed in some way. Any way of doing this?
Thanks
I finally managed to achieve this by attaching an ActivityToolboxItem to the Activity, and overriding a method in it that creates the instance shown in the designer. I used an ActivityBind object to bind the dependencyproperty to the workflow's property. To get the instance of the workflow, I just searched for an ancestor to my activity by calling act.Parent until the activity had no parent (and thus was the StateMachineWorkflowActivity itself)