Reputation: 5375
I have a WPF application with Caliburn.Micro. The main ViewModel is ShellViewModel. It contains a tab control, and each tab contains a user control. I need to access a property of ShellViewModel from that internal user control.
var par = ((MyApp.ShellViewModel)((Screen)Parent).MyProperty;
ShellViewModel is not known though. Could you please tell how I can access it?
Thanks.
Upvotes: 0
Views: 2394
Reputation: 14012
Ok from your comments it sounds like you have a combobox on the shell which needs to affect what is displayed on one of the tabs.
To communicate between your ViewModels, you can always use the EventAggregator
which is part of CM and implements a subscriber pattern which you can take advantage of
e.g.
On your shell VM you can create a static instance of the aggregator or create a separate static class which will provide the aggregator to the application
static class AggregatorProvider
{
// The event aggregator
public static EventAggregator Aggregator = new EventAggregator();
}
class ShellViewModel : Conductor<IScreen>
{
// When the combo box selection changes...
public void SelectionChanged(object SomeValue)
{
// Publish an event to all subscribers
AggregatorProvider.Aggregator.Publish(new SelectionChangedMessage(SomeValue));
}
}
You handle the SelectionChanged
of the combobox by using a standard action message or convention (I'm not sure what conventions CM applies by default to the combo so I'll show the explicit bindings in my example)
<ComboBox x:Name="MyCombo" cal:Message.Attach="[Event SelectionChanged] = [Action SelectionChanged(MyCombo)" />
Hopefully if the correct conventions are applied, you should get the selected item being passed to the method
Your child VM just needs to subscribe to the aggregator and implement IHandle where T is the type of message it should handle
class ChildViewModel : Screen, IHandle<SelectionChangedMessage>
{
public ChildViewModel()
{
// Subscribe to the aggregator so we receive messages from it
AggregatorProvider.Aggregator.Subscribe(this);
}
// When we receive a SelectionChangedMessage...
public void Handle(SelectionChangedMessage message)
{
// Do something with the new selection
}
}
The SelectionChangedMessage
can just be:
class SelectionChangedMessage
{
public object NewValue { get; private set; }
public SelectionChangedMessage(object newValue)
{
NewValue = newValue;
}
}
Obviously the above could be a generic type so that you strongly type the NewValue
parameter - then again the message you publish can be anything, so it's up to you
It might be worth pointing out that you can Unsubscribe
from the aggregator so you can control when it receives notifications. The aggregator uses weak references anyway so you don't need to worry too much about unsubscribing, but it does mean you have control over when your objects receive messages (i.e. stop listening when the are not active by subscribing on OnActivate
and unsubscribing on OnDeactivate
).
Upvotes: 2
Reputation: 9478
var parent = IoC.Get<ShellViewModel>();
I can't verify that syntax at the moment but I think it's correct.
Upvotes: 2