简体   繁体   中英

How to access ShellViewModel in an Caliburn.Micro application?

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.

var parent = IoC.Get<ShellViewModel>();

我目前无法验证该语法,但我认为这是正确的。

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

eg

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 (ie stop listening when the are not active by subscribing on OnActivate and unsubscribing on OnDeactivate ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM