2

On a WPF app, I got a Canvas object containing several Path object. I need to do things on click on those Path, things that would be in VM. There is no Command on Path, like Button for example. What is the best way to do that? My solution so far is :

  1. To create an MouseDown handler on the view code behind to catch my Path click
  2. Send a message from here
  3. Register to this message type on targeted VM in order to execute my business code.

It seems a bit overkill to me, what's your opinion? Do you see a more straitforward method?

Thanks a lot !

nbonniot
  • 1,034
  • 16
  • 33

2 Answers2

2

You can use Button with Path as Template:

<Button Command="{Binding MyCommand}">
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <Path ... />
        </ControlTemplate>
    </Button.Template>
</Button>
dkozl
  • 32,814
  • 8
  • 87
  • 89
  • This really does the trick ;). Thanks. Just got 1 thing not working now, without clear explanation to me : I put all this is an ItemControl, as I got an ObservableCollection of Path. As ItemPanel, I chose Canvas, because I need special positioning. The property Canvas.Left and Canvas.Top are never read, so my Paths always stick on top left. Don't work either in ItemTemplate or Style I created for Path... Any idea where to put them (I precise I first try without binding with hard-coded data, so no binding problem) ? @HighCore : EventToCommand is to dig as well ! Thank you – nbonniot Mar 07 '14 at 13:56
  • You need to set `Canvas.Left`/`Canvas.Top` on direct child of `Canvas` and since `ItemsControl` wraps each item in a container (`ContentPresenter` for `ItemsControl`, `LisBoxItem` for `ListBox` etc) you need to create `Style` for that container in `ItemContainerStyle` and do something like ``. Check [this](http://stackoverflow.com/questions/1265364/setting-canvas-properties-in-an-itemscontrol-datatemplate) question – dkozl Mar 07 '14 at 14:07
  • Thank you very much ! Just find it by myself :) – nbonniot Mar 07 '14 at 14:11
0

Just to add complementary infos about my last comment... The right way to position ItemTemplate is to style the ContentPresenter, within ItemsControl.ItemContainerStyle. Below you will find my finally working code :

<UserControl.Resources>
    <Style x:Key="PathStyle" TargetType="Button">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Path Data="{Binding Data}" 
                          StrokeStartLineCap="Round" 
                          Stretch="Fill" 
                          StrokeEndLineCap="Round" 
                          Stroke="{DynamicResource selectedZoneBorderColor}" 
                          StrokeLineJoin="Round" 
                          Width="{Binding Path=Width}"
                          Height="{Binding Path=Height}"
                          Fill="{DynamicResource selectedZoneColor}" 
                          Panel.ZIndex="1" 
                          StrokeThickness="3" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
<ItemsControl Name="zonesContainer" ItemsSource="{Binding Zones}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas Grid.Column="1" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Button 
                            Style="{StaticResource ResourceKey=PathStyle}"
                            Command="{Binding ElementName=zonesContainer, 
                                                Path=DataContext.ActivateZone}"
                            CommandParameter="{Binding Id}"
                        />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Canvas.Left" Value="{Binding Path=Left}" />
                        <Setter Property="Canvas.Top" Value="{Binding Path=Top}" />
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>

All this with corresponding VM exposing a ObservableCollection, and a Zone class exposing all inside props (Width, Height, Top, Left...).

You can detailled answer here

Community
  • 1
  • 1
nbonniot
  • 1,034
  • 16
  • 33