disabling mdi child maximizing when activating by clicking on title bar - c#

I have an MDI form that I open multiple child windows into. I have noticed that if I click the title bar of an a child form that is not the active mdi child, that that child becomes actived and maximizes. This behavior does NOT happen when I click the unactivated child in a place other than the title bar. How can I disable the maximizing in this case? I still want to be able to maximize the form using the maximize button on the title bar. It would also be nice to be able to maximize a form when double-clicking the title bar (just not single-clicking).
I have found this routine to be causing the problem, but not sure how. This method is called whenever when an mdi child's activated event is called. This specific statement is causing the problem: "if (dv.Disk.IsOS9)"
private void UpdateDiskMenu()
{
if (this.ActiveMdiChild == null)
{
diskToolStripMenuItem.Enabled = false;
}
else
{
diskToolStripMenuItem.Enabled = true;
DiskViewer dv = (DiskViewer)this.ActiveMdiChild;
if (dv.Disk.IsOS9) // <----- Problem occurs here.
{
//if (((OS9Format)dv.Disk).BootstrapLSN > 0)
// bootstrapToolStripMenuItem.Enabled = true;
//else
// bootstrapToolStripMenuItem.Enabled = false;
}
}
}

Related

How can I hide a window WITHOUT Visibility property?

I have an application that has a lot of modal popup windows. Some are custom windows displayed with .ShowDialog(), other are generic message boxes using a 3rd party tool (DXMessageBox.Show(...)), and others are system dialogs such as an OpenFileDialog. If the user leaves the application running long enough, it should time out and show a "Session Locked" screen and prevent users from seeing or interacting with the application until they login again. This is problematic because of the modal dialogs.
My current solution is to host the Relogin screen in the current modal window if there is one, and hide all other windows. The problem is that if I set Visibility = Hidden on any window I have called using .ShowDialog(), it treats that dialog as having received a result and processes the code that handles the dialog result. They are also no longer modal after they are re-shown.
So my current attempt is to try to hide the window using something other than Visibility, and prevent it from being activated. The closest I've come is by setting Minimized=true and ShowInTaskbar=false, but this results in an undesirable minimized titlebar above my taskbar.
Is there a way to prevent this from happening, or alternatively is there another way to hide a window and prevent it's activation without causing .ShowDialog to return?
Here's some code to re-create a sample application to test this with. Just add a button to launch the ShowLock_Click event handler.
private readonly Dictionary<System.Windows.Window, WindowStyle> _hiddenWindows = new Dictionary<System.Windows.Window, WindowStyle>();
// Create a button to launch this for testing
private void ShowLock_Click(object sender, RoutedEventArgs e)
{
// Will show another window with .ShowDialog, then 2s timeout will trigger lock window
using (new System.Threading.Timer(OnLockTimerElapsed, null, 2000, System.Threading.Timeout.Infinite))
{
ShowTestDialog();
}
}
private void OnLockTimerElapsed(object state)
{
_hiddenWindows.Clear();
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
var mainWindow = Application.Current.MainWindow;
Window host = null;
foreach (Window win in Application.Current.Windows)
{
if (IsModalDialog(win))
host = win;
_hiddenWindows.Add(win, win.WindowStyle);
// Been testing various ways to hide window without using Visibility
win.ShowInTaskbar = false;
win.WindowStyle = WindowStyle.None;
win.WindowState = WindowState.Minimized;
win.Opacity -= 1;
win.IsHitTestVisible = false;
}
ShowLockScreen(host);
}));
}
private void ShowLockScreen(Window owner = null)
{
var lockScreen = new Window
{
Title = "Relogin Window",
Content = "This is a test Relogin Window. Close Window via X to continue",
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
if (owner != null)
lockScreen.Owner = owner;
lockScreen.ShowDialog();
// Once that window closes, restore other windows
RestoreSession();
}
private void RestoreSession()
{
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
foreach (var win in _hiddenWindows.Keys)
{
win.ShowInTaskbar = true;
win.WindowStyle = _hiddenWindows[win];
win.WindowState = WindowState.Normal;
win.IsHitTestVisible = true;
win.Opacity += 1;
}
}));
}
private void ShowTestDialog()
{
var test = new Window
{
Title = "Test Modal Dialog",
Content = "This is a test Modal Dialog. Close window via X to continue.",
Height = 100,
Width = 350,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Owner = this
};
var result = test.ShowDialog();
// This code gets run if I set Visibility=Hidden. I do not want that.
MessageBox.Show($"Test Dialog result returned. Result : {result}. This should ONLY happen when you click X on the dialog window");
}
private static bool IsModalDialog(Window window)
{
return (bool)typeof(System.Windows.Window)
.GetField("_showingAsDialog", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.GetValue(window);
}

C# WinForms TabControl Remove Tab and close child controls

I have a parent container (form) that initializes a new TabPage with a user control inside of it (called from the Menu Strip). The Tab Control has a Context Menu that, when you right click and select "Close Selected Tab", I call a method that Removes that tab. However, it does not stop the code within that TabPage's user control from running. How can I clean this up so when I close the Tab (TabPages.Remove... etc) that it also closes the user control within that TabPage so that any background code stops executing?
The code below is what closes the tab:
The latter part just selects the next tab to the left after the tab is removed.
public static void closeCurrentTab(TabControl tc)
{
int curTabIndex = tc.SelectedIndex;
TabPage tp = tc.SelectedTab;
tc.TabPages.Remove(tp);
if(curTabIndex > 0)
{
tc.SelectedTab = tc.TabPages[(curTabIndex - 1)];
}
}
I found the issue. I found that the asynchronous processes within the child control were running astray even after the parent control (in this case being the TabPage) was disposed of.
A simple example of how I solved it is below.
Also, for more complex task chaining , I can introduce cancellation tolkens once the parent becomes null, thus cleaning up whatever needs to be once a user closes a tab hosting that control, but doesnt close the overall application.
using this.Parent and testing whether it is null or not whevenever id like to.
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
if(this.Parent == null)
{
// Clean up
}
}
and \ or this
private async Task popUp()
{
do
{
MessageBox.Show("Im running!");
await Task.Delay(5000);
}
while (this.Parent != null);
}

