WPF - PopUp not closed on clicking outside - wpf

I have Custom control which uses control template as shown in below code block. I need to show popup when user left clicks on the control. Once he/she clicks outside the pop up, it should close.
With MouseLeftButtonUp, the pop up is displayed however stays open on clicking outside the popup.
Please note I have set focus on on popup listbox element as soon as pop opens using behaviours:Focus
<ControlTemplate x:Key="ControlWithPopup" TargetType="local:CustomizedControl">
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<ei:ChangePropertyAction
PropertyName="IsDropDownOpen"
TargetObject="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}"
Value="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Popup
x:Name="Popup1"
Width="100"
MinWidth="80"
MaxHeight="300"
AllowsTransparency="true"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Placement="Center"
PlacementTarget="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}"
PopupAnimation="Fade"
StaysOpen="False">
<Border
Background="{DynamicResource SomeBackgroundBrush}"
BorderBrush="{DynamicResource SomeBorderBrush}"
BorderThickness="1"
TextElement.Foreground="{DynamicResource SomeFontBrush}">
<ListBox
x:Name="List1"
ItemTemplate="{TemplateBinding DropDownTemplate}"
ItemsSource="{Binding Path=ListSource, RelativeSource={RelativeSource Mode=TemplatedParent}}"
ScrollViewer.CanContentScroll="False"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectedItem="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Style="{DynamicResource ListBoxNormalStyle}"
VirtualizingPanel.IsVirtualizing="False">
</ListBox>
</Border>
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding IsOpen, ElementName=Popup1}" Value="True">
<behaviours:ScrollIntoCenterView TargetObject="{Binding ElementName=List1}" />
<behaviours:Focus TargetObject="{Binding ElementName=List1}" />
</ei:DataTrigger>
</i:Interaction.Triggers>
</Popup>
<Border
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Transparent"
BorderThickness="1">
<TextBlock
x:Name="Presenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="11"
FontWeight="ExtraBold"
Text="{Binding SelectedValue}" />
</Border>
</Grid>
</Border>
</ControlTemplate>
Note -
- Also note, i dont want to set StayOpen to True due to some reason outside the scope of the problem. I want to achieve it using StayOpen set to False

Related

How to Find ElementName of Parent View (XAML) in TargetObject of ChangePropertyAction WPF?

