Listbox - using message.attach for double click event?

Dec 4, 2010 at 12:17 PM

Good day,

Hopefully this is a simple question, but I am not having luck getting things to work.

 

Can anyone provide an example of xaml that wires up a MouseDoubleClick event to a bound ListBoxItem in a WPF ListBox using the cal:Message.Attach capability?

 

this is the sample data template that I am using inside the item template

          <DataTemplate><Border Margin="2" Padding="2" BorderBrush="DimGray" BorderThickness="1" CornerRadius="2" >
                                <StackPanel Orientation="Vertical" >
                                    <StackPanel Orientation="Horizontal" >
                                        <TextBlock Text="{Binding Path=DisplayName}" Margin="2" Padding="2" FontWeight="UltraBold" />
                                        <TextBlock Text="{Binding Path=Req.Width}" Margin="2" Padding="2" FontWeight="Bold" />
                                        <TextBlock Text="{Binding Path=Req.Material}" Margin="2" Padding="2" FontWeight="Bold" />
                                    </StackPanel>
                                    <TextBlock HorizontalAlignment="Right" Text="{Binding Path=Req.Length,StringFormat=N0}" Margin="2" Padding="2"  />
                                </StackPanel>
                            </Border></DataTemplate>

 

This is the event I'm attempting to wire up.

cal:Message.Attach="[Event MouseDoubleClick] = [Action Function($dataContext)]"

 

I was able to get a MouseEnter event to work when placing the Message.Attach on the border element, but this didn't seem to work with the MouseDoubleClick.

Thanks,

James

 

Coordinator
Dec 4, 2010 at 1:46 PM

Can yo confirm that that event exists on Border?

Dec 4, 2010 at 2:23 PM

Thanks for the quick response.

 

with the following element, the message is fired when I enter the border with the mouse 

<Border Margin="2" Padding="2" BorderBrush="DimGray" BorderThickness="1" CornerRadius="2" cal:Message.Attach="[Event MouseEnter] = [Action Function($dataContext)]">

 

with the following element, the message does not fire when I double click with the mouse on the list item

<Border Margin="2" Padding="2" BorderBrush="DimGray" BorderThickness="1" CornerRadius="2" cal:Message.Attach="[Event MouseDoubleClick] = [Action DblClickTestFunction($dataContext)]">

 

Looking at the Caliburn log, I see that the following was reported (it appears once for each list item)

INFO: [2010-12-04T10:15:43.6461896-05:00] Action: DblClickTestFunction availability update.

So, I it appears that the CM is wiring the event, but the MouseDoubleClick event is not firing properly or something else is happening that I don't fully comprehend yet.

 

Is there another way to confirm that the event exists properly?  Any other suggestions?

 

Thanks,

James

Coordinator
Dec 4, 2010 at 2:44 PM
Edited Dec 4, 2010 at 2:44 PM

The availability update happens initially just to make sure that the action is available for execution. It may be that the event isn't raised because it is either swallowed by another element, or perhaps it can't be captured by the border. Does your border have a background? If not, chances are that it can't receive click events. Try setting it to some color.

Dec 4, 2010 at 4:00 PM

Thanks for the response.

 

 I added a Background="Transparent" and that allowed the event to be raised.

(Never would have thought of that... )

 

James

Dec 16, 2010 at 10:39 AM
Edited Dec 16, 2010 at 10:48 AM

Hi, and thanks for this discussion : I'm facing the same problem.

1) I'm trying to attach an "OpenItem($dataContext)" action to an item double-click on on listbox, but can't find a way to make it properly works.

Moreover, the Border class does'nt seems to expose any MouseDoubleClick even (check MSDN), so the method will certainly never be called. (Certainly because it does'nt inherit from Control).

Code sample :

<ListBox ItemsSource="{Binding AllItems}" SelectedItem="{Binding Path=SelectedItem}">
  <ListBox.ItemTemplate>
    <DataTemplate DataType="{x:Type ts:MyType}">
      <Border Background="#eee" cal:Message.Attach="[Event MouseDoubleClick] = [Action OpenItem($dataContext)]">
        ...
      </Border>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

Edit : I've added a simple <Label> in my border and the OpenItem() is now raised.

<ListBox ItemsSource="{Binding AllItems}" SelectedItem="{Binding Path=SelectedItem}">
  <ListBox.ItemTemplate>
    <DataTemplate DataType="{x:Type ts:MyType}">
      <Border Background="#eee">
        <Label cal:Message.Attach="[Event MouseDoubleClick] = [Action OpenItem($dataContext)]">Item</Label>
      </Border>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

So, I will certainly wrap items in a control which exposes MouseDoubleClick event, like ContentControl...

