简体   繁体   中英

How to handle Click event on a custom WPF control composed of controls that don't have Click events

I am creating a custom ToolBar control that I will be able to use in my WPF application.

My CustomToolBar control is based on a StackPanel control and will contain multiple CustomToolBarButton controls.

My CustomToolBarButtons are based on a vertical StackPanel and contain an Image control and a Label control.

I want to programmatically create a Click event for my CustomToolBarButtons that will fire when Image or label gets clicked. Unfortunately, neither Image nor Label controls have Click events in WPF.

It's a surprise for me because I am used to WinForms controls and vast majority of them have Click events by default. Do I have to create custom Image and Label controls and create Click events for them or is there a cleaner and simpler way of doing this?

Thanks for any help!

Well, there's not a great and simple way using standard functionality. I got around this by making my own trigger (derived from System.Windows.Interactivity.TriggerBase from the Blend SDK) so that in my projects I can do the following:

     <Label> 
         <i:Interaction.Triggers>
             <mu:MouseTrigger MouseButton="Middle" MouseAction="Click">
                 <i:InvokeCommandAction Command="{Binding Path=Close}" />
             </mu:MouseTrigger>
         </i:Interaction.Triggers>
     </Label>

Effectively the MouseTrigger class will handle MouseDown and MouseUp events from the UIElement it's attached to and use that to invoke the actions associated with the trigger. The code is a bit more complex than just that, though, since I also do mouse capturing & I utilize an internal helper class so that I could add multiple triggers to the same element with only one instance of a helper class handling events & capturing the mouse for that element.

For the actual actions, I just use existing Blend or Prism actions such as InvokeCommandAction.

Here is the project if you're interested. It was too large to paste into this format. It uses some C# 6.0 features but you could easily modify it to work on an older version of C# by removing some null conditional operators. It requires you install the Blend SDK as it depends on System.Windows.Interactivity (should install with Visual Studio as long as you select that option). MouseTrigger is the publicly visible class that is the point of interaction with the functionality. MouseCatcher is the internal helper class mentioned.

I'd recommend not going down the route of custom controls, but rather of using some mechanism (this one or otherwise) to extend the existing functionality using the attached property framework that WPF and XAML bring to the table.

In WinForms you would create custom controls simply to get a nonstandard look, in WPF this is no longer necessary.

The WPF way: instead of making a Stackpanel 's children implement Click behaviour, let's make a Button look like the desired Stackpanel .

Could do this setting the Content :

<Button>
    <StackPanel >
        <Image Source="C:\myFiles\myPic.png"/>
        <Label HorizontalAlignment="Center">SomeTxt</Label>
    </StackPanel>
</Button> 

But this way it still looks like a Button , to overcome this we can set the Template instead:

<Button>
    <Button.Template>
        <ControlTemplate TargetType="Button">
            <StackPanel >
                <Image Source="C:\myFiles\myPic.png"/>
                <Label HorizontalAlignment="Center">SomeTxt</Label>
            </StackPanel>
        </ControlTemplate>
    </Button.Template>
</Button>   

Both solutions will raise a Click event clicking the image or label.

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