I'm having DataGrid, the Grid has a Filter Functioning. The Filter Icon Button is styled as DataGridColumnHeader in app.xaml and I attached the style to my DataGrid. If the Button gets Click, then it opens a Filter Popup to perform Filter. The Popup is designed in a Parent View XAML.
The DataGrid View XAML inherits the Parent View XAML. Now I need to set the ElementName=autoFilter in Popup or ElementName=popFilter in Filter Icon Button. I Can't able to call the control using TargetObject of ChangePropertyAction in WPF. Kindly assist.
The DataGrid View: gridView.xaml
<DataGrid Name="EmpList" ColumnHeaderStyle="{StaticResource FilterDataGridColumnHeader}" AutoGenerateColumns="False" ItemsSource="{Binding EmpList}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Employee Name" ElementStyle="{StaticResource DataGridElementStyle}" />
<DataGridTextColumn Binding="{Binding Age}" Header="Employee Age" ElementStyle="{StaticResource DataGridElementStyle}" />
</DataGrid.Columns>
</DataGrid>
Parent View Contains Popup: MainView.xaml
<Popup Name="popFilter" Placement="Mouse" StaysOpen="False" Width="200" IsOpen="{Binding IsPopupFilterOpen, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Opened">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=autofilter}" PropertyName="Visibility"/>
</i:EventTrigger>
<i:EventTrigger EventName="Closed">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=autofilter}" PropertyName="Visibility">
<ei:ChangePropertyAction.Value>
<Visibility>Collapsed</Visibility>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<Border Background="White" BorderBrush="Gray" BorderThickness="1,1,1,1">
<StackPanel Margin="5,5,5,15">
<TextBlock Text="Welcome to Popup Window" />
</StackPanel>
</Border>
</Popup>
Filter Icon Button in ColumnHeaderStyle : app.xaml
<Application.Resources>
<Style TargetType="{x:Type DataGridColumnHeader}" x:Key="FilterDataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Button Grid.Column="2" Background="Yellow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=autofilter}" PropertyName="Visibility">
<ei:ChangePropertyAction.Value>
<Visibility>Visible</Visibility>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
<i:EventTrigger EventName="MouseLeave">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=autofilter}" PropertyName="Visibility">
<ei:ChangePropertyAction.Value>
<Visibility>Collapsed</Visibility>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
<i:EventTrigger EventName="Click">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=popFilter}" PropertyName="IsOpen">
<ei:ChangePropertyAction.Value>True</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1"/>
<ContentControl x:Name="autofilter" Visibility="Collapsed" ContentTemplate="{StaticResource FilterButtonStyleKey}" Margin="0 0 3 0"/>
</Grid>
</Button>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
The Icon Button Image Key: FilterButtonStyleKey
<DataTemplate x:Key="FilterButtonStyleKey">
<Canvas Height="15.898" Width="15.297" HorizontalAlignment="Center" VerticalAlignment="Center" Background="Transparent">
<Path Data="M16.0117,6.7368C18.3417,6.7368,20.6727,6.7358,23.0027,6.7378C23.5327,6.7378,23.5977,6.8308,23.6437,7.3438C23.7027,7.9958,23.4897,8.4748,23.0197,8.9548C21.4107,10.5968,19.8547,12.2888,18.2957,13.9788C18.1647,14.1208,18.1137,14.3828,18.1117,14.5898C18.0987,17.0608,18.1067,19.5308,18.0907,22.0018C18.0887,22.2158,18.0077,22.4968,17.8607,22.6158C17.7697,22.6878,17.4587,22.5408,17.2807,22.4368C16.3057,21.8718,15.3447,21.2788,14.3677,20.7148C14.0637,20.5408,13.9287,20.3278,13.9297,19.9728C13.9407,18.1778,13.9257,16.3848,13.9357,14.5908C13.9367,14.2698,13.8367,14.0388,13.6137,13.8058C12.1347,12.2548,10.6717,10.6898,9.2027,9.1298C9.0967,9.0168,8.9927,8.9018,8.8797,8.7958C8.4137,8.3608,8.2387,7.6118,8.4377,7.0158C8.5277,6.7478,8.7137,6.7358,8.9347,6.7368C10.0937,6.7388,11.2517,6.7378,12.4097,6.7378C13.6107,6.7378,14.8107,6.7378,16.0117,6.7368z" Height="16.898" Canvas.Left="-0.5" StrokeStartLineCap="Round" Stretch="Fill" StrokeEndLineCap="Round" Stroke="#FF323232" StrokeThickness="1" StrokeLineJoin="Round" Canvas.Top="-0.5" Width="16.297"/>
<Path Data="M14.2427,14.3921L17.9117,14.3921" Height="1" Canvas.Left="5.386" StrokeStartLineCap="Round" Stretch="Fill" StrokeEndLineCap="Round" Stroke="#FF323232" StrokeThickness="1" StrokeLineJoin="Round" Canvas.Top="7.156" Width="4.669"/>
</Canvas>
</DataTemplate>
I need to show (Visibility:Visible) the Filter Icon Button while on Mouse Hover Event of the Corresponding Column or If user can click the Filter Icon Button then the Filter Popup gets opened and that time the Icon should show - Filter Popup IsOpen=True state. The Filter Icon Button should Collapsed while on Popup gets closed while on Icon Button Clicked otherwise Mouse Hover is not happened.
Note:
Design the Datagrid in one XAML and the Filter Popup should be in Main
View XAML, The DataGrid XAML inherits the Main View XAML.
The Filter Icon is a Button designed in app.xaml and call the Style in
the DataGrid.

Adding image to radiobutton that can act as Toggle button using wpf

