IgorShare Thoughts and Ideas

Consulting and Training

Tip: opening a MessageBox in Caliburn

Posted by Igor Moochnick on 03/27/2011

While working with Caliburn V2 I’ve noticed that there is no default View for the message box. It was a bumpy road figuring out how to add one but I’ve learned a lot.

In this post you can see my solution for this challenge, but the flexibility of the framework allows multiple solutions and you may come up with a different one.

The result of this exercise look like this:

image

In my case I wanted to warn the user during the Screen closure if the changes have not been saved. The usual place to hook the check is in “CanClose” method:

public override void CanClose(Action<bool> callback)
{
    if (HasChanges)
    {
        var result = Show.MessageBox("Current item was not saved. Do you really want to close it?",
            "Question", new[] { Answer.Ok, Answer.Cancel });

        result.Completed += (s, e) => callback(result.Answer == Answer.Ok);

        result.ExecuteWithDefaultServiceLocator();
    }
    else
    {
        callback(true);
    }
}

public static class Extensions
{
    public static void ExecuteWithDefaultServiceLocator(this IResult result)
    {
        result.Execute(new ResultExecutionContext(IoC.Get<IServiceLocator>(), null, null));
    }
}

Notice that the result of the “Completed” callback from the MessageBox is used to raise the callback reply for the “CanClose” method.

When I ran the application I’ve received an error from Caliburn that the “QuestionDialogView” was not found. After checking the source I’ve noticed that the View, in fact, is not there. I had to create one. This is my simplified take on the view:

<UserControl ...>
<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
    	<RowDefinition/>
    	<RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <ContentControl x:Name="FirstQuestion" Grid.Row="0">
        <ContentControl.ContentTemplate>
            <DataTemplate>
                <TextBlock x:Name="Text" Text="{Binding Text}" TextWrapping="Wrap" Style="{StaticResource DefaultTextBlockStyle}" />
            </DataTemplate>
        </ContentControl.ContentTemplate>
    </ContentControl>            
    <ItemsControl x:Name="Buttons" Grid.Row="1" HorizontalAlignment="Right" Margin="0,10,0,0">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Button Content="{Binding Content, Converter={StaticResource upperCase}}" cal:Message.Attach="{Binding Action}" Width="70" />
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
		<ItemsControl.ItemsPanel>
			<ItemsPanelTemplate>
				<StackPanel Orientation="Horizontal" />
			</ItemsPanelTemplate>
		</ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>
</UserControl>

After the view was defined – it had to be registered in the IOC to be found. This is how I did it in the bootstrapper:

            builder.With.PresentationFramework()
                .Using(x => x.ViewLocator<DefaultViewLocator>())
                    .Configured(x => x.AddNamespaceAlias("Caliburn.ShellFramework", "MyProject.Common.Views"))

BTW: in the following article you can find a full View definition for the MessageBox. When I’ve replaced my XAML with the XAML from this article – I’ve received exactly the same result:

http://caliburn.codeplex.com/wikipage?title=ISupportCustomShutdown

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: