How to close Win32 SaveFileDialog when an error has occurred? - c#

I've run into an issue with the Microsoft.Win32.SaveFileDialog in our Wpf application.
If the user enters an enormous file path, above the allowed maximum (I think its 255 chars?), within the SaveFileDialog then it starts to become unusable (details of this are in the code example).
So as a work-around I want to close the dialogue and make them enter the file path again. However the problem is that the SaveFileDialog does not have a Close() routine or anything else that I can see to close it. How can I close the dialogue programmatically?
// error only seems to occur if a filter is specified.
var dialog = new Microsoft.Win32.SaveFileDialog
{
Filter = "My juicy file (*.mjf) | *.mjf"
};
try
{
dialog.ShowDialog();
}
catch (System.IO.PathTooLongException error) // handle
{
/*
* if I handle this exception (by displaying a message to the user)
* the dialog will remain open, but if the user attempts to use it
* and enter another filename a mixture of the following exceptions
* are raised:
*
* AccessViolationException
* FatalExecutionEngineError
* ExecutionEngineException
*/
MessageBox.Show(error.Message);
}
EDIT
Thanks for you answers/comments. I've just tested this on my Windows 7 box and it behaves as expected so this maybe an issue only on XP.

In WPF 4.0 on Windows 7 the SaveFileDialog is showing its own error dialog:
<long path?
The path is too long.
Try a shorter name.
with an OK button to dismiss the error dialog. That leads the user back to the original SaveFileDialog where they can change their value or Cancel.
For earlier versions where the behavior might be different, you can use the Windows UI Automation framework to programmatically click the 'Cancel' button on the SaveFileDialog.

if (dialog != null)
{
dialog.DialogResult = DialogResult.Cancel;
}
Try setting the dialog result to close the dialog.

Send the window a WM_SYSCOMMAND message with a wParam parameter of SC_CLOSE. This is the equivalent of clicking on the Close button in the upper-right corner of the dialog.

Related

How to check if a dialog is open in PowerPoint?

I have an application written in C# using Microsoft.Office.Interop.PowerPoint. This application opens a PowerPoint presentation file to the user. The user interacts with the file. After applying some modifications, the user submits the file through the application submit button.
The Problem:
When user modifies the content of the presentation, for example changes font color of the text to red, by using a dialog and keeps the dialog open without clicking on "Apply" or "OK" button and thereby submits the file by clicking on application submit button, those dialog done changes aren't reflected in the submitted file and hence such changes can't be tracked of.
I somehow want to alert a user to close any open dialog before clicking on submit button.
I do this easily on Word and excel files by checking Exception on saving such files because Word and Excel throws exception on using save method if there is any dialog open, like the Following:
try{
document.Save();
}
catch (Exception e){
//Alert user here here
}
but this doesn't work for PowerPoint files. I tried the following:
PowerPointApplication application = new Microsoft.Office.Interop.PowerPoint.Application();
Microsoft.Office.Interop.PowerPoint.Presentations presentations = application.Presentations;
Microsoft.Office.Interop.PowerPoint.Presentation presentation =
presentations
.Open(file, WithWindow: Microsoft.Office.Core.MsoTriState.msoTrue,ReadOnly:Microsoft.Office.Core.MsoTriState.msoFalse,Untitled:Microsoft.Office.Core.MsoTriState.msoFalse);
The following is triggered on Submit button click event:
try
{
presentation.Save();
}
catch (Exception e)
{
//alert user here
}
Is there a way to track if there are any open dialog boxes?
Typically if any dialog window is displayed to a user the code is blocked because the dialog window uses the main thread for running. Do you use multiple threads in the code?
Anyway, you can use Windows API functions for detecting the active window, see GetActiveWindow which retrieves the window handle to the active window attached to the calling thread's message queue. To get the handle to the foreground window, you can use GetForegroundWindow. To get the window handle to the active window in the message queue for another thread, use GetGUIThreadInfo.
After retrieving the window handle you can use the GetWindowText function which copies the text of the specified window's title bar (if it has one) into a buffer. If the specified window is a control, the text of the control is copied.

Detect if an open file dialog pops up in a browser