I want to use 2 radiobuttons like a toggle button using WPF. I tried something like this:
<RadioButton Name="RightAnswer" Width="20">
<RadioButton.Template>
<ControlTemplate>
<ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<Image Width="20"
Height="20"
VerticalAlignment="Center"
Source="{Binding Content,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}"
ToolTip="Right Answer" />
</ToggleButton>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
<RadioButton Name="WrongAnswer" Width="20">
<RadioButton.Template>
<ControlTemplate>
<ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<Image Width="20"
Height="20"
VerticalAlignment="Center"
Source="{Binding Content,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}"
ToolTip="Wrong Answer" />
</ToggleButton>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
I could make this work but it shows blank buttons. I want to have buttons with Image in each of them and on checked i should bind it with ViewModel code.
Update: I added Images in each of them which now works well. I hoping to connect the press events to VM property.

WPF DataTemplate previewmouseleftbuttonup not working

I have Listbox with ListItemTemplate. There are two commands I want attach with each list item.
1) PreviewMouseLeftButtonDown : I use this even when for drag and drop functionality. user press button event gets fired and I came to know how many items user has selected for dragging.
2) PreviewMouseLeftButtonUp: I want to use this when user release mouse from list item. (But issue is this even never gets fired. It seems like 1st event taking control of both.
Here is my code. Pls help.
<DataTemplate x:Key="ListItemTemplate">
<Grid Margin="0" Width="58" Height="58" x:Name="OuterGrid">
<Border x:Name="OuterBorder" BorderBrush="{DynamicResource ContentToGreyedOutBrush}" BorderThickness="0" Margin="0" Background="Transparent" Grid.Column="0" Grid.Row="0"
ClipToBounds="True" CornerRadius="0">
<Border x:Name="InnerBorder" BorderBrush="Transparent" BorderThickness="1" Margin="0" Background="Transparent" CornerRadius="0">
<Grid>
<Image Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding Path=FileName,Converter={StaticResource FileNameImageConverter}}"
Width="50" Height="50">
</Image>
<ToggleButton x:Name="zoomButton" Grid.Column="0" Grid.Row="0" Margin="0" HorizontalAlignment="Right" HorizontalContentAlignment="Right" VerticalAlignment="Bottom"
VerticalContentAlignment="Bottom" Background="Transparent" Cursor="Hand" Template="{StaticResource ZoomTemplate}" Width="20" Height="20" Visibility="Collapsed">
</ToggleButton>
</Grid>
</Border>
</Border>
<ac:CommandBehaviorCollection.Behaviors>
<ac:BehaviorBinding Event="PreviewMouseLeftButtonDown" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}},Path=DataContext.DragItemSelectedCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"/>
<ac:BehaviorBinding Event="PreviewMouseLeftButtonUp" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}},Path=DataContext.MouseUPCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"/>
</ac:CommandBehaviorCollection.Behaviors>
</Grid>
</DataTemplate>
It looks like you're trying to do dragging of the item to a different location outside the original bounds. In this case the up event would be firing on the new control over which the mouse is located when it is released, not the control that you started dragging. To make this work you need to make sure to capture the mouse when starting a drag operation.

MouseOver on ToggleButton to popup a Text

