ContextMenu not appearing when clicking on 'empty space' within StackPanel - wpf

I have a HierarchicalDataTemplate which has some simple Items contained in a horizontal StackPanel.
A context menu is assigned to the root StackPanel container as well:
<HierarchicalDataTemplate DataType="{x:Type data:GroupViewModel}"
ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal" Margin="2" ContextMenuOpening="groupContextMenuOpening">
<StackPanel.ContextMenu>
<StaticResource ResourceKey="groupContextMenu" />
</StackPanel.ContextMenu>
<Rectangle Width="16" Height="15" Fill="{Binding Converter={StaticResource HierarchyLevelConverter}}" Margin="0 0 3 0" Cursor="Hand" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown" >
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding SetCurrent}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
<Image Width="16" Height="15" Source="{Binding Path=GroupState, Converter={StaticResource GroupStateConverter}}" Cursor="Hand" Margin="0 0 3 0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown" >
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding ToggleGroupState}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
</StackPanel>
</HierarchicalDataTemplate>
The host TreeView also uses a ContextMenu.
The idea is that if you right click on an item in the TreeView, you will get it's ContextMenu.
If you right clik in empty space in the tree view you will get the 'default' context menu with lesser options.
This is all working expcept one odd problem.
As you can see the horizontal StackPanel leaves a margin between the images. If I right click in that space between items, the TreeView context menu shows up. I would expect the ContextMenu defined in my HierarchicalDataTemplate to pop up as i AM right click on the StackPanel itself.
I've found that if I assign a background color to the StackPanel it then works, but I would prefer to avoid this if possible.
Any ideas?

Set the Background of the StackPanel to Transparent to make it hit test in those empty areas.

Related

How to fire double click event in a combobox in a child user control?

I have a user control that use another user control. The child user control has a combobox and the click event works because i can open the combobox, but the double click it doesn't work.
My code is this:
Main user control:
<StackPanel>
<views:ucMyChildUserControl/>
</StackPanel>
My child user control:
<StackPanelOrientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label Content="Content" Style="{StaticResource LabelDefault}"/>
<ComboBox Name="cmbMyCombobox"/>
</StackPanel>
<!--More related controls-->
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding MyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
But I have realized that if the comand of mouse double click is set in the parent user control, it works:
<views:ucChildUserControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding MyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</views:ucChildUserControl>
So I guess the problem is about the handling of the event, but I don't know how to catch it in the child user control.
Thanks.
The issue is that the MouseDoubleClick event and the PreviewMouseDoubleClick are defined on Control. Since UserControl is a derivative of Control, the event is available and can be handled. However, StackPanel is not a derivative of Control so the event is not available, therefore the trigger does not work.
There are workarounds to this in code-behind that you can eventually turn into a behavior for MVVM, but simple workarounds like using input bindings on the left mouse click action only work on some elements, as others like ComboBox will already handle it and then the input bindings are not triggered.
<StackPanel Orientation="Horizontal">
<StackPanel.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick"
Command="{Binding MyCommand}"/>
</StackPanel.InputBindings>
<StackPanel Orientation="Vertical">
<Label Content="Content"/>
<ComboBox Name="cmbMyCombobox"/>
</StackPanel>
<!--More related controls-->
</StackPanel>
The most simple solution without creating additional code is to wrap the StackPanel in a control that is a derivative of Control, e.g. a ContentControl, like this.
<ContentControl>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label Content="Content"/>
<ComboBox Name="cmbMyCombobox"/>
</StackPanel>
<!--More related controls-->
</StackPanel>
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseDoubleClick">
<b:InvokeCommandAction Command="{Binding MyCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ContentControl>

Binding a TabItem in WPF

