简体   繁体   中英

How to bind WindowsCommands with Caliburn.Micro in Metro?

I just added the MahApps.Metro WPF UI package to an existing WPF application, for which I use Caliburn.Micro . In my MainView I had a menu with buttons, which switched the content of the main area of the UI, as follows:

<DockPanel>
     <Button DockPanel.Dock="Left" Style="{StaticResource MenuButton}" Name="ShowHomeVM">
</DockPanel>

and in the MainViewModel , I have the following method bound by naming convention,

public void ShowHomeVM() {
    CentralVM = HomeVM;
}

and the CentralVM view model instance is bound to the content of the window. Now, with Metro I'd like to move my menu to the windows title bar as follows

<Controls:MetroWindow.LeftWindowCommands>
    <Controls:WindowCommands>
        <Button Name="ShowHomeVM" Content="Home"/>
    </Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>

and that works, except Caliburn does not bind the button to the method in the view model anymore.

How should one bind methods to buttons in the title bar with caliburn.micro?

I found out that Caliburn.Micro can still help, maybe not as comfortable as binding by name, but you can use the Message.Attach from the caliburnproject namespace.

I did it like this:

xmlns:cal="http://www.caliburnproject.org"

<Controls:MetroWindow.LeftWindowCommands>
    <Controls:WindowCommands>
        <Button Content="Home" cal:Message.Attach="[Event Click] = [Action ShowHomeVM()]"/>
    </Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>

Hope this helps.

Caliburn.Micro can't handle these situations. Your only options are:

  1. Fork the Caliburn.Micro source and fix it yourself.
  2. Drop Caliburn.Micro and use a different MVVM framework.

This does indeed not go with built-in features of Caliburn.Micro. Instead of changing the internals of the framework which was suggested by @Keith, I just wired up the buttons by hand, namely in my MainView I define buttons as follows,

<Controls:MetroWindow.LeftWindowCommands>
    <Controls:WindowCommands>
        <Button Content="Home" Command="{Binding HomeCommand}"/>
        <Button Content="Import" Command="{Binding ImportCommand}"/>
        <Button Content="Players" Command="{Binding PlayerCommand}"/>
    </Controls:WindowCommands>
</Controls:MetroWindow.LeftWindowCommands>

Here I am binding the Command property to Commands in the MainViewModel , which looks as follows,

public class MainViewModel : PropertyChangedBase {

    // ... other stuff ... 

    public ICommand HomeCommand { get; private set; }
    public ICommand PlayerCommand { get; private set; }
    public ICommand ImportCommand { get; private set; }

    public MainViewModel(IEventAggregator eventAggregator) {

        // ... other stuff ... //

        HomeCommand = new RelayCommand(o => CentralVM = HomeVM, o => true);
        PlayerCommand = new RelayCommand(o => CentralVM = PlayersVM, o => true);
        ImportCommand = new RelayCommand(o => CentralVM = ImportVM, o => true);
    }
}

As for the RelayCommand class, I am using the implementation given here . The first argument in the constructor is the action that the command should execute, the second is whether it should be able to execute it - which I want to be always true for menu buttons (for now).

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