WPF DragDrop: Window.ShowModal() hangs Windows Explorer - c#

I have written code to allow dropping a file from Windows Explorer into a WPF application. In my drop event handler I launch a window which displays information about the dropped file. If I create this window using Window.ShowModally() then Windows Explorer will hang/freeze until the window in my app is closed. However, if I create the window using Window.Show() this problem does not occur. Unfortunately, I require this window to be shown modally.
Presumably the Windows Explorer thread is locked because it detects that one of its files is being used. Is there a way to inform Windows Explorer that it does not need to wait for the window in my application to close? I have tried setting the DragDropEventArgs.Handled to true but this does not resolve the problem.
I no longer require the DragDrop once I have extracted the data from it so if there is a way to cancel or end the DragDrop in my Drop event handler then this would be an acceptable solution.

You cannot block in any of your drag+drop event handlers, that will hang the D+D plumbing and a dead source window is the expected outcome.
There's a simple workaround, just ask the dispatcher to run your code later, after the event completes. Elegantly done with its BeginInvoke() method. Roughly:
private void Window_Drop(object sender, DragEventArgs e) {
// Do something with dropped object
//...
this.Dispatcher.BeginInvoke(new Action(() => {
var dlg = new DialogWindow();
dlg.Owner = this;
var result = dlg.ShowDialog();
// etc..
}));
}

Related

Cross thread exception from minimized winform app

I have a FileSystemWatcher that is waiting for files to appear in a folder, which then triggers an insert to an ObservableCollection. When the form is open on the screen the update happens successfully. But when the form is minimized I get a cross-thread exception? I know I can just check for context, but I want to know why this behaviour is happening so I can ensure it doesn't come up again in other places.
I've tried this with a new blank winform app, and it errors 100% of the time whether it is minimised or not, so I'm unsure what I'm doing wrong or how to diagnose the issue. The main app is thousands of lines long, with many custom libraries so I can't post all of it here.
Called by the watcher
private void CheckForFiles(object source, FileSystemEventArgs e)
{
WaitingFiles.Add(e.FullPath);
}
Which triggers this
private async void WaitingFiles_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
CurrentProcessStatusLabel.Text = "Checking download for despatch file";
}
When I minimize the window I run the following code;
Hide();
SysTrayIcon.Visible = true;
Unless a SynchronizingObject is set, events are raised on a background thread, and background threads are not allowed to update the UI. I'm not sure why it works unless the application is minimized, but a good start is to ensure you are using correct synchronization to avoid issues like this.
If you want to update the UI you should either set the SynchronizingObject to one of the controls in your UI, or manually schedule any UI updates to the UI thread.

Show a Window while application is closing

I've a very heavy application that takes some time to close itself (it also depends on the pc where it is running.. but this is not the matter right now)
I would like to show a custom window with a message during this closing time, but as soon as i call the "Shutdown" method every window disappears (except made for the MessageBox).
This is the code i'm trying to use to achieve my objective
void MainWindow_Closing(object sender, CancelEventArgs e)
{
Task.Factory.StartNew(() =>
{
var closingWaitTest = "application closing, please wait;
Application.Current.Dispatcher.Invoke(() =>
{
var closingSplash = new ClosingSplashWindow(closingWaitTest);
closingSplash.Show();
});
MessageBox.Show(closingWaitTest);
});
Application.Current.Shutdown();
}
I Added a messageBox just to check, and it actually works. I mean, the MessageBox stays open until the application process is alive (i check that from the windows TaskManager) while my Window is instantly closed.
Hope someone can give some advice about this,
thanks in advance (:
EDIT -
So, the main problem is that as soon as i call the Application.Current.Shutdown my splash window instantly closes, while the application process is still up and running for some time (disposing all my things before calling shutdown actually reduced this time a bit).
The point is that i would like to show a window for the entirety of time that the process is still up; given the fact that a MessageBox behaves exactly like that, my question is:
Is there a way to make my ClosingSplashWindow behave like a MessageBox and stay visible until the application process is really dead?
Since Application.Current.Shutdown(); is going to close the application immediately. Maybe you first have a flag to track that application is being closed, cancel the Closing event and initiate the Resource cleanup followed by Application.Current.Shutdown(); again.
The Application_Closing handler may get fired once again, since you've a flag which says you're about to close you can directly exit the handler and all should be good.
First of all, you want to have a flag which indicates that your application is currently shutting down:
private bool IsShuttingDown { get; set; }
Then you should cancel closing operation, perform some heavy work and shut down your application:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (!IsShuttingDown)
{
e.Cancel = true;
ShowSplashWindow();
PerformHeavyOperation();
Application.Current.Shutdown();
IsShuttingDown = true;
}
}
In the end I solved the problem creating another application that shows a window while the main application process is still up and running.
I know it is not the best way to do it, but i was not able to do it in any other way..
Thank for the support! :)

