Mare Infinitus
Mare Infinitus

Reputation: 8162

Using caliburn.micro with hierachical viewmodel structure

In a project I use caliburn.micro as MVVM framework.

Now I have a somewhat big viewmodel for a master-details view.

It is hierarchically built.

Just to have a example:

I have a ComputerView with a ComputerViewModel. Everything works fine here.

Now this ComputerViewModel contains a ObservableCollection<HardwareComponentViewModel>

This HardwareViewModel has no View attached, it is just there to keep data in place. Caliburn does not set up Binding correctly here. (I cannot use a x:name to get a Binding)

Until now, that was no problem as I could use the "normal" Binding way. Now I need to add a ActionMessage to a grid in the HardwareComponentViewModel.

To make more clear what I mean, here is the full XAML to reproduce it

<UserControl x:Class="DemoApplication.Views.ComputersView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:cal="http://www.caliburnproject.org"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:s="clr-namespace:System;assembly=mscorlib"
             d:DesignHeight="300"
             d:DesignWidth="300"
             mc:Ignorable="d">
    <Grid>
        <Grid.Resources />
        <Grid.RowDefinitions>
            <RowDefinition Height="10*" />
            <RowDefinition Height="2*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>

        <Border HorizontalAlignment="Stretch"
                BorderBrush="Transparent"
                BorderThickness="0">
            <ScrollViewer HorizontalContentAlignment="Stretch"
                          Background="Yellow"
                          BorderBrush="Transparent"
                          BorderThickness="0"
                          CanContentScroll="True"
                          HorizontalScrollBarVisibility="Auto"
                          VerticalScrollBarVisibility="Auto">
                <ListView x:Name="Computers"
                          HorizontalContentAlignment="Stretch"
                          Background="Red"
                          BorderThickness="0">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <Border Background="Transparent"
                                    BorderBrush="Transparent"
                                    BorderThickness="0">
                                <ListView HorizontalContentAlignment="Stretch"
                                          Background="Black"
                                          ItemsSource="{Binding HardwareComponents}">
                                    <ListView.ItemTemplate>
                                        <DataTemplate>
                                            <Border Background="Aquamarine"
                                                    BorderBrush="DarkGray"
                                                    BorderThickness="1">
                                                <Grid Background="Lime" cal:Message.Attach="[Event Click] = [Action Expand($dataContext)]">
                                                    <Grid.RowDefinitions>
                                                        <RowDefinition Height="20" />
                                                    </Grid.RowDefinitions>
                                                </Grid>
                                            </Border>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                </ListView>
                            </Border>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </ScrollViewer>
        </Border>
    </Grid>
</UserControl>

Update

1. Have tried cal:Bind.Model="{Binding}" on the UserControl, but no effect Took them from this question here

2. In the Grid I tried: cal:Message.Attach="[Event Click] = [Action Expand]" but did not work either

3. I added Logging now and get

Action Convention Not Applied: No actionable element for Expand.

But I do not know what it tries to tell me. Perhaps no action can be applied to Grid?

4. Have now bound it to a button inside the grid, this works. As a parameter I pass the datacontext, which is indeed the HardwareComponentViewModel, but it is bubbled to the most outside ViewModel, where the Binding is set up correctly (ComputerViewModel).

<Button cal:Message.Attach="[Event Click] = [Action Expand($dataContext)]">

So the question is: What do I have to do to get Binding set up correctly? What do I have to do to get ActionMessages in HardwareComponentViewModel called?

Upvotes: 0

Views: 1358

Answers (3)

Mare Infinitus
Mare Infinitus

Reputation: 8162

Finally made it work!

The event that works is MouseDown, not Click!

<Grid cal:Message.Attach="[Event MouseDown] = [Action Expand($dataContext)]" Background="Lime">

Thank you all so much for your help!

To be honest, I do not know why it works, but it expands and collapses like a charm :)

Upvotes: 1

T045T
T045T

Reputation: 597

This is more of a comment, really, but I'm putting this into an answer to have proper code formatting. I've used an EventTrigger in a similar situation, and I remember it working flawlessly:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Click">
        <cal:ActionMessage MethodName="Expand" />
    </i:EventTrigger>
</i:Interaction.Triggers>

where i is the System.Windows.Interactivity namespace, defined in the top-level XAML tag via

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

(Not sure if the exact line should be different for a Desktop app)

Have you tried doing it this way?

Upvotes: 1

Charleh
Charleh

Reputation: 14012

Have you tried

cal:Action.TargetWithoutContext="{Binding DataContext}"

on your button/grid/wherever you need it? I would expect the target of the action to be the current binding by default, but it may not be (not sure exactly how CM wires it up, might look at the source). Regardless, CM needs to know what target to try to bind the action to (the VM) and due to not being bound the standard CM way my guess is that some wiring can't be done automatically and you need to explicitly bind it using the above code

Upvotes: 1

Related Questions