How to close popup in silverlight? - silverlight

I have ListBox. when i click on ListBox item I have to show item information in popup But it does not close after clicking out side. I am creating popup in itemsselected event. how to handle popup close?

One approach is to create a canvas with a transparent background that you make visible at the same time as opening the Popup and attaching to is Mouse down event to closed the popup. Like this:-
Xaml:-
<Grid x:Name="LayoutRoot" Background="White" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Popup x:Name="MyPopup" Closed="MyPopup_Closed" HorizontalOffset="100" VerticalOffset="100" Opened="Popup_Opened">
<ListBox x:Name="PopupChild" MaxHeight="300" LostFocus="PopupChild_LostFocus">
<sys:String>Hello World</sys:String>
</ListBox>
</Popup>
<Button Content="Open Popup" Grid.Row="1" Click="Button_Click" />
<Canvas x:Name="PopupOpen" Visibility="Collapsed" Background="Transparent" Grid.RowSpan="2" MouseLeftButtonDown="PopupOpen_MouseLeftButtonDown" />
</Grid>
Code:-
private void Button_Click(object sender, RoutedEventArgs e)
{
MyPopup.IsOpen = true;
}
private void Popup_Opened(object sender, EventArgs e)
{
PopupOpen.Visibility = Visibility.Visible;
}
private void PopupChild_LostFocus(object sender, RoutedEventArgs e)
{
MyPopup.IsOpen = false;
}
private void PopupOpen_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MyPopup.IsOpen = false;
}
private void MyPopup_Closed(object sender, EventArgs e)
{
PopupOpen.Visibility = Visibility.Collapsed;
}
Note that its important that if your popup contains a control that can receive the focus that you also handle LostFocus.

This is similar to a question that I had. Take a look at How to dismiss a popup in Silverlight when clicking outside of the control?. I posted in my solution an extension method that's been very helpful in making popups close when clicking outside of them.

I'm not quite sure what you mean by "clicking out side" because popups act in a modal way.
You should set up your popup window as a ChildWindow. Then you can handle the Closed event.
Here's a very simple sample that shows a selected string from a listbox in a main window.
First the main window:
<UserControl x:Class="PopupTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<ListBox x:Name="SomeList" Width="100" Height="100" />
<TextBlock x:Name="DialogResult" Width="100" />
</StackPanel>
</Grid>
In the codebehind, the popup is triggered when the list selection changes. Simply set up a Closed handler. In this example, I simply put the chosen list item into a textblock, then upon closing the popup, I just put the dialog result in a textblock on the main window (to show if the user pushed ok or cancel).
public MainPage()
{
InitializeComponent();
SomeList.SelectionChanged += new SelectionChangedEventHandler(SomeList_SelectionChanged);
SomeList.Items.Add("one");
SomeList.Items.Add("two");
SomeList.Items.Add("three");
}
void SomeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var popup = new SomePopup();
popup.Closed += new EventHandler(popup_Closed);
popup.ChosenItem.Text = (string)SomeList.SelectedItem;
DialogResult.Text = "";
popup.Show();
}
void popup_Closed(object sender, EventArgs e)
{
var popup = sender as SomePopup;
if (popup.DialogResult == true)
DialogResult.Text = "Ok";
else
DialogResult.Text = "Cancel";
}
The popup closes when the user pushes Ok or Cancel, because the DialogResult value is set in the popup's code-behind:
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}

Related

Programatically attach an event handler to a custom child element routed event