UIAutomation Click button without making window take focus and GetCurrentPattern() returning unsupported pattern

I have the handle of a window and what I want to do is click it's button named "Load Settings". I have 2 problems.
My first problem is when I call Invoke on a certain InvokePattern, it brings the window to focus and this is undesirable for my application.
My second problem is visible and documented in the comments towards the end of my following code:
AutomationElement aeBot = AutomationElement.FromHandle(mbotSettingList.ElementAt(i).getWindowHandle());
AutomationElement aeButtonLoadSettings = aeBot.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Load Settings"));
InvokePattern ipClickLoadSettings = (InvokePattern)aeButtonLoadSettings.GetCurrentPattern(InvokePattern.Pattern);
Thread invokeLoadSettingsThread = new Thread(ipClickLoadSettings.Invoke);
InvokePattern ipClickOpen = null;
AutomationElement aeOpenDialogEdit = null;
AutomationElement aeButtonOpen = null;
AutomationElementCollection aeDialogs = null;
AutomationElement aeOpenDialog = null;
ValuePattern vpOpenDialogEdit = null;
//Using a thread to invoke the Load Settings button click because as a result of clicking Load Settings a dialog is opened and invoke doesnt return for nealy 10 seconds
invokeLoadSettingsThread.Start();
//We probably wont join() this thread because it goes on for far longer than we expect to be in this function
//Get a collection of the Dialog windows that are direct children of the main window we have a handle to
aeDialogs = aeBot.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"));
while (aeDialogs.Count == 0)
{
//This while loop is to continue to check for the Open file dialog as it may take a little time to open
aeDialogs = aeBot.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "#32770"));
Thread.Sleep(250);
}
for (int j = 0; j < aeDialogs.Count; j++)
{
//There is usually only 1 child dialog window, but just make sure we have the correct one
if (aeDialogs[j].Current.Name == "Open")
{
Debug.WriteLine("Found open dialog!");
aeOpenDialog = aeDialogs[j];
break;
}
}
//Inside the Open window, the first Edit window is the one where the file name/path should be entered
aeOpenDialogEdit = aeOpenDialog.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"));
//Set the value of the file name/path to the string variable "loadSettingsString"
vpOpenDialogEdit = (ValuePattern)aeOpenDialogEdit.GetCurrentPattern(ValuePattern.Pattern);
vpOpenDialogEdit.SetValue(loadSettingsString);
//******************************************PROBLEM BEGINING BELOW******************************************
//Using multiple methods, we can successfully get a successful AutomationElement for the "Open" button in the Open file dialog
aeButtonOpen = aeOpenDialog.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Open"));
//aeButtonOpen = aeOpenDialog.FindFirst(TreeScope.Subtree, new PropertyCondition(AutomationElement.NameProperty, "Cancel"));
//Something to consider: If we assigned aeButtonOpen to the AutomationElement we find be looking for "Cancel" rather than "Open"
Debug.WriteLine(aeButtonOpen.Current.Name + " button found!");
//Prints "Open button found!"
//If aeButtonOpen were assigned to "Cancel", this would print "Cancel button found!"
ipClickOpen = (InvokePattern)aeButtonOpen.GetCurrentPattern(InvokePattern.Pattern);
//GetCurrentPattern has returned null
//If aeButtonOpen were assigned to "Cancel", this would NOT be null
ipClickOpen.Invoke();
//Invoke() on a null results in "Unsupported Pattern" exception
//If aeButtonOpen were assigned to "Cancel", this would work and the Open file dialog would then be exited just as if cancel were clicked
Use UIAVerify to look at the UIA tree of your application. Looking at your code, I suspect you're not retrieving the element you think you are. If the 'Open' element is a button, it should support the Invoke pattern.
Alternatively, you are opening a dialog and then immediately searching for a sub element of that dialog. It is possible that you are running into a reliability issue here where the UIA tree is still being created for that dialog. To check for this, add a sleep for one second and see if that resolves your issue. If this is the case, look into UIA structure changed events. Those events will let you synchronize your UIA test code against changes in the UIA tree.

