Monday, 16 April 2012

OverviewThis behavior causes a ScrollViewer to automatically scroll to the bottom when it's contents change size. It is useful for TextBox controls inside ScrollViewers so that the cursor doesn't disappear whilst typing.

Thursday, 12 April 2012

After a lot more thinking about this, I've come up with a really neat solution, needs more testing, but here it is in current form. There's a MessageSender and MessageReceiver class which between them handle sending InitMessageBase type objects and allow buffering and requesting of a message if target is not constructed.

The main problem I've faced is that I often want to pass parameters to the target view's view model to prepare it for what it needs to do. It is possible to access properties in the target view model through the ViewModelLocator as each view model has a static property used for the view binding via the non-static properties, however this means that the view models are tightly coupled through the VML and it seems like a bit of a hack.

The example code is from an article page which requires navigation to a links page.

MessagingIt's possible to fire a message out before navigating to pass parameters to the target view model, however, if the target view has never been hit, the associated vm will not not have instantiated so will not receive the message! This can be worked around by calling the VML CreateXXX method however this is still not the elegant solution I was hoping for.

2-Way MessagingTo solve this problem, I figured that when a VM instantiates, ask if any other VM has any parameters for it then register a message pipe for parameters when it is instantiated.

The MessageI created a message which would take a parameter to pass from the source to the target or an action to request a parameter from the source, by the target:

publicclassLinksInitMessage : MessageBase

{

publicArticle
Payload { get; set;
}

publicAction<Article> Callback { get;
set; }

public LinksInitMessage(Article
payload)

{

this.Payload = payload;

}

public LinksInitMessage(Action<Article> callback)

{

this.Callback = callback;

}

}

Source VMFirst off messages need registering (at constructor stage) so that the target VM may message back one it constructs:

privatevoid
RegisterMessenger()

{

//Register any messages

Messenger.Default.Register<LinksInitMessage>(this,
msg =>

{

if (this._linksInitItem
!= null)

{

msg.Callback(this._linksInitItem);

this._linksInitItem = null;

}

});

}

Then when the source VM is ready to navigate , it can send out a message and keep a parameter in case the VM calls back, then navigate:

privatevoid Link()

{

// Send message to Links (it will get it if it's there
otherwise, the VM will request when open)

First off when the VM constructs, it sends out a message to ask if any other VM has any a message for it, if it gets a response it can initialise itself. Second it registers a message type so once it is already instantiated, it can receive params again and re-initialise itself: