WPF Loses Event Handler - wpf

I have a simple WPF app in .NET 4.7. The main Window listens for a "Key Up" event. If the Escape key is pressed, the Main Window closes itself. This works fine (at least it starts out working fine).
The main Window also contains a Button that opens another Window (call it X). X is just an empty Window. It has no event handlers. When X opens, the Button in the main Window is disabled. Once X closes, the Button is re-enabled.
Here's the problem: Once X is closed, the main Window's Key Up event handler seems to be gone...sort of. I can no longer press Escape to close the main Window unless I first give the focus to one of the buttons. If I just click on the main Window and press Escape, it will not close the Window. Prior to showing Window X, this was not the case.
It turns out that if I do not disable and re-enable the Button, the Key Up event handler continues to work after X is closed -- I can still reliably close the main Window by pressing the Escape key.
Obviously, I'm new to WPF. I'm wondering if there is something weird going on with Windows events.
Here is the the Main Window's XAML followed by it's code behind. I have also included Window X's XAML and code behind (btw, Window X is the WrapPanelWindow).
<Window x:Class="Wpf_01.MainWindow" x:ClassModifier="internal"
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"
xmlns:local="clr-namespace:Wpf_01"
mc:Ignorable="d"
Title="Main Window" Height="300" Width="300" Background="#FF6289A4" KeyUp="Key_Up">
<StackPanel Margin="20,10,20,10">
<Button Content="Canvas Example"/>
<Button Content="WrapPanel Example" Click="Button_Click"/>
<Button Content="DockPanel Example"/>
<Button Content="Grid Example"/>
<Button Content="StackPanel Example"/>
</StackPanel>
Here is the Main Window's code behind:
namespace Wpf_01 {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
internal partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
Button clickedButton = sender as Button;
Window newWindow = null;
switch(clickedButton.Content) {
case "Canvas Example":
newWindow = new CanvasWindow();
break;
case "WrapPanel Example":
newWindow = new WrapPanelWindow();
break;
}
if(newWindow != null) {
clickedButton.IsEnabled = false;
newWindow.Show();
newWindow.Closed += (x, y) => clickedButton.IsEnabled = true;
}
} // Button_Clicked()
private void Key_Up(object sender, KeyEventArgs e) {
if(e.Key == Key.Escape)
Close();
} // KeyHandler()
}
}
Here is the WrapPanelWindow XAML and code behind:
<Window x:Class="Wpf_01.WrapPanelWindow" x:ClassModifier="internal"
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"
xmlns:local="clr-namespace:Wpf_01"
mc:Ignorable="d"
Title="Fun with WrapPanel Window" Height="200" Width="260">
<Grid>
</Grid>
</Window>
Finally, the WrapPanelWindow's code behind.
namespace Wpf_01 {
/// <summary>
/// Interaction logic for WrapPanelWindow.xaml
/// </summary>
internal partial class WrapPanelWindow : Window {
public WrapPanelWindow() {
InitializeComponent();
}
}
}

The main window is not getting the focus back when you close the CanvasWindow. When you disable the button, nothing else on the window is focusable.
If you select the App from the windows taskbar (minimize and restore) or switch programs and come back using Ctrl+Tab it works.
Try giving the clickedButton focus after you re-enable it:
newWindow.Closed += (x, y) =>
{
clickedButton.IsEnabled = true;
clickedButton.Focus();
};

Related

Close the WPF dialog when one clicks on a button inside the WindowsFormHost