Simple UI issue in winforms

I have a simple winforms application, on performing operations it shows a child window everytime. If I open a browser window (fully maximized) or some other window as usual
the application goes back with its childwindow, on clicking the exe which is in the taskbar
only the child window gets visible,but the application window doesn't come into view. I want to know how to show both the windows when I select it from taskbar.
childwindow is also a winform,whose toplevel property is set as true,apart from it nothing
is new(JUST BY CLICKING A BUTTON OR CELL IN GRID I CREATE AN OBJECT FOR THE FORM AND USES IT SHOW PROPERTY TO SHOW)
AlertMsgWindow _alertMsg;
void dataGridViewAlerts_MouseDoubleClick(object sender, MouseEventArgs e)
{
try
{
if (!string.IsNullOrEmpty(this.dataGridViewAlerts.getValue(0, this.dataGridViewAlerts.SelectedRow)))
{
this.dataGridViewAlerts.setCellImage(0, this.dataGridViewAlerts.SelectedRow, "NewsIconRead");
if (_alertMsg == null || _alertMsg.IsDisposed)
{
if (_alertMsg != null)
{
_alertMsg.onDeleteMessageRequest -= new DeleteMessage(_alertMsg_onDeleteMessageRequest);
_alertMsg.Dispose();
}
_alertMsg = new AlertMsgWindow();
_alertMsg.onDeleteMessageRequest += new DeleteMessage(_alertMsg_onDeleteMessageRequest);
}
_alertMsg.FillDetails(alertDetails[IDcollection[this.dataGridViewAlerts.SelectedRow]]);
if (!_alertMsg.Visible)
{
_alertMsg.Location = PointToScreen(new Point(this.Width / 4, -this.Height));
_alertMsg.Show(this);
}
if (onReadMessageReq != null)
onReadMessageReq(IDcollection[this.dataGridViewAlerts.SelectedRow]);
}
}
catch (Exception)
{ }
}
Note: THIS IS HAPPENING ONLY IN WINDOWS2000
I used a component named Dotnetmagic.dll,i dont know whether it causes the problem.can somebody helps me to solve this
I replaced these lines
_alertMsg.Location = PointToScreen(new Point(this.Width / 4, -this.Height));
With
_alertMsg.Left = x;
_alertMsg.Top = y;
and it solved my problem

C# WatiN - Add an AlertDialogHandler to click ok button on every Alert dialog window

Hello
Those who have used WatiN likely also used DialogHandlers.
Well can someone teach me how can i assign a DialogHandler that will handle any Alert Box window.alert(), of a specific IE instance under WatiN control .
The DialogHandler only has to click in the OK button for very alert dialog box, in that case i think we need an AlertDialogHandler that basically only has to click the OK button.
AlertDialogHandler.OKButton.Click()
I've search the web and found a few examples.. But they work for a small period of time or the time you specify, i need one that will work forever, until i choose to stop it by clicking a button.
This as been bugging my head for hours, any help is appreciated. Thanks.
Note: Sometimes the alert dialog window has two buttons. Thats why i really need to click the OK button, not just Close the dialog window.
Create class:
public class OKDialogHandler : BaseDialogHandler
{
public override bool HandleDialog(Window window)
{
var button = GetOKButton(window);
if (button != null)
{
button.Click();
return true;
}
else
{
return false;
}
}
public override bool CanHandleDialog(Window window)
{
return GetOKButton(window) != null;
}
private WinButton GetOKButton(Window window)
{
var windowButton = new WindowsEnumerator().GetChildWindows(window.Hwnd, w => w.ClassName == "Button" && new WinButton(w.Hwnd).Title == "OK").FirstOrDefault();
if (windowButton == null)
return null;
else
return new WinButton(windowButton.Hwnd);
}
}
After creating instance of IE, attach dialog handler to it:
ie.AddDialogHandler(new OKDialogHandler());
This dialog handler will handle all windows, that contains a button with "OK" caption, by clicking on that button.

Categories

Resources