I am in a fairly odd situation here. I have created a custom MessageBox form (instead of the built-in MessageBox.Show). The below code is what I use to call up the form, when I need it:
internal DialogResult ShowCustomMessageBox(string message, string caption, Icon icon = null)
{
var result = DialogResult.None;
MainForm.Get.UISynchContext.Send(s =>
{
var messageBox = new DialogBox
{
Icon = icon,
Text = caption,
rtbInDialogBox = { Text = message }
};
result = messageBox.ShowDialog();
messageBox.Dispose();
}, null);
return result;
}
When I run this, I get an error message on messageBox.ShowDialog(); that the messageBox instance has already been disposed.
When I post the code to the synchronization context I was pretty sure MainForm would run the code itself (as opposed to other threads), and I am not sure why it tells me that the messageBox has already been disposed.
Any ideas?
I found the problem. Apparently you need to specify the owner of the dialog box: result = messageBox.ShowDialog(MainForm.Get);
Related
I have a WPF window and I'm calling it from a C++/cli code and it works fine. What I need is what's the best way to intercept user action I mean whether he click OK or Cancel. Wath I think to do is to define a Boolean property in my window and set it depends on user action. Here is my code :
MyWindowView^ window = gcnew MyWindowView();
System::Windows::Interop::WindowInteropHelper^ windowInteropHelper = gcnew System::Windows::Interop::WindowInteropHelper(window);
windowInteropHelper->Owner = (IntPtr)AfxGetMainWnd()->m_hWnd;
window->WindowStartupLocation = System::Windows::WindowStartupLocation::CenterScreen;
window->ShowDialog();
if ()
{
//some action
}
else
{
//
}
Also I want to know do I need to delete the window object ?
Window.ShowDialog returns dialog result. I can't see any reason to get this result in some way, that differs from C# or VB .NET:
System::Nullable<System::Boolean> result = window->ShowDialog();
if (result.HasValue)
{
// OK or Cancel
if (result.Value)
{
// OK clicked
}
else
{
// Cancel clicked
}
}
else
{
// dialog closed via system menu or Alt+F4
}
do I need to delete the window object ?
No, you don't. See this answer.
So I'm working with selenium firefox webdrivers in c# winform and I have this code below to get the handle of the popup that shows when you click on the "webtraffic_popup_start_button" and it should get the handle of the popup but the popup handle is same as current one.
string current = driver.CurrentWindowHandle;
driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']")).Click();
Thread.Sleep(Sleep_Seconds);
popup = driver.CurrentWindowHandle;
Thread.Sleep(3000);
driver.SwitchTo().Window(current);
Thread.Sleep(1000);
Any help with this would be much appreciated thank you
This is what pop up looks like.
WebDriver does absolutely no tracking whatsoever to detect which window is actually in the foreground in the OS, and does no automatic switching when new browser windows are opened. That means the proper way to get the handle of a newly-opened popup window is a multi-step process. To do so, you would:
Save the currently-focused window handle into a variable so that you
can switch back to it later.
Get the list of currently opened window handles.
Perform the action that would cause the new window to appear.
Wait for the number of window handles to increase by 1.
Get the new list of window handles.
Find the new handle in the list of handles.
Switch to that new window.
In code using the .NET language bindings, that would look something like this:
string currentHandle = driver.CurrentWindowHandle;
ReadOnlyCollection<string> originalHandles = driver.WindowHandles;
// Cause the popup to appear
driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']")).Click();
// WebDriverWait.Until<T> waits until the delegate returns
// a non-null value for object types. We can leverage this
// behavior to return the popup window handle.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
string popupWindowHandle = wait.Until<string>((d) =>
{
string foundHandle = null;
// Subtract out the list of known handles. In the case of a single
// popup, the newHandles list will only have one value.
List<string> newHandles = driver.WindowHandles.Except(originalHandles).ToList();
if (newHandles.Count > 0)
{
foundHandle = newHandles[0];
}
return foundHandle;
});
driver.SwitchTo().Window(popupWindowHandle);
// Do whatever you need to on the popup browser, then...
driver.Close();
driver.SwitchTo().Window(currentHandle);
Alternatively, if you're using the .NET bindings, there's a PopupWindowFinder class in the WebDriver.Support assembly that is specifically designed to do these operations for you. Using that class is much simpler.
// Get the current window handle so you can switch back later.
string currentHandle = driver.CurrentWindowHandle;
// Find the element that triggers the popup when clicked on.
IWebElement element = driver.FindElement(By.XPath("//*[#id='webtraffic_popup_start_button']"));
// The Click method of the PopupWindowFinder class will click
// the desired element, wait for the popup to appear, and return
// the window handle to the popped-up browser window. Note that
// you still need to switch to the window to manipulate the page
// displayed by the popup window.
PopupWindowFinder finder = new PopupWindowFinder(driver);
string popupWindowHandle = finder.Click(element);
driver.SwitchTo().Window(popupWindowHandle);
// Do whatever you need to on the popup browser, then...
driver.Close();
// Switch back to parent window
driver.SwitchTo().Window(currentHandle);
If the lastly opened window is your target then simply do the following after the click
driver.SwitchTo().Window(driver.WindowHandles.ToList().Last());
EDIT
//You may need to go back to parent window to perform additional actions;
// to the new window
driver.SwitchTo().Window(driver.WindowHandles.ToList().Last());
// to the new window
driver.SwitchTo().Window(driver.WindowHandles.ToList().First());
//or
driver.SwitchTo().DefaultContent();
I've got some code you might like. The quickest solution is to use Popup Finder, but I've made my own method as well. I would never rely on the order the Window Handles are in to select the appropriate window. Popup Window Finder:
PopupWindowFinder finder = new PopupWindowFinder(driver);
driver.SwitchTo().Window(newWin);
My Custom method. Basically you pass it the element you want to click, your webdriver, and optionally the time to wait before searching after you click the element.
It takes all of your current handles and makes a list. It uses that list to eliminate the previously existing windows from accidentally getting switched to. Then it clicks the element that launches the new window. There should always be some sort of a delay after the click, as nothing happens instantly. And then it makes a new list and compares that against the old one until it finds a new window or the loop expires. If it fails to find a new window it returns null, so if you have an iffy webelement that doesn't always work, you can do a null check to see if the switch worked.
public static string ClickAndSwitchWindow(IWebElement elementToBeClicked,
IWebDriver driver, int timer = 2000)
{
System.Collections.Generic.List<string> previousHandles = new
System.Collections.Generic.List<string>();
System.Collections.Generic.List<string> currentHandles = new
System.Collections.Generic.List<string>();
previousHandles.AddRange(driver.WindowHandles);
elementToBeClicked.Click();
Thread.Sleep(timer);
for (int i = 0; i < 20; i++)
{
currentHandles.Clear();
currentHandles.AddRange(driver.WindowHandles);
foreach (string s in previousHandles)
{
currentHandles.RemoveAll(p => p == s);
}
if (currentHandles.Count == 1)
{
driver.SwitchTo().Window(currentHandles[0]);
Thread.Sleep(100);
return currentHandles[0];
}
else
{
Thread.Sleep(500);
}
}
return null;
}
i have a wpf application, i need to display a messagebox, the problem is that the message box is displayed for 0.5 second and doesn't even wait for user to click OK.
MainWindow.xaml.cs :
public partial class MainWindow : Window
{
public MainWindow()
{
//verifying application setting file to see if the connection is ok
string pathToApp = System.AppDomain.CurrentDomain.BaseDirectory + "settings.sts";
ApplicationSettings applicationSettings = new ApplicationSettings();
applicationSettings.ServerIp = "127.0.0.1";
applicationSettings.ServerDatabase = "test";
applicationSettings.ServerUserName = "root";
applicationSettings.MakeConnectionString();
foreach (char c in "")
{
applicationSettings.ServerPassword.AppendChar(c);
}
MySqlConnection connection = new MySqlConnection(applicationSettings.ConnectionString);
try
{
connection.Open();
}
catch (Exception e)
{
// here the message box shows for 0.5 second and closes immediately
MessageBox.Show(e.Message);
}
finally
{
connection.Close();
}
//display window
InitializeComponent();
}
i should also that am using a image as a splash screen, if this have a relation with the message box.
sorry this code is not yet completed. thanks in advance
Your problem stems from a known issue with WPF:
First, it happens when used with the splash screen. If you don't specify an parent for a message box, it assumes the splash screen is it's parent and is therefore closed when the splash screen closes. Second, even if you specify the parent as the MainWindow while in MainWindow's constructor, it still won't work since MainWindow doesn't have a handle yet (it gets created later on).
So, the solution is to postpone the invocation of the message box until after the constructor, and by specifying MainWindow as the parent. Here is the code that fixes it:
Dispatcher.BeginInvoke(
new Action(() => MessageBox.Show(this, e.Message)),
DispatcherPriority.ApplicationIdle
);
Here's a reference to the parent/splash issue:
http://connect.microsoft.com/VisualStudio/feedback/details/381980/wpf-splashscreen-closes-messagebox
In my situation (minimal tray icon app) there was no splash screen or MainWindow.
I found this solution from another SO question helpful:
var tempWindow = new Window();
var helper = new WindowInteropHelper(tempWindow);
helper.EnsureHandle();
MessageBox.Show(tempWindow, "Lorem Ipsum");
tempWindow.Close();
(I am not sure if the .Close() can be omitted)
Please can someone tell me the technique that would be used, for the following scenario.
I would like to authenticate users, before I allow my code to perform another action.
I have a method that opens a new window that contains my authentication form (username and password).
private bool userLogin()
{
Window loginInterface = new Window()
{
Title = "Please Login",
Content = new login(),
Height = 282,
Width = 300,
ResizeMode = ResizeMode.NoResize,
WindowStartupLocation = WindowStartupLocation.CenterOwner
};
loginInterface.Owner = this;
loginInterface.ShowDialog();
return true;
}
I'm calling this method like so, on button click:
private void perform_action(object sender, RoutedEventArgs e)
{
if (!userLogin())
{
// Failed login, do nothing
}
else
{
// Authentication successful, perform action
delete_item();
}
}
The window opens fine, but how can I now make my method return true or false based on the what the user does on the opened form?
So when the user clicks the login button named login_button, my code already validates the credentials, but I need the 'bool' value sent back.
Can I make my first window almost wait for an action to be performed on another window and get the response back?
The Window.ShowDialog() method actually already returns a bool?. This can be set at any point from within the Window by setting (for example) this.DialogResult = true. You can then close the window and access the value from the calling code.
To close the window with a result:
this.DialogResult = true;
...and then to use that result in the calling code:
var myWindow = /*create window*/;
var result = myWindow.ShowDialog();
if (result == true)
{
//...
}
To close the login screen you can set DialogResult to true or false, and ShowDialog returns this value. For other things you can create events on the second window and subscribe to them on the first.
userLogin should return something other than true.
I would do something like this (based on the code shown):
return loginInterface.WasSuccessful; // you'd have to add this property
How might one go about creating a Modeless MessageBox? Do I have to just create my own Windows Form class and use that? If so, is there an easy way of adding a warning icon (rather than inserting my own image of one) and resizing based on text volume?
If you need a message box that just displays itself while your code continues running in the background (the box is still modal and will prevent the user from using other windows until OK is clicked), you can always start the message box in its own thread and continue doing what ever you do in the original thread:
// Do stuff before.
// Start the message box -thread:
new Thread(new ThreadStart(delegate
{
MessageBox.Show
(
"Hey user, stuff runs in the background!",
"Message",
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
})).Start();
// Continue doing stuff while the message box is visible to the user.
// The message box thread will end itself when the user clicks OK.
You'll have to create a Form and use Show() to display it Modeless. MessageBox.Show(...) behaved Modal as seen in the example by ghiboz; "Description of the message" is displayed until the user presses a button.
With MessageBox.Show(...) you get the result as soon as the messagebox is closed; with a modeless message box, your code will have to have a mechanism such as an event to react when the user eventually selects something on your message box.
Short of writing the code, you could create a small form that in the constructor does the following
Takes a parameter string as the message to display
Fills up a label on the form with this string
Loads an icon with one of the following (pass in an Enum to the constructor)
SystemIcons.Application
SystemIcons.Asterix
SystemIcons.Error
SystemIcons.Exclamation
SystemIcons.Hand
SystemIcons.Information
SystemIcons.Question
SystemIcons.Shield
SystemIcons.Warning
SystemIcons.WinLogo
Calls Show() which will cause it to be a modal dialog
If you really wanted, you could listen to an event that is fired when the OK button is pushed.
You can use the standard system warning icon using SystemIcons
You have to either use form and call showDialog()
And for icons use
MessageBoxIcon.Warning
Note: this will create a Modal dialog box, which is not what the question is asking
here is a sample code
if (MessageBox.Show("Description of the message", "Caption text", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes)
{
// Do some stuff if yes pressed
}
else
{
// no pressed
}
//no commnet
object sync = new object();
ManualResetEvent Wait = new ManualResetEvent();
//you should create a place holder named MessageData for Message Data.
List<MessageData> Messages = new List<MessageData>();
internal void ShowMessage(string Test, string Title, ....)
{
MessageData MSG = new MessageData(Test, Title);
Wait.Set();
lock(sync) Messages.Add(MSG);
}
// another thread should run here.
void Private_Show()
{
while(true)
{
while(Messsages.Count != 0)
{
MessageData md;
lock(sync)
{
md = List[0];
List.RemoveAt(0);
}
MessageBox.Show(md.Text, md.Title, md....);
}
Wait.WaitOne();
}
}
needs more threads and more code(I don't have enough time to write) for concurrent messageboxes.