I am automating a file upload with C# and selenium (running Google Chrome), but I don't want to type the file path on the file input, I would like to emulate how a real user would do it (Typing the path in the file dialog box). Using the SendKeys.SendWait() method is the perfect solution for this, however I am encountering a problem.
I have the following code.
var e = driverWait.Until(driver => driver.FindElement(By.Id("file-button")));
e.Click();
SendKeys.SendWait(#"C:\Users\seawolf\Downloads\Result.pdf");
The problem is before the open file dialog pops up, SendWait begins typing on the keyboard, so the path is typed on the Webpage and not the dialog box.
Is there a way until an open file dialog pops up with C#? It doesn't have to be built into selenium as it's easy to integrate everything with driverWait. What I want to do is something like:
driverWait.Until(_ => DialogIsOpen() );
Thanks to #Jimi, here is my solution.
var chromeElement = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "Chrome_WidgetWin_1"));
var openDialogClassName = "#32770";
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, chromeElement, TreeScope.Subtree, (sender, _) =>
{
var element = sender as AutomationElement;
Console.WriteLine("running");
if (element.Current.ClassName.Equals(openDialogClassName))
{
SendKeys.SendWait(#"C:\Users\seawolf\Downloads\Result.pdf");
}
});
This is what I use. I just put a wait to allow for the window to appear before using sendwait. A majority of times, you will switch focus to the upload window once it appears.
//Click browse btn to open upload window
driver.FindElement(By.ClassName("uploadbtn")).Click();
//Wait for Upload Window to appear(may not be necessary in some cases)
Thread.Sleep(2000);
//Send the path and then click the Right arrow key
SendKeys.SendWait(GetProjectRoot() + #"\DataFiles\red.png" + #"{RIGHT}");
//Click Enter Key to submit
SendKeys.SendWait(#"{Enter}");

Opening a new WPF Window before WaitForExit() without making the window stuck

I'm developing a WPF Application. Right now I'm trying to do something like this:
//Print the information about what happened, and open toolbar.
MessageBox.Show("Cannot find the destination file, The application will now open Google Chrome." + Environment.NewLine
+ "Please fill in the information and when you finish close Google Chrome.");
//open Attributes Toolbar
new AttributesToolbar(application.Attributes).Show();
//start google chrome and wait for the user to close it
Process.Start(startInfo).WaitForExit();
var success = (MessageBox.Show("Did you succeed?", "Status check", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes);
return new RPAResult()
{
Succeeded = success
};
These are the steps:
1) After the application could not found a configuration file, it prints a message that the user has to fill in some details himself (That's the background story, not so important).
2) The application opens a toolbar window - that's a WPF Window with some details that the user has to copy and paste from it to the chrome page.
3) The application opens google chrome and waits until the user closed it
The problem is when the "WaitForExit()" command is executed, the entire application is freezed, even the new WPF Window that has just been opened and the user cannot copy and paste anything.
I have tried to open a new thread but it causes a STAThread problem.
Any help please?
You could try to start your process in a task and then continue on exit with your message box.
Task.Factory.StartNew(() =>
{
Process.Start(startInfo).WaitForExit();
}).ContinueWith(prevTask =>
{
var success = (MessageBox.Show("Did you succeed?", "Status check", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes);
[...]
});

Why does a folder dialog immediately close unless a window is displayed in WPF?

I'm developing a WPF application that's meant to live in the tool tray, so it doesn't involve any windows. Right-clicking the tool tray icon brings up a menu with a Configure Report Path... option, and I'd like to display a folder browser dialog to the user when this is clicked:
What I'm finding is that when the option is selected, a dialog opens and immediately closes unless I assign some window to Application.Current.MainWindow and show it before opening the dialog. This is the code I'm using:
public CounterIconViewModel(IMessenger messenger)
{
void ConfigureReportPath()
{
// Application window must be created and displayed.
Application.Current.MainWindow = new Window();
Application.Current.MainWindow.Show();
var browseDialog = new VistaFolderBrowserDialog { ShowNewFolderButton = false };
if (browseDialog.ShowDialog() != true)
{
return;
}
// (Separate issue) Command doesn't execute unless I comment out the line below.
//messenger.Send(browseDialog.SelectedPath, "ReportPath");
}
ConfigureReportPathCommand = new RelayCommand(ConfigureReportPath);
ExitApplicationCommand = new RelayCommand(Application.Current.Shutdown);
}
In this case I'm using VistaFolderBrowserDialog from Ookii.Dialogs.Wpf, but I've tried the same thing with another WPF browser dialog and notice identical behaviour.
Is there a reason why a browser dialog seems to require a window to be displayed to remain open, and any workarounds?
Update
I've found that if I initialize and pass an instance of Window to browseDialog.ShowDialog, the dialog remains open without me having to assign the main application window and display it:
if (browseDialog.ShowDialog(new Window()) != true)
I don't understand why this works. I'll post this as an answer if no others appear so that at least people in a similar situation are aware of this workaround.
Update 2
The other dialog I tested it with was CommonOpenFileDialog from Microsoft.WindowsApiCodePack-Shell:
var browseDialog = new CommonOpenFileDialog { IsFolderPicker = true };
browseDialog.ShowDialog();
My tool tray icon displays a rich tool-tip (a custom UserControl) if I hover over it, and with this browser dialog I found that:
If I hover over the icon to make the tool-tip display, then the browser dialog works fine when I try to open it on the first and every subsequent attempt.
If I try to open the browser dialog before displaying the tool-tip display, the browser dialog opens and closes immediately on the first try, but then remains open on every subsequent attempt.
This dialog also accepts a Window instance in ShowDialog but it makes no difference if I pass one or not.
My workaround (initializing and passing a blank window to the Ookli dialog browser) seems to work fine regardless of whether I first bring up the tool-tip, so I'm sticking with that for the time being.

Yes-No MessageBox appearing too early in a worker thread

My program needs to display a dialog box to the user, which prompts the user to select the save folder, and then displays a Yes-No buttons messageBox to ask the user to confirm that they wish to continue.
This is my code:
/* Wait until user has selected a save folder */
do { } while (sSaveFolder == null);
/* Cancel operation if user clicks on cancel when in folder selection window */
if (sSaveFolder == "<cancel>")
{
worker.ReportProgress(0, "Operation Cancelled\r\n\r\n**********\r\n");
return;
}
/* Check for confirmation */
if (MessageBox.Show("Please confirm whether or not to continue.", "Do you wish to continue?", MessageBoxButtons.YesNo) == DialogResult.No)
{
worker.ReportProgress(0, "Operation Cancelled\r\n\r\n**********\r\n");
return;
}
The problem I'm getting is that I can run this once, click No and the worker thread terminates. But, if I click on the button to run the worker thread again, I get the message box popping up at the same time as the save folder dialog box - which, for obvious reasons is problematic. So does anyone know why this might be happening and how to solve it?
I found a work around to my particular problem by moving the message box to before the save folder dialog box but, as this is a weird problem, I thought I'd ask about it crops up again in the future.
Thanks in advance :)
I cannot see anywhere in your code where the value of sSaveFolder would be reset.
Since you are reusing the same object the previous value may still be set, so the do...while completes very quickly and therefore the messagebox is displayed.
Resetting the value of sSaveFolder before you display the dialog should fix your problem.

Categories

Resources