I have a Window that has a Button and a Popup. When the button is clicked, the event handler in code behind opens the Popup. On the Popup I have Button when clicked, the event handler in code behind closes the Popup. Simple. Crude.
I also have a UserControl that has a custom routed event and a Button that raises that event.
That UserControl has been placed on the Popup.
I have added an event handler in XAML on the Popup element for the UserControl custom event. In code behind I show a message box.
This all works fine and dandy.
This is an extremely boiled down example. My ultimate question is, how do I programmatically attach an event handler to the custom routed event at the Popup level?
The UserControl XAML:
<Grid>
<Button
Width="100"
Height="100"
Click="Button_Click"
Content="Event!" />
</Grid>
The UserControl code behind:
public static readonly RoutedEvent CustomEventEvent = EventManager.RegisterRoutedEvent(
nameof(CustomEvent), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(UserControl1));
public event RoutedEventHandler CustomEvent
{
add => this.AddHandler(CustomEventEvent, value);
remove => this.RemoveHandler(CustomEventEvent, value);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(CustomEventEvent));
}
Main window XAML:
<Grid>
<Button
Width="200"
Height="100"
Click="Button_Click"
Content="Popup" />
<Popup
x:Name="MyPopup"
local:UserControl1.CustomEvent="MyPopup_CustomEvent"
AllowsTransparency="True"
Loaded="MyPopup_Loaded"
Placement="Right">
<Border
Background="Azure"
BorderBrush="Gray"
BorderThickness="2"
CornerRadius="3">
<Grid Width="500" Height="300">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button
Grid.Row="0"
Width="100"
Height="100"
Click="Button_Click_1"
Content="Close" />
<local:UserControl1
Grid.Row="1"
Width="100"
Height="100" />
</Grid>
</Border>
</Popup>
</Grid>
The main window code behind (minus the boring popup open/close button clicks):
private void MyPopup_CustomEvent(object sender, RoutedEventArgs e)
{
MessageBox.Show("YAY");
}
private void MyPopup_Loaded(object sender, RoutedEventArgs e)
{
if (sender is Popup popup)
{
// Here is where the wheels fall off.
// How do I find/attach to the routed event after it has bubbled up to the popup?
// popup.CustomEvent += LocalMyPopup_CustomEvent;
}
}
private void LocalMyPopup_CustomEvent(object sender, RoutedEventArgs e)
{
}
Ultimately, there will be several of the UserControls in many popups and I'd rather not have to attach event handlers to each and every one of them. Especially considering I can get them all at the Popup level using MyPopup_CustomEvent. I just want to replicate that behavior.
Turns out the solution is as trivial as it is (in hindsight) obvious. The AddHandler has to be called directly on the Popup and passing in the static Routed Event reference.
private void MyPopup_Loaded(object sender, RoutedEventArgs e)
{
if (sender is Popup popup)
{
popup.AddHandler(UserControl1.CustomEventEvent, new RoutedEventHandler(LocalMyPopup_CustomEvent), true);
// popup.CustomEvent += LocalMyPopup_CustomEvent;
}
}

Mouse on control immediately lost

my intention is to capture the mouse events for a specific control, but the mouse capture is instantly lost
XAML
<Window x:Class="TryMouseCapture.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="lbl" BorderBrush="Black" BorderThickness="2" GotMouseCapture="lbl_GotMouseCapture" IsEnabled="True" LostMouseCapture="lbl_LostMouseCapture" MouseLeftButtonDown="lbl_MouseLeftButtonDown">Mouse captured here</Label>
<Label Grid.Row="1" BorderBrush="Red" BorderThickness="2">Click here</Label>
<Button Grid.Row="2" Click="Button_Click">Capture Mouse in the first label</Button>
</Grid>
</Window>
code behind
private void lbl_GotMouseCapture(object sender, MouseEventArgs e)
{
Label label = (Label)sender;
var b = label.IsMouseCaptured;
}
private void lbl_LostMouseCapture(object sender, MouseEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var b = Mouse.Capture(lbl);
}
private void lbl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
}
So after clicking the button, the lbl_GotMouseCaptureis called, and then immediately lbl_LostMouseCapture follows.
Is there something else to do, besides calling Mouse.Capture(lbl); ?
For me the code works. But setting the b variable implies that you are setting breakpoints. I would replace those by Debug statements to start with..
You should set also
e.Handled = true;
in your Button_Click event handling to make it working everywhere.

WPF: How to make textblock fire key event?

TextBlock has KeyDown and KeyUp event, but it's never fired. Is there a way to make it happen? I just need to detect if any key is pressed.
First of all you will need to set the Focusable Property of your TextBlock to True, This will allow you to Tab to the Item but not Click to select it, but if you handle the MouseDown Event you can manualy set Focus to your TextBlock.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid >
<TextBlock Name="tb1" Height="30" Width ="100" IsEnabled="True" Focusable="True" KeyDown="tb1_KeyDown" MouseDown="tb1_MouseDown">Hello World</TextBlock>
</Grid>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void tb1_KeyDown(object sender, KeyEventArgs e)
{
tb1.Background = Brushes.Blue;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
tb1.Focus();
}
private void tb1_MouseDown(object sender, MouseButtonEventArgs e)
{
tb1.Focus();
}
}