2) I was using MouseDoubleClick event on the ListBox itself to call an Open() action which uses my VM SelectedItem property.

But the CanOpen() method was used to disable the entire ListBox control (I have also a "Open" button which required the CanOpen method to disable it).

3) So, less specifically :

I want to create a listbox and an "Open" button. when the user double click on an item it opens it. If he clicks the open button (and when an item is selected) it also opens this item.

4) the "CanOpen()" method thoe the action "Open()" seems to not be called when the SelectedItem property changes. Should I raise a specific PropertyChanged event ?

Thanks,

Dec 16, 2010 at 10:56 AM
styx31 wrote:

1) I'm trying to attach an "OpenItem($dataContext)" action to an item double-click on on listbox, but can't find a way to make it properly works.

Moreover, the Border class does'nt seems to expose any MouseDoubleClick even (check MSDN), so the method will certainly never be called. (Certainly because it does'nt inherit from Control).

Code sample :

<ListBox ItemsSource="{Binding AllItems}" SelectedItem="{Binding Path=SelectedItem}">
  <ListBox.ItemTemplate>
    <DataTemplate DataType="{x:Type ts:MyType}">
      <Border Background="#eee" cal:Message.Attach="[Event MouseDoubleClick] = [Action OpenItem($dataContext)]">
        ...
      </Border>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

Edit : I've added a simple <Label> in my border and the OpenItem() is now raised.

<ListBox ItemsSource="{Binding AllItems}" SelectedItem="{Binding Path=SelectedItem}">
  <ListBox.ItemTemplate>
    <DataTemplate DataType="{x:Type ts:MyType}">
      <Border Background="#eee">
        <Label cal:Message.Attach="[Event MouseDoubleClick] = [Action OpenItem($dataContext)]">Item</Label>
      </Border>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

So, I will certainly wrap items in a control which exposes MouseDoubleClick event, like ContentControl...

Got it ! I've applied a style on the itemcontainer :


<ListBox ItemsSource="{Binding AllItems}" SelectedItem="{Binding Path=SelectedItem}">
  <ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
      <Setter Property="cal:Message.Attach" Value="[Event MouseDoubleClick] = [Action OpenItem($dataContext)]"/>
    </Style>
   </ListBox.ItemContainerStyle>
  <ListBox.ItemTemplate>
    <DataTemplate DataType="{x:Type ts:MyType}">
      <Border Background="#eee">
        ...
      </Border>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

The OpenItem action is now invoked when I double click an item.

The point 4) remains.

Feb 5, 2011 at 5:18 PM
Edited Feb 5, 2011 at 5:25 PM

For the DataGrid, the key is also the ItemContainerStyle.

<DataGrid x:Name="DocList">

    <DataGrid.ItemContainerStyle>
        <Style TargetType="{x:Type DataGridRow}">
            <Setter Property="cal:Message.Attach" Value="[Event MouseDoubleClick] = [Action ShowDocEdit($dataContext)]"/>
        </Style>
    </DataGrid.ItemContainerStyle>

    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=Model.DocRef}" Header="Doc Ref." Width="SizeToHeader"/>
        <DataGridTextColumn Binding="{Binding Path=Model.DocDate}" Header="Doc Date" Width="SizeToHeader"/>
        <DataGridTextColumn Binding="{Binding Path=Model.DocClassName}" Header="Doc Class Name" Width="SizeToHeader"/>
        <DataGridTextColumn Binding="{Binding Path=Model.DocTypeName}" Header="Doc Type Name" Width="SizeToHeader"/>
        <DataGridTextColumn Binding="{Binding Path=Model.DocStatusName}" Header="Doc Status Name" Width="SizeToHeader"/>
        <DataGridTextColumn Binding="{Binding Path=Model.RecipientName}" Header="Recipient Name" Width="SizeToHeader"/>
        <DataGridTextColumn Binding="{Binding Path=Model.SenderName}" Header="Sender Name" Width="SizeToHeader"/>
        <DataGridTextColumn Binding="{Binding Path=Model.Subject}" Header="Subject" Width="*"/>
    </DataGrid.Columns>

</DataGrid>

and you can MouseDoubleClick on any column.

Now some context. I have a DocListViewModel that has a DocList property declared like this

public ObservableCollection<DocInfoViewModel> DocList

The ShowDocEdit method is like this:

public void ShowDocEdit(object context)
{
    var docID = ((DocInfoViewModel)context).Model.DocID;
    ((ShellViewModel)Parent).ActivateItem(new DocEditViewModel(docID));
}

I cast the context to the ObservableCollection item type and grab whatever I want (in this case Model.DocID).