Minimize Event ( C# Win 8.1 app)

I'm developing an App for windows 8.1 and i need to execute a method to pause some tasks or play a sound when the app is minimized in the sidebar.
I tried:
Application.Current.Suspending += new SuspendingEventHandler(Method_Name);
private void Method_Name(object sender, object e)
{
Other_Method();
}
But this event takes a few seconds (5~10) to occur after I minimize the app.
What event occurs when the app is dragged to the sidebar? What process sends the event?
Thanks.
Check out this post for the answer. It's WindowSizeChanged and check the value of ApplicationView.Value.
[EDIT]
Apparently for 8.1 things have changed a bit. The ApplicationView stuff is deprecated (that was quick) but this still takes place in SizeChanged for the window. Check out this for more details.
After long searching I found something that is not exactly what i wanted, but it works.
This event occurs everytime that visibility of the page changes (Is started, is maximized or minimized for exemple), then you must do some conditions using the if operator.
Window.Current.VisibilityChanged += new WindowVisibilityChangedEventHandler(One_Method);
private void One_Method(object sender, Windows.UI.Core.VisibilityChangedEventArgs e)
{
if(Some_Condition)
{
//TODO: Code that you want execute.
}
}
I'll keep the answer in open for the case of someone knows something more efficient.

Is ShowDialog handled differently in WPF than Winforms?

I have another issue in converting my Winforms program to a WPF program. In my first program, I had a smaller window open to allow the user to adjust some data, and then when it closed, the other form was activated again with the new data.
I used form2.ShowDialog(); to open the form, which automatically makes the parent form deactivated in Winforms. This way when I closed form2, the parent form was activated, and I was able to use an event handler form1_Activated to reload and re-initialize some of the settings successfully.
However, now when I attempt to do the same thing with WPF, I am still able to open form2 using form2.ShowDialog();, but then when I close the form, it does not register the form1_Activated event handler. Instead, in order to reload the settings, I must click on another window, and then come back into my program to register the form1_Activated event handler.
Am I just doing something wrong, or is there another event handler that I should be using in WPF to achieve the same thing I was able to do in Winforms?
Calling ShowDialog() causes the dialog box top appear in modal mode so I don't understand why you would need an event handler to process the results after the dialog box is closed. Keep in mind that you can access public variables in the DialogBox, as well. If I understand your question, this should do what you are asking:
MainWindow:
My_DialogBox dlg = new My_DialogBox();
dlg.Owner = this;
dlg.MyPublicVariable = ''; //some value that you might need to pass to the dialog
dlg.ShowDialog(); //exection of MainWindow is suspended until dialog box is closed
if (dlg.DialogResult == true)
{
//dlg.MyPublicVariable is still accessible
//call whatever routines you need in order to refresh the main form's data
}
DialogBox:
private void OK_Button_Click(object sender, RoutedEventArgs e)
{
MyPublic variable = something; //accessible after the dialog has closed.
this.DialogResult = true;
}
private void Cancel_Button_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
The MSDN write-up on dialog boxes is pretty good. There may be some tips that might help you even more:
http://msdn.microsoft.com/en-us/library/aa969773.aspx
Good luck!

How do I "Hide()" a Modal WPF Window without it closing?

I have a WPF window that is run on a background thread as a sort of "notifier window"... when an event is raised, it displays a message... a user clicks the "Snooze" button and I call this.Visibility = Visibility.Collapsed
The very moment that I hide the window (either by calling this.Hide() or setting the Visibility as mentioned above)... the "ShowDialog()" code releases the window and closes it.
This is absolutely a bug in the WPF code (which I've identified via reflector)... but my question remains. Has anyone been able to come up with a work-around for this issue?
I've tried many things and am now reaching out to ya'll smart people :)
You can't hide a modal dialog. That's like asking, "How do I get to 100mph in reverse?" You don't, you drive the car forwards.
Use Show, not ShowDialog. Alternately you can simply re-ShowDialog when it needs to become visible again.
Timothy's Answer is good. I just needed for my scenerio to add the following
window.Closed += new EventHandler(window_Closed);
window.Show();
System.Windows.Threading.Dispatcher.Run();
and then in the event...
void window_Closed(object sender, EventArgs e)
{
System.Windows.Threading.Dispatcher.ExitAllFrames();
}
I needed to do this because it was hanging on the Run after the form was really closed.
In order to show modal window always use ShowDialog().
Use Close() instead of Hide().
Handle the FormClosing event like that:
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Visible = false;
}
OK, and as quickly as that - my boss (old C++ goofy guy that he is) figured out the answer.
Here was the code inside of my background thread (which is set to STA mode):
// Show dialog - keeps the thread open and shows the window! Yay!!!
new BeamUI.Notifier.NotifierWindow().ShowDialog();
And here is the modification, that strangely enough works perfectly :)
// Show... hmm, that shows the window... but how do I keep this thread open?
new BeamUI.Notifier.NotifierWindow().Show();
// ZOMG - a line of code that JUST keeps the thread (and msgpump) going!!!
System.Windows.Threading.Dispatcher.Run();
And that's it.
This kinda thing makes me hate C++ people though, and makes me want to just say "if you just built it right in the first place I wouldn't have to look for a work-around!" (j/k)

Categories

Resources