I have a WPF dialog, that hosts a windowsFormHost control, with something like this
<Window x:Class="WPFSort.MainWindow"
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"
xmlns:local="clr-namespace:WPFSort"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<WindowsFormsHost HorizontalAlignment="Left" Height="Auto"
Margin="87,43,0,0" VerticalAlignment="Top" Width="Auto">
<local:SimpleWinControl />
</WindowsFormsHost>
</Grid>
</Window>
And for the SimpleWinControl , it is a WinForm control. When button 1 is clicked, I want
The WPF dialog to be closed
And the data importantdata to be "pass out" to the WPF form that calls the WPF dialog?
public partial class SimpleWinControl : UserControl
{
public SimpleWinControl()
{
InitializeComponent();
}
public object importantdata;
private void button1_Click(object sender, EventArgs e)
{
//how should I write the close and pass the importantdata out
}
}
You could for example add a property to your WinForms control that exposes the Button control:
public partial class SimpleWinControl : UserControl
{
public SimpleWinControl()
{
InitializeComponent();
}
public Button TheButton { get { return button1; } }
...
}
Give the WinForms control an x:Name in your XAML markup:
<WindowsFormsHost HorizontalAlignment="Left" Height="Auto" Margin="87,43,0,0" VerticalAlignment="Top" Width="Auto">
<local:SimpleWinControl x:Name="winFormsControl" />
</WindowsFormsHost>
...and hook up to the Click event of the Button in the code-behind of your WPF dialog window:
public partial class Dialog : Window
{
public Dialog()
{
InitializeComponent();
winFormsControl.TheButton.Click += (s, e) => this.Close();
}
}
The window that opens the dialog could then access the importantdata field once the ShowDialog method returns:
private void ShowDialog_Click(object sender, RoutedEventArgs e)
{
Dialog d = new Dialog();
d.ShowDialog();
object importantData = d.winFormsControl.importantdata;
}
Another option may be to raise an event from the WinForms control: https://msdn.microsoft.com/en-us/library/5z57dxz2(v=vs.90).aspx

Add cofirmation message when ever user clicks on close button in WPF with MVVM

In WPF with MVVM,how to add a confirmation message when a user clicks on close button. Everytime,it just closes the window without any confirmation message whereas the same thing is happening in windows form.
In APP.XAML.CS
public partial class App : Application
{
protected override void OnExit(ExitEventArgs e)
{
if (MessageBox.Show("Sure you wanna close?", "..", MessageBoxButton.YesNo) == MessageBoxResult.No)
e.ApplicationExitCode = 110;
base.OnExit(e);
}
}
When i click on Close button it doesnt ask for confirmation just closes the window.
You could use a behavior.
First of all, you have to add a reference to Interactivity in your project.
Go to References-addReference-assemblies-System.Windows.Interactivity.
Now, you create the behavior.
public class CloseWindowBehavior : Behavior<Window>
{
protected override void OnAttached()
{
this.AssociatedObject.Closing += AssociatedObject_Closing;
}
private void AssociatedObject_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Sure you wanna close?", "..", MessageBoxButton.YesNo) == MessageBoxResult.No)
e.Cancel = true;
}
}
When you click on the close button, the event assigned will be fired, showing the message box.
Now, you have to declare this created behavior in your xaml file.
<Window x:Class="WpfApplication1.MainWindow"
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:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<i:Interaction.Behaviors>
<local:CloseWindowBehavior />
</i:Interaction.Behaviors>
<Grid>
</Grid>
Since you are using the pattern MVVM, behavior is a good choice since you don't need to write a single line in the code behind.
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
base.ShutdownMode = ShutdownMode.OnMainWindowClose;
//update user settings (if first run after software upgrade)
}
// Initialise the application directory//
// Set up the main window and its view model
var mainWindow = new MainWindow();
mainWindowViewModel = new MainWindowViewModel();
mainWindow.DataContext = mainWindowViewModel;
mainWindow.Show();
}
protected override void OnExit(ExitEventArgs e)
{
e.ApplicationExitCode = 110;
Dispose();
base.OnExit(e);
}

WPF weird window switching on double-click

