Command Binding in WPF

Command Binding in WPF

Old forum URL: forums.lhotka.net/forums/t/5660.aspx


JZuerlein posted on Thursday, October 23, 2008

I'm using a MVVM pattern with Prism, and I have run into a problem with Commands.

*I'm not using the CslaDataProvider in my app.

In my ViewModel object, I have a property "Server" that is an editableroot.  There is a function ("SaveServerEditsCommand") that takes in a "Server" object and performs the save operation on it.  What is odd is that the Save performs correctly, and the IsDirty flag gets set to false.  However, when the function completes, the "Server" object's IsDirty flag is set to true. Has anyone seen something like this happen?

<Button Content="Save" Command="{Binding Path=SaveServerEditsCommand}" CommandParameter="{Binding Path=Server, Mode=TwoWay}">

private void SaveServerEdits(CSLABusinessObjects.Server server)

{

if (server == null) return;

try

{

server.ApplyEdit();

Server savable = server.Clone();

server = savable.Save();

(server as Csla.Core.ISavable).SaveComplete(server);

server.BeginEdit();

catch

{

}

SaveServerEditsCommand.RaiseCanExecuteChanged();

CancelServerEditsCommand.RaiseCanExecuteChanged();

}

RockfordLhotka replied on Thursday, October 23, 2008

I don't see the specific issue. Here are some comments:

  1. If you use AutoCloneOnUpdate (which is the default in CSLA 3.5 and higher) you shouldn't do the clone yourself - the data portal is already doing the clone
  2. You shouldn't use the "as" keyword like you are - "as" can always return null and should ONLY be used with appropriate null value checking. In your case a direct cast is the correct answer (for your SaveComplete() call)
  3. I suspect that some code in your SaveComplete() handler is altering a property in the new object, and that's why it is marked with IsDirty of true. Is server.IsDirty true IMMEDIATELY after the Save() call completes?
    1. If it is dirty immediately after Save(), then in your DataPortal_Insert/Update method you are probably using SetProperty() rather than LoadProperty(). The data portal now calls MarkOld() before calling DataPortal_XYZ, so if your DataPortal_XYZ method alters the object's state it would be dirty.

 

JZuerlein replied on Thursday, October 23, 2008

Thank you for the response.  I made the modifications you suggested in points 1 and 2.  There is no SaveComplete() handler.  I put breakpoints on the lines in red.  The first breakpoint to hit is the one in CanSaveServerEdits.  This is because I raised the SaveServerEditsCommand.RaiseCanExecuteChanged event.  The parameter passed into the function is dirty.  The next breakpoint to hit is the one last one in SaveServerEdits, telling me that the object is not dirty.  This suggests to me that there are actually two objects.

I'm wondering if WPF is creating a clone of the datacontext object before passing it as a command parameter.  Any ideas on how to trouble shoot it?

private bool CanSaveServerEdits(CSLABusinessObjects.Server server)

{

if (server == null) return false;

return server.IsSavable;

}

private void SaveServerEdits(CSLABusinessObjects.Server server)

{

if (server == null) return;

try

{

server.ApplyEdit();

server = server.Save();

((Csla.Core.ISavable)server).SaveComplete(server);

server.BeginEdit();

}

catch(Exception ex)

{

}

SaveServerEditsCommand.RaiseCanExecuteChanged();

CancelServerEditsCommand.RaiseCanExecuteChanged();

if (server.IsDirty)

return;

else

return;  //  Breakpoint stops here.

}

RockfordLhotka replied on Thursday, October 23, 2008

So to be clear, you are saying that IsDirty is false at the BOTTOM of your method, but that the object WPF binds to has IsDirty as true. Meaning that WPF isn’t binding to the object you get back from Save().

 

So my question is this: where does your code update the form’s DataContext to use the new object?

 

THERE ARE TWO OBJECTS – the Save() method returns a new object. If you don’t tell WPF to use that new object, it will just keep using the old object.

 

When using a data provider, the DataContext is updated automatically. But using your approach, it seems to me that your code will need to update the DataContext somehow.

 

Rocky

JZuerlein replied on Thursday, October 23, 2008

To setup the binding, I have a ServerView object that has a Model property.  When the Model property is set, the ServerViewModel is assigned to the DataContext property of the ServerView.  The actual assignment occurs when the ServerViewModel is constructed.

I get the idea that calling EditableRoot.Save() will return another object.  So I think what I'm hearing is that calling...

server = server.Save();

will cause a disconnect with databinding, and the DataContext will not be updated.

 

 

RockfordLhotka replied on Thursday, October 23, 2008

The Save() method returns a new instance of the object. You need to get your view to bind to that new object.

 

Rocky

Copyright (c) Marimer LLC