I am coding to popup a Text when MouseOver on ToggleButton. I got it too, but the real problem is that popped Text is not remains constant i.e., it continuously shaking on the ToggleButton. One more thing is that popped Text is appeared on the ToggleButton itself but it should be beneath of it. How can i get rid of this one?
Here is my Code looks
<ToggleButton x:Name="btn" Width="20" Height="15">
<Image Source="../Images/flag_orange.ico"/>
</ToggleButton>
<Popup x:Name="popUp" IsOpen="{Binding IsChecked, ElementName=btn, Mode=TwoWay}"
StaysOpen="False" PlacementTarget="{Binding ElementName=btn}"
Placement="Bottom" PopupAnimation="Slide" HorizontalOffset="-5"
VerticalOffset="3">
<Border Background="DarkGray">
<TextBox Text="Its a place holder for user notes" x:Name="tbText"/>
</Border>
</Popup>
<TextBlock x:Name="tbTextBlock"
Visibility="{Binding Path=IsMouseOver,ElementName=btn,Mode=OneWay,
Converter={StaticResource BoolToVisibilityConverter}}"
Text="{Binding ElementName=tbText, Path=Text, Mode=TwoWay}" />
use IsHitTestVisible="False" on your TextBlock. The Mouseover is catched by the Textblock yet, so your mouse is not over the ToggleButton when the TextBlock appears.
To get the TextBlock beneath the ToggleButton use either a Margin="0,15,0,0" or a StackPanel to get those controls in order:
<StackPanel>
<ToggleButton x:Name="btn" Width="20" Height="15">
<Image Source="../Images/flag_orange.ico"/>
</ToggleButton>
<Popup x:Name="popUp" IsOpen="{Binding IsChecked, ElementName=btn, Mode=TwoWay}"
StaysOpen="False" PlacementTarget="{Binding ElementName=btn}"
Placement="Bottom" PopupAnimation="Slide" HorizontalOffset="-5"
VerticalOffset="3">
<Border Background="DarkGray">
<TextBox Text="Its a place holder for user notes" x:Name="tbText"/>
</Border>
</Popup>
<TextBlock x:Name="tbTextBlock"
IsHitTestVisible="False"
Visibility="{Binding Path=IsMouseOver,ElementName=btn,Mode=OneWay,
Converter={StaticResource BoolToVisibilityConverter}}"
Text="{Binding ElementName=tbText, Path=Text, Mode=TwoWay}" />
</StackPanel>

Modifying TabControl's header

So I'm adding my views directly to the TabControl's Items collection at runtime (instead of creating TabItems around them and addings those TabItems to TabControl). The views expose a property (wrapper around a ViewModel property of the same name) named HasChanges that I want to bind to TabItem's Header to show a Asterisk (*) sign to identify tabs with unsaved changes, just like VS does. I have already tried using DataTemplates but am having trouble accessing the view object in the DataTemplate. What's the correct way of doing this? Here's one of my several attempts:
<TabControl.ItemTemplate>
<DataTemplate DataType="UserControl">
<StackPanel Orientation="Horizontal" Margin="0" Height="22">
<TextBlock VerticalAlignment="Center" Text="{Binding HeaderText, RelativeSource={RelativeSource AncestorType=UserControl}}" />
<TextBlock Text="*" Visibility="{Binding HasChanges, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource B2VConverter}}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
Note that I'm trying two different binding methods for the two TextBlocks, none of which is working. My views inherit from UserControl and expose properties HasChanges and HeaderText.
OK. I solved it myself. For anyone else trying to implement a VS-like Close button and unsaved changes asterisk, here's the template:
<TabControl.ItemContainerStyle>
<Style TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0" Height="22">
<TextBlock VerticalAlignment="Center" Text="{Binding RelativeSource={RelativeSource AncestorType=TabItem}, Path=Content.HeaderText}" />
<TextBlock Text=" *" ToolTip="Has unsaved changes" Visibility="{Binding Content.DataContext.HasChanges, RelativeSource={RelativeSource AncestorType=TabItem}, Converter={StaticResource B2VConverter}}" />
<Button Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" Width="18" Height="18"
Margin="6,0,0,0" Padding="0" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center"
Command="{Binding DataContext.TabClosingCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"
VerticalAlignment="Center" Focusable="False">
<Grid Margin="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Line StrokeThickness="3" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Stroke="Gray" X1="1" Y1="1" X2="9" Y2="9" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Line StrokeThickness="3" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Stroke="Gray" X1="1" Y1="9" X2="9" Y2="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Button>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
Results in an elegant drawing-based button with a flat-look. Your View must implement Boolean HasChanges and HeaderText properties, plus you need to define a BooleanToVisibilityConverter in your resources section, named B2VConverter.

Resources