Does anybody know how to implement a double-click event handler that opens a new window in a way the new window becomes the front most window? (Just the behavior that is normally expected).
In WPF there is a strange behavior of windows when opening a second window in the double-click event handler. The second window opens but the first window, where the double-click-event was fired, becomes activated again immediately.
Opening a window in a click event handler, works as expected. The second window opens and remains the front window.
For demonstration purposes I created the following application. Two window classes with just a button control. To distinguish between click and double-click on the button control, the click-event works only if the left shift key is pressed.
After double-click
http://blog.mutter.ch/wp-content/uploads/2014/05/wpf_window1.png
After click (this is also the expected behavior for double-click)
http://blog.mutter.ch/wp-content/uploads/2014/05/wpf_window2.png
Main Window
<Window x:Class="WpfWindowSwitching.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="200" Width="600">
<Grid>
<Button Margin="40"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MouseDoubleClick="doubleClick"
Click="click">
<TextBlock FontWeight="Bold"
FontSize="22">
I am the first Window, double click this button...
</TextBlock>
</Button>
</Grid>
</Window>
The code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void doubleClick(object sender, MouseButtonEventArgs e)
{
openNewWindow();
}
private static void openNewWindow()
{
var window = new SecondWindow();
window.Show();
}
private void click(object sender, RoutedEventArgs e)
{
if (!Keyboard.IsKeyDown(Key.LeftShift)) return;
openNewWindow();
}
}
Second Window
<Window x:Class="WpfWindowSwitching.SecondWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SecondWindow" Height="200" Width="600">
<Grid>
<Button Margin="40"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Click="click">
<TextBlock FontWeight="Bold"
FontSize="22">
I am the second Window
</TextBlock>
</Button>
</Grid>
</Window>
The code behind:
public partial class SecondWindow : Window
{
public SecondWindow()
{
InitializeComponent();
}
private void click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
After MouseDoubleClick event, MouseUp event is raised which gets handled on MainWindow. Hence secondary window gets activated momentarily and with subsequent event bubbling, main window gets activated.
In case you don't want that, you can explicitly stop event bubbling by setting e.Handled to True after mouse double click event. This way secondary window will remain activated.
private void doubleClick(object sender, MouseButtonEventArgs e)
{
openNewWindow();
e.Handled = true;
}

Caliburn.Micro - Setting focus in new window

My application is a topmost Window switching between multiple UserControl views. Its behavior is to close when the user clicks outside the window (more generally when it loses focus), and to show again when the user clicks on the system tray icon.
I'm having trouble getting the window to get focus when it shows up after clicking the tray icon. The problem is that the window shows up without focus and it doesn't hide when the user clicks outside. The user has to first click into the window and then click outside to trigger the Window's Deactivated event.
I can reproduce the problem with the most basic example from the documentation. I'm showing below the most basic representation of the problem I could produce.
I have tried many different things, none of which have shown any different behavior. For example, I tried calling the view's Focus() in the OnViewLoaded handler in the view models and deactivating the viewmodels instead of closing the window in the Close action. I also tried this suggestion on what seemed to be the same problem.
Any hint or help as to how to do this would be greatly appreciated.
[Export(typeof(ShellViewModel))]
public class ShellViewModel : Conductor<object>
{
IWindowManager windowManager;
[ImportingConstructor]
public ShellViewModel(IWindowManager windowManager)
{
this.windowManager = windowManager;
ShowPageOne();
}
public void ShowPageOne()
{
ActivateItem(new PageOneViewModel());
}
public void ShowPageTwo()
{
ActivateItem(new PageTwoViewModel());
}
public void Close()
{
this.TryClose();
// Using this to simulate the user clicking on a system tray icon
var timer = new Timer();
timer.Tick += (s, e) =>
{
windowManager.ShowWindow(this);
timer.Stop();
};
timer.Interval = 1000;
timer.Start();
}
}
My ShellView is:
<Window x:Class="PopupTest.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tc="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
Width="300" Height="400"
cal:Message.Attach="[Event Deactivated] = [Action Close]"
Topmost="True">
<StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="ShowPageOne" Content="Show Page One" />
<Button x:Name="ShowPageTwo" Content="Show Page Two" />
</StackPanel>
<ContentControl x:Name="ActiveItem" />
</StackPanel>
My two view models are:
public class PageOneViewModel : Caliburn.Micro.Screen { }
public class PageTwoViewModel : Caliburn.Micro.Screen { }
And the views are:
<UserControl x:Class="PopupTest.PageOneView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock x:Name="bob" FontSize="32">Page One</TextBlock>
</UserControl>

Make the WPF Combobox popup stay always open, make disappear with mouse click on "x"

I have a WPF Combobox with a ListView + "X"-Button in the Popup-DropDown. I am showing search results in that listview.
How can I make the popup close ONLY when the user clicks my "X"-Button in the popup?
You will probably have to write a custom control template for a permanently open listbox, or change the default one to behave like this. Inside the control template you have to set the StaysOpen property of the Popup to true and make your button switch that value
Short example
<Window x:Class="WPFComboSample.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>
<ComboBox Name="Combo">
<TextBox></TextBox>
<Button Name="Close" Width="150" Height="200" Click="Close_Click">Close</Button>
</ComboBox>
</Grid>
namespace WPFComboSample
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml>
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Close_Click(object sender, RoutedEventArgs e)
{
Combo.IsDropDownOpen = false;
}
}
}

Resources