Any way for a ToolTip to trigger a MouseEnter event?

I have a control with a tooltip. What i want is that when I hover over the control and the tooltip opens: if I then enter the tooltip with the mouse - this will trigger a mouseEnter event in order to trigger some other action. The closest I am to finding a solution to this is adding a ToolTipClosing event on the control with the trigger ... but this will fire as soon as I leave the control - even if my mouse doesn't enter the tooltip.
(Triggering a MouseEnter event on the tooltip itself doesn't seem to get fired at all)
Here's an example: (where I want to change the background of the border if I enter the tooltip)
XAML
<Border Height="300" Name="dummyBorder"
Width="200"
Background="Red" />
<Label ToolTipService.InitialShowDelay="3000"
Content="Hover over here"
ToolTipService.ShowDuration="4000"
ToolTipService.Placement="Right"
ToolTipClosing="Label_ToolTipClosing"
Width="100"
HorizontalAlignment="Center"
Margin="10">
<Label.ToolTip>
<ToolTip Name="tt" MouseEnter="ttBorder_MouseEnter">
<Border Background="Brown"
Name="ttBorder"
MouseEnter="ttBorder_MouseEnter"
Width="100"
Height="50">
<TextBlock Text="This is a tool tip." />
</Border>
</ToolTip>
</Label.ToolTip>
</Label>
CodeBehind: (neither of these work)
private void Label_ToolTipClosing(object sender, ToolTipEventArgs e)
{
if (tt.IsMouseDirectlyOver)
{
dummyBorder.Background = Brushes.Aqua;
}
}
private void ttBorder_MouseEnter(object sender, MouseEventArgs e)
{
dummyBorder.Background = Brushes.Aqua;
}
I specifically want to use a tooltip and not a popup. Is this possible?
Any help will be greatly appreciated!
you will want to try something like this:
<Window.CommandBindings>
<CommandBinding Command="ChangeColour"
CanExecute="ChangeCanExecute"
Executed="ChangeExecuted" />
</Window.CommandBindings>
inside your tooltip tag:
<MouseBinding Gesture="LeftClick" Command="{Binding ChangeColour}"/>
then in your codebehind:
private void ChangeCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
private void ChangeExecuted(object sender, ExecutedRoutedEventArgs e)
{
dummyBorder.Background = Brushes.Aqua;
e.Handled = true;
}
Well (after 9 months and no answer) I guess that there is no way then. (Unless proven otherwise)

Why does WPF ScrollViewer causes window to open behind main window?

I have an items control on my window and when its double clicked I want to open a second window. My problem is that if the items control is wrapped in a scroll viewer the new window comes up behind the main window instead of in front of it. If comment out the scroll viewer in this code the window opens in front as intended.
Whats going on here?
Window XAML:
<Window x:Class="EktronDataUI.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestWindow" Height="300" Width="300">
<Grid>
<ScrollViewer>
<ItemsControl ItemsSource="{Binding Source={StaticResource odpMockSmartForms}}" MouseDoubleClick="ItemsControl_MouseDoubleClick" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="Double Click Me" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
Code Behind:
private void ItemsControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TestWindow window = new TestWindow();
window.Show();
}
Have you tried telling the MouseButtonEventArgs that you handled it? The ScrollViewer is most likely trying to focus or do something else when you double click inside it, causing the window to become active again after the other window is opened.
private void ItemsControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
e.handled = true;
TestWindow window = new TestWindow();
window.Show();
}
Not sure... but does the issue get fixed if you remove your scrollviewer, and instead use:
<ItemsControl ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
I pulled in your code and got it to pull to the front if I set the TopMost equal to true.
private void ItemsControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TestWindow window = new TestWindow();
window.Show();
window.Topmost = true;
}
Is this what you're looking for?

Resources