In WPF, a button can be bound to a command.
<Button Command="{Binding DoSomething}">Click me!</Button>
Now I want to do the same to a TabItem:
<TabItem Header="A little tab" ???="{Binding DoSomething}">...</TabItem>
What should ??? be? Or is there another way to do it?
It depends on what do you want to achieve. TabItems have the IsSelected property
IsSelected="{Binding IsSelected}"
that can be bounded TwoWay, and can be used to signal stuff to the ViewModel.
You could also use the fact that you can override the header of the TabItem, and bound it to a command, using Interactivity.
<TabItem TabIndex="0"
Tag="{Binding CurrentPrinterStatus}">
<TabItem.Header>
<Grid Background="Transparent">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DoSomething}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock Style="{StaticResource TextBlockSelectedStyle}"
Text="Printers"/>
</Grid>
</TabItem.Header>
Other solutions are to use the SelectionChanged event of the TabControl, and that could allow you to find the ViewModel of the TabItem currently selected.
Hope this ideas atleast help you get a solution to your problem.

Shift + Tab is not working for combobox in wpf

I am working with five text boxes and two comboboxes in xaml.
When I click on Tab key it comes from top to bottom(textboxes to comboboxes),
when I click on shift + Tab it doesn't move from combobox to textbox.
My Combobox is
<TextBlock Text="Select" Style="{StaticResource WaterMarkTextBlockStyle}" Visibility="{Binding ElementName=ComboCOM, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<ComboBox x:Name="ComboCOM" ItemsSource="{Binding COM.COM}" SelectedItem="{Binding TestResultsEntity.CountryOfOrigin,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}" Validation.ErrorTemplate="{StaticResource ErrorTemplateSilverlightStyle}" IsReadOnly="True" IsHitTestVisible="{Binding TestResultsIsHitTestVisible}" Margin="0" Background="Transparent" >
<i:Interaction.Triggers>
<UC:EventTriggerHandler EventName="Loaded">
<i:InvokeCommandAction Command="{Binding GetCOMComboName}" CommandParameter="{Binding ElementName=ComboCOM}"/>
</UC:EventTriggerHandler>
</i:Interaction.Triggers>
</ComboBox>
Could you please provide me the solution,thanks in advance.
Also this is an old post, I wanted to share my experience.
I came across the same problem with TextBoxes and CheckBoxes inside a Window. Tab worked for jumping to the next Control, Shift+Tab did not work.
The solution was to set TabIndex property on all controls in the Window/UserControl.

DataGridTemplateColumn.CellTemplate How to add Image conditionally and hide checkbox in same column cell

<c1:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chkBxIsChecked" IsChecked="{Binding IsChecked, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding IsVisible, Mode=TwoWay}" >
<Image Name="ErrorImage" Visibility ="{Binding IsImgVisible, Mode=TwoWay}" Source= "../../../Resources/Images/Fail.png" Height="16" Width="16" Margin="5,0,0,0"></Image>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<t:MapEventToCommand Command="{Binding Source={StaticResource TestVM},Path=IsCkCommand}" CommandParameter="checked" />
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<t:MapEventToCommand Command="{Binding Source={StaticResource TestVM},Path=IsCkCommand}" CommandParameter="unchecked" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</DataTemplate>
</c1:DataGridTemplateColumn.CellTemplate>
</c1:DataGridTemplateColumn>
I want to hide a check box in column and display image based on the data from db .
I was trying the above approach , but unable to display the image when i made visibility.collapse for the checkbox .
can i do that from codebehind ? , please suggest me .
Test one record in the attched image i am expecting to display image instead of checkbo ,where as it is showing empty because i made visibility collapsed against the row .
Thanks in advance .
You have added Image as child of CheckBox. So, making parent (CheckBox) collapsed will eventually make child (image) collapsed. Make checkBox and Image as siblings of parent container.
Replace
<CheckBox>
<Image/>
</CheckBox>
with
<Grid>
<CheckBox/>
<Image/>
<Grid>
Assuming Visibility bindings working fine.

ZIndex of pushpins in WP7 bing map control

