I have a WPF application, powered by Caliburn.Micro, view-model first approach. There's a command-bar type of control with its CommandBarView.xaml and bound CommandBarViewModel. Command-bar VM holds a number of nested VMs, one for each button control, all showing a common interface and having common behaviour. Command-bar VM expose them so they can be bound from view:
public interface IWarningButtonViewModel
{
bool IsVisible { get; }
bool CanShowWarning { get; }
void ShowWarning();
}
public class CommandBarViewModel : PropertyChangedBase
{
public IWarningButtonViewModel UserNotFoundWarning { get; private set; }
public IWarningButtonViewModel NetworkProblemWarning { get; private set; }
// ... initialization omitted for simplicity
}
This is a tentative XAML for a bit of CommandBarView:
<Button x:Name="UserNotFoundWarning_ShowWarning"
IsEnabled="{Binding UserNotFoundWarning.CanShowWarning}">
...
<DataTrigger Binding="{Binding UserNotFoundWarning.IsVisible}" Value="True">
...
</Button>
In this way I'm able to successfully bind the two properties (CanShowWarning, IsVisible) but I'm not able to bind the button command/action to ShowWarning method.
I tried with deep property binding and that works again for properties, but not for action.
I also tried with a mix of cal:Model.Bind
and cal:Message.Attach
:
<Button cal:Model.Bind="{Binding UserNotFoundWarning}"
cal:Message.Attach="[Event Click] = [Action ShowWarning]"
IsEnabled="{Binding CanShowWarning}">
...
<DataTrigger Binding="{Binding IsVisible}" Value="True">
...
</Button>
That seems to work at runtime, but cal:Model.Bind makes the VS designer completely unusable, UI controls are not shown.
I've searched around quite a bit, but I could not find an actual solution that let me also work with designer. It seems strange to me that I could only find examples of deep binding for properties, not for actions.
Any idea how to solve this?
Here is my workaround:
Call
EnableNestedViewModelActionBinding()
once from your bootstrapper and it will allow you to bind actions to nested model's methods using the usual dotted notation. E.g.Edit: please note, that this wouldn't work if you change the nested ViewModel instance at runtime. E.g. if you assign your
UserNotFoundWarning
to something new after the binding happened - Caliburn would still call actions on previous instance.