Canvas that allows events for overlapped elements - c#

I am looking for a way in WPF to recognize click events on all ZIndex levels. So this means I would like to recoginze a click also if another element (on the same canvas - only different ZIndex) is clicked.
What I want to achive with this functionality is that I have some ListBoxes on the same canvas and I would like to get the SelectionChanged event also when they overlap.
Edit: Added some code.
<DataTemplate DataType="{x:Type my:type}">
<ListBox SelectionMode="Extended" Background="Transparent"
ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Elements}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<ei:CallMethodAction TargetObject="{Binding ElementName=control, Path=DataContext}"
MethodName="SelectionChanged" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Width="500" IsItemsHost="True"
Height="500"
VerticalAlignment="Top" HorizontalAlignment="Left" Background="Transparent">
</Canvas >
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<DataTemplate>
In this example the SelectionChanged handler is only visible for one object (depending on ZIndex).

Related

How to enable event bubling from nested canvas

I am drawing shapes on Canvas. I am using mouse events to do some action.
I draw rectangle with right mouse click, unfortunately when I release mouse on rectangle, no MouseUp event is fired.
ItemsControl
<ItemsControl ItemsSource="{Binding Shapes}" Width="{Binding ActualWidth, ElementName=img}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="canvas" Background="Transparent" Cursor="Cross" Panel.ZIndex="0">
<i:EventTrigger EventName="MouseUp">
<i:CallMethodAction MethodName="MouseReleasedHandler" TargetObject="{Binding}" IsEnabled="{Binding IsDrawingEnabled}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
DataTemple for Rectangle
<DataTemplate DataType="{x:Type over:RectangleROI}">
<Canvas>
<Rectangle Canvas.Top="{Binding Y}" Canvas.Left="{Binding X}"
Fill="{Binding Fill}" Stroke="{Binding Stroke}"
Width="{Binding Width}" Height="{Binding Height}"
/>
</Canvas>
</DataTemplate>
My research:
I've used Snoop to sniff event.
I could see event is fired on Rectangle item
I could also see event is bubbling up (Rectangle -> Canvas -> ContentPresenter)
In all cases event wasn't marked as handled
UI structure snippet from Snoop (sorry for image quality):
What I've tried
I saw some post which adviced to set:
Canvas background to transparent
Explicitly set Width & Height
I've tried it on both Canvases
My current solution
I've I attached EventTrigger to Rectangle
<i:EventTrigger EventName="MouseUp" >
<i:CallMethodAction MethodName="MouseReleasedHandler" TargetObject="{Binding DataContext , RelativeSource={RelativeSource AncestorType=UserControl}}" />
</i:EventTrigger>
I don't like this solution because I think there has to be better way.
My question
What I should do to enable event bubbling from Content presenter up to second (main) Canvas (ItemsControlItemPanel)

How can I make a GridViewItem as a draggable object instead of a DataTemplate in XAML?

I have a XAML file which should make it possible to drag GridViewItems inside a GridView. Now I'm using an ItemSource for the GridView items and a DataTemplate to show them in the way I want them to be shown. That works. The following problem occured: Since I started using DataTemplate, the GridViewItems are not draggable. I can only drag the DataTemplate. That's weird, so the only part I can use to drag, is the area left and right of the GridViewItems because this is used for margin.
Why is the DataTemplate the 'draggable' control instead of the GridViewItem? I have tried numerous fixes but none seem to work out well.. I can ofcourse make it work without a DataTemplate, but it's much cleaner to use it like this.
<GridView Name="canvas" ItemsSource="{Binding GridviewItemList}" CanReorderItems="{Binding CanvasCanReorder}" CanDragItems="{Binding CanvasCanDrag}" ReorderMode="Enabled" AllowDrop="True" VerticalAlignment="Center" Width="660" Height="110" IsSwipeEnabled="False" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.HorizontalScrollMode="Disabled">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MainPageItems">
<GridViewItem Name="{x:Bind GvName}" Margin="13 0 15 0">
<Border Width="100" Height="100" Background="{x:Bind BdBackground, Mode=OneWay}">
<TextBlock Height="60" Width="30" FontSize="40" Text="{x:Bind TbText, Mode=TwoWay}" Margin="{x:Bind TbMargin, Mode=TwoWay}"></TextBlock>
</Border>
</GridViewItem>
</DataTemplate>
</GridView.ItemTemplate>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DragItemsCompleted">
<core:InvokeCommandAction Command="{Binding CanvasDragCompleted}"></core:InvokeCommandAction>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</GridView>
Thanks in advance!
When you add GridViewItem in the DataTemplate, there are two ListViewItemPresenter in one GridViewItem. Please check it in the Live Visual Tree.
In UWP apps for Windows 10, both ListViewItem and GridViewItem use ListViewItemPresenter; the GridViewItemPresenter is deprecated and you should not use it. ListViewItem and GridViewItem set different property values on ListViewItemPresenter to achieve different default looks.
For more info, please refer Item containers and templates.
If you want to set Margin to the GridViewItem, we should be able to set the GridViewItem style in the GridView.ItemContainerStyle.
For example:
<GridView Name="canvas" ItemsSource="{Binding GridviewItemList}" CanReorderItems="{Binding CanvasCanReorder}" CanDragItems="{Binding CanvasCanDrag}" ReorderMode="Enabled" AllowDrop="True" VerticalAlignment="Center" Width="660" Height="110" IsSwipeEnabled="False" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.HorizontalScrollMode="Disabled">
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:MainPageItems">
<Border Width="100" Height="100" Background="{x:Bind BdBackground, Mode=OneWay}">
<TextBlock Height="60" Width="30" FontSize="40" Text="{x:Bind TbText, Mode=TwoWay}" Margin="{x:Bind TbMargin, Mode=TwoWay}"></TextBlock>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="13 0 15 0"/>
</Style>
</GridView.ItemContainerStyle>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DragItemsCompleted">
<core:InvokeCommandAction Command="{Binding CanvasDragCompleted}"></core:InvokeCommandAction>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</GridView>