I have a Bing silverlight map control for Windows phone 7. I am trying to display on top currently selected pushpin. Here is the snippet:
<my:Map x:Name="map" Canvas.ZIndex="1" CredentialsProvider="{StaticResource Credentials}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
CopyrightVisibility="Collapsed" LogoVisibility="Collapsed">
<my:MapItemsControl x:Name="Pushpins">
<my:MapItemsControl.ItemTemplate >
<DataTemplate>
<my:Pushpin Location="{Binding Location}" Canvas.ZIndex="{Binding Zindex}" PositionOrigin="0.515625,0.859375" Content="{Binding Id}" Template="{StaticResource PushpinControlTemplate}" Tap="Pushpin_Tap"/>
</DataTemplate>
</my:MapItemsControl.ItemTemplate>
</my:MapItemsControl>
</my:Map>
The control is ignoring the ZIndex. Am I missing something or the ZIndex is not supported. The ZIndex is property of a class which implements INotifyPropertyChanged
private int _zIndex;
public int Zindex
{
get { return _zIndex; }
set
{
_zIndex = value;
OnPropertyChanged(new PropertyChangedEventArgs("Zindex"));
}
}
I had the same problem where I had multiple pushpins close together and the problem was exacerbated when I had additional content to show when the pushpin was clicked.
The way I got around this problem was to remove the pushpin and then re-add it. That way it became the topmost pushpin.
map1.Children.Remove(pushpin);
map1.Children.Add(pushpin);
In a recent project I used two map layers to achieve this. The first map layer was bound to my list of pushpins ("resultsLayer"), the 2nd map layer was bound to a single 'SelectedItem' ("selectedLayer") on my view model.
The 2nd map layer will render on top of the first one. So, when a pushpin on the first layer was selected, it was removed from the collection (consequently removed from the layer) and set to be the selected pin which added it to the 2nd layer. The puspin control template for the 2nd layer contained the 'callout' which in my case was a button with some text in it that the user could click to open another page.
Here is my xaml:
<m:Map CredentialsProvider="xxxx" x:Name="map" Center="{Binding MapCenter, Mode=TwoWay}" ZoomLevel="{Binding MapZoomLevel, Mode=TwoWay}">
<m:MapLayer x:Name="resultsLayer" Visibility="{Binding IsBusy, Converter={StaticResource booleanNotCollapsedConverter}}">
<m:MapItemsControl ItemsSource="{Binding VenuesFound}">
<m:MapItemsControl.ItemTemplate>
<DataTemplate>
<m:Pushpin Location="{Binding VLocation}" PositionOrigin="BottomCenter" >
<m:Pushpin.Template>
<ControlTemplate>
<Image x:Name="mapPin" Grid.Row="1" Source="{Binding MapPin}" Stretch="None" />
</ControlTemplate>
</m:Pushpin.Template>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<gs:EventToCommand Command="{Binding SelectPinCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</m:Pushpin>
</DataTemplate>
</m:MapItemsControl.ItemTemplate>
</m:MapItemsControl>
</m:MapLayer>
<m:MapLayer x:Name="selectedLayer" DataContext="{Binding SelectedV}" Visibility="{Binding IsBusy, Converter={StaticResource booleanNotCollapsedConverter}}">
<m:Pushpin Location="{Binding VLocation}" PositionOrigin="BottomCenter">
<m:Pushpin.Template>
<ControlTemplate>
<StackPanel>
<Button Style="{StaticResource PushPinCallout}" Command="{Binding SelectItemCommand}">
<TextBlock Text="{Binding Name}" Foreground="White" Margin="2" TextWrapping="Wrap" />
</Button>
<Image x:Name="mapPin" Grid.Row="1" Source="{Binding MapPin}" Stretch="None" />
</StackPanel>
</ControlTemplate>
</m:Pushpin.Template>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<gs:EventToCommand Command="{Binding SelectPinCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</m:Pushpin>
</m:MapLayer>
</m:Map>
As the BingMapsControl is not a Silverlight control it does not have any concept of a canvas.
Instead of trying to ensure the selected one is at the front, I'd change the selected pin to be of a larger, more prominent style.
It doesn't make sense (to me) to be able to control the z-index of pins as doing so could create a scenario where a pin appears to be on top of another pin, rather than on the map.

Resources