Is there a way to re-use an already closed WPF Window instance - wpf

I have a Window instance which I show by calling wInstance.ShowDialog() from a button click and I close the window by pressing Alt+F4. The issue now is that I cant call wInstance.ShowDialog() again. How can I re-use the same window instance again.
Exception :
Cannot set Visibility or call Show or ShowDialog after window has closed.

You need to override the wInstance OnClosing method to set the window visibility to hidden and cancel the close event.
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
this.Visibility = Visibility.Hidden;
e.Cancel = true;
}

What exactly is it that makes it so important to use the same window?
If you are using MVVM, you could just reuse the viewmodel for a new window.

I'm reusing a window as a Dialog that uses a treeview and the client wants the tree branches to remain open for a more selections.
The override worked for re-use, and the branches stay expanded.
I'm not using a view model to keep it simple as it is a read only selection dialog. But since I can't seem to clear the selection yet, I may have to switch to a view model.

Related

How to detect when a ChildWindow modal open/closes application-wide

Our application uses ChildWindow modals all throughout. I am in need of a way to detect when these ChildWindows are being opened and closed in order to do some UI trickery (don't ask and not important).
Alternatively, since the modal ChildWindow "grays out" and disables the app in the background while open, is there someway to hook into that event?
Lately, I've tried GotFocus and LostFocus events on the main LayoutRoot, but it's proven to be erratic. Any ideas would be greatly appreciated.
ChildWindow has a Closed event, so you can have some code run when it is closed, e.g.:
var window = new MyChildWindow();
window.Closed += (s, e) => DoSomethingWhenWindowCloses();
window.Show();

Application.Current.Activated doesn't fire while .ShowDialog() active

I am using Application.Current.Activated to bring all windows to the front when any one is clicked. This is working great, but doesn't work when I have a modal dialog open using .ShowDialog()
Clicks on other windows of the application (besides the dialog) do not result in the application being activated. The default behavior is to do nothing. (The clicks appear to be entirely IGNORED!)
How can I make it so that when any window of the application is clicked, the open dialog is brought to the front? (The expected behavior based on how pretty much every application works)
YES: I did set the owner of the dialog to my MainWindow, and clicking on the main window produces the desired result, but clicking any other window does nothing.
Code:
Create a new WPF project and add two windows.
Then put a button on MainWindow.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Window1 foo = new Window1();
foo.Show();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Window2 modal = new Window2();
modal.Owner = this;
modal.ShowDialog();
}
}
To see what I'm talking about, click the button to open the modal dialog.
The desired behavior is what happens when MainWindow is clicked.
I want the same to happen when Window1 is clicked.
AFAIK, a modal dialog (which .ShowDialog() triggers) blocks all other windows thereby Activation events.
As per the MSDN:
When a Window class is instantiated, it is not visible by default. ShowDialog shows the window, disables all other windows in the application, and returns only when the window is closed. This type of window is known as a modal window.
http://msdn.microsoft.com/en-us/library/system.windows.window.showdialog(v=vs.110).aspx
This may be an ugly hack, but maybe you can accomplish what you need to by creating your modal window on a separate thread thereby letting your main application continue to process activation (and other) events? You would need a way to prevent 2 of that 2nd modal dialog from opening though.

Setting focus on WPF ComboBox not always working

I have a solution, that has two projects, the main one and a small shared control that's used as well. In our application, a certain feature opens this shared control in a new window. I want to set the focus to the first combobox in this control when the window opens.
In my code, on the window that loads the shared control, at the end of the _Loaded event, I set focus to this combobox. But when running the code - I still have to hit tab to have 'keyboard' focus on the box (as in, I would have to hit tab to then start typing the name of one of the items in the list).
If I set a breakpoint here, hit it, and then continue - it actually is set the way it should be. If I use a WPF inspector - IsFocused is also set.
Other things noticed:
If I hit tab (to get what I want), then tab back, it takes me to the last control on the form, not to this unknown control. This makes me believe the focus is set right, but for some reason doesn't have correct keyboard focus.
If I try to use MoveNext in code, it actually selects the next item in the window, outside of the control.
How do I properly set focus here? On another combobox in the 'main' project, just calling .Focus() worked correctly.
try to postpone the focus() after all events are handled and bindings updated with QueueUserWorkItem. Something like this :
public delegate void VoidDelegate();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Some other things to do here.
System.Threading.ThreadPool.QueueUserWorkItem
(x => this.Dispatcher.Invoke(
new VoidDelegate(SetFocus), null));
}
private void SetFocus()
{
MyControlIWantToSetFocusOn.Focus();
}

Show Loading Image when TreeView Node is clicked in WPF

The question is we have a WPF application, which has Tree View. On the click of node Report gets generated which has no time interval (I mean no clue how much time it will take). So I am planning to show a Loading.gif file on the window till the report is generated.
How can I make the image (.gif) visible while the main window process to show the report and after showing the report I need to hide the image.
Do you have any other alternate method to do so.
Appreciate your help in advance.
You can make use of Extended WPF Toolkit's BusyIndicator.
Here's a sample of how to make async multi-threaded treeview -> http://www.codeproject.com/KB/WPF/ThreadedWPFExplorer.aspx
The general technique for this is:
1) Create an IsBusy property in the view model for your window; make sure it raises PropertyChanged when it changes.
2) In the code executed when the item is clicked, use a BackgroundWorker to run the long-running task.
3) Before calling BackgroundWorker.DoWork(), set IsBusy to true. In the event handler called when the BackgroundWorker.RunWorkerCompleted is raised, set IsBusy to false.
4) In the DataTemplate for the window, add a Style with a DataTrigger bound to IsBusy, and use that to control the visibility of the image.
Note that you may be able to move IsBusy (and the long-running task and the BackgroundWorker) to the item view model instead of the window view model, and add a "Loading" animation to the DataTemplate for the item.
If you do this, the user can start multiple items loading simultaneously, and the entire application doesn't lock up just because one item in the TreeView got clicked on. (Of course, you have to deal with any multithreading issues involved in generating multiple reports simultaneously).

How do I get the KeyDown event to fire in a custom container control?

I have a custom container control (deriving from FlowLayoutPanel) which contains zero or more child controls dragged there by the user. When a child control is clicked, it is "selected." (It is drawn with a colored border and options are available for altering its properties.)
I would like to handle the Delete key so that, if the user is currently working in the container control (clicked within the control or on a child control, for instance) the currently selected control (if there is one) is deleted.
I already have the delete functionality working using a right-click context menu on the child items. My problem is handling the Delete key. I cannot figure out how to get the KeyDown event to raise within my container control. I know it has something to do with focus, so that Control.Select() (or its equivalent) must be called, but what is the best way to go about this? Where does this focus logic reside? Or is there a better way?
I do not want to handle the KeyDown event in the form and then sniff out where the focus is. This is a reuseable container control and I want the logic to reside there.
What do I have to do to get the KeyDown event to fire on a custom control?
public class MyContainer : FlowLayoutPanel
{
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
MessageBox.Show("How do I get here?");
e.Handled = true;
}
base.OnKeyDown(e);
}
}
The KeyDown event is listed as unmeaningful for the FlowLayoutPanel control on MSDN. Suggest the PreviewKeyDown event as an alternative.
Is it possible that the items dragged into the container are receiving the event?
Perhaps after an item is drug into your container, you need to manually set the focus to the container.

Resources