Cant get InputBinding to apply to entire ListBoxItem using DataTemplate WPF

Trying to get some keybindings onto my ListBoxItems in a ListBox in WPF. I am using MVVM, and binding the ItemSource of the ListBox to a list of ViewModels. This ViewModel has a string and a boolean for 'Selected'. I wish to display Selected as a property to a CheckBox.
I am trying to make it so that if I navigate the list items with the up and down arrows on the keyboard, and then press enter/space/whatever, I can toggle the Checkbox. However, I have to press tab first, to get focus to the StackPanel which contains the checkbox.
<DataTemplate x:Key="MyTemplate" DataType="{x:Type ViewModel}">
<Border Width="2" BorderBrush="Blue">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding EnterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<CheckBox VerticalAlignment="Center"
Content="{Binding Name}"
IsChecked="{Binding Selected}"
Margin="3" />
</Border>
</DataTemplate>
=======================
<Popup x:Name="FilterPopup" Grid.Column="1"
IsOpen="{Binding IsChecked, ElementName=FilterButton}"
StaysOpen="False"
PlacementTarget="{Binding ElementName=FilterButton}"
Placement="Top">
<ListBox ItemsSource="{Binding ViewModels}"
ItemTemplate="{StaticResource MyTemplate}" />
</Popup>
Have I missed something obvious???
The triggers above are fired inside the data template, not inside item container. So if the last one is focused there is no effect.
To avoid this, the triggers should be specified on item container level:
<ListBox.ItemContainerStyle>
<Style>
<Setter Property="l:Attach.InputBindings">
<Setter.Value>
<InputBindingCollection>
<KeyBinding Command="{Binding EnterCommand}" Key="Enter" />
<KeyBinding Command="{Binding EnterCommand}" Key="Space" />
</InputBindingCollection>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
I've taken a way to set input bindings from style from this question.

Context menu event or trigger of a control inside an itemtemplate of a listview is not fired

I've got following problem. Following situation in my xaml code:
<ListView ItemsSource="{Binding ListViewItems}">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Label Content="Test">
<Label.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuItems}">
</ContextMenu>
</Label.ContextMenu>
</Label>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding LabelMouseUpCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
After clicking a label no context menu is shown and the trigger does not work as well, LabelMouseUpCommand method is not entered. I fear the listview handles the click itself and does not pass it to the embedded controls.
Is there any way to pass it to the controls. In future i want to add several controls to the itemtemplate and everyone has it own different context menu.
I found the answer for my problem with this stackoverflow article
There the author explains that the contextmenu does not lie in the same visual tree as the listview. Therefore my initial binding can't work because the source can't be found within the visual tree.
Furthermore Sinatr was totally right, the trigger was initially defined for listview, not for the label.
Here is my working code:
<ListView ItemsSource="{Binding ListViewItems}" x:Name="listViewMain">
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Label Content="Test">
<Label.ContextMenu>
<ContextMenu ItemsSource="{Binding DataContext.MenuItems, Source={x:Reference listViewMain}}">
</ContextMenu>
</Label.ContextMenu>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding DataContext.LabelMouseUpCommand, Source={x:Reference listViewMain}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Label>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Grid "Tap" or "Click" event through a data template?

I have already tried searching the web for using commands in Windows Phone, but I can't find a scenario that fits my problem. I have a DataTemplate which creates some grids. For these grids, I want them to do something when their Click event is triggered. However, the Grid element doesn't have a Command property.
I don't nescessarily need to do it through commands, but I thought that was the way to go.
Here's what I want to do.
<ItemsControl VerticalAlignment="Top" Visibility="Collapsed" x:Name="RadioList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="12" Tag="{Binding}">
<!-- this is the grid I want to listen for clicks on -->
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
To bind a command to a grid you will need to use EventTrigger:
<ItemsControl VerticalAlignment="Top" Visibility="Collapsed" x:Name="RadioList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="12" Tag="{Binding}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding YourCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
with the following namespace definition:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

Categories

Resources