Pushing window to foreground - c#

i'm using a listview to display multiple items to the user. Now I want that the user has the ability to open an detail window with an double click. This works fine but when the window is opened it's immediatly pushed to the background.
I tried several things with the window state etc. the result was in every situation terrible(window is pushed to background or the window is a permanent overlay). The only solution that works relative well is that I change the DoubleClick Event in a MouseLeftButtonUp Event. When a user now click an item the window are in the foreground.
This is my code from the controller class:
public void ShowDetails(object details)
{
Details detailWindow = new Details(this, Config.GetCultureInformation());
detailWindow.LoadData(details);
detailWindow.Show();
}
This my code from the UI Class
private void listViewItem_MouseClick(object sender, MouseButtonEventArgs e)
{
ListViewItem item = sender as ListViewItem;
AppControl.ShowDetails(item.Content);
}

You should show it as modal.
public void ShowDetails(object details)
{
Details detailWindow = new Details(this, Config.GetCultureInformation());
detailWindow.LoadData(details);
detailWindow.ShowDialog(); //Instead of detailWindow.Show();
}
If you want to keep your main window without freeze use detailWindow.BringToFront() or detailWindow.TopMost = true, take a loot at this other post
Source here.

Ok. Thank you for your help and with Topmost I find I way to create a solution that suits for me.
In the constructor of my window I set topmost to true and in the Window is Loaded Event I set topmost to false. My Window is prominent in the foreground but the user can go out of it and can handle things in the main app.

Related

C# wpf multiple windows on task bar

I created a C# project which have multiple windows. When I do some other stuff, some of the windows are lost focus. Then I have to bring them to front by clicking the task bar one by one.
I am wondering is there are OnTaskBarClick Event on C# wpf window?
Then What I need to do is to set all sub windows with "ShowInTaskbar="False"". Then when ever my mainwindow is clicked on the task bar, I bring all the windows to the front.
You'll want to use the Window.Activated event to detect when your application's window is brought into focus:
From the documentation:
A window is activated (becomes the foreground window) when:
The window is first opened.
A user switches to a window by selecting it with the mouse, pressing ALT+TAB, or from Task Manager.
A user clicks the window's taskbar button.
Or you could use the Application.Activated event.
Clicking on a control of an already active window can also cause the Window.Activated event to fire, so if the issue is that it's firing too often, you'll probably want to watch for when the application toggles between being active and deactive.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Application.Current.Activated += CurrentOnActivated;
Application.Current.Deactivated += CurrentOnDeactivated;
}
private bool isDeactivated = true;
private void CurrentOnDeactivated(object sender, EventArgs eventArgs)
{
isDeactivated = true;
//handle case where another app gets focus
}
private void CurrentOnActivated(object sender, EventArgs eventArgs)
{
if (isDeactivated)
{
//Ok, this app was in the background but now is in the foreground,
isDeactivated = false;
//TODO: bring windows to forefont
MessageBox.Show("activated");
}
}
}
I think what you are experiencing is the window Owner not being set on your child window.
Please refer to Window.Owner Property
When a child window is opened by a parent window by calling
ShowDialog, an implicit relationship is established between both
parent and child window. This relationship enforces certain behaviors,
including with respect to minimizing, maximizing, and restoring.
-
When a child window is created by a parent window by calling Show,
however, the child window does not have a relationship with the parent
window. This means that:
The child window does not have a reference to the parent window.
The behavior of the child window is not dependent on the behavior of the parent window; either window can cover the other, or be
minimized, maximized, and restored independently of the other.
You can easily fix this by setting the Owner property in the child window when before calling Show() or ShowDialog()
Window ownedWindow = new Window();
ownedWindow.Owner = this; // this being the main or parent window
ownedWindow.Show();
Note : if conforming to an MVVM pattern, this can become a little
more cumbersome, however there is plenty of resources on how to link owner and parent windows.

Open .net windows form after event finishes

I'm having a Windows Mobile CE application written in C# with .Net CF.
Consider i have 2 forms in my application:
List of objects (has a listview)
Details page (should appear when something is selected in previous listview)
Currently i'm attaching callback to listview's SelectedIndexChanged event, and open a new form there.
New form opens okay (in the midde of the event callback), but when i close the form(this.Close()), then the list page isn't clickable first time, after the first click UI is interactable again.
Also the the ListViewItem clicked at first step doesn't get selected(blue background).
Here's a short (12s) video showing this problem: http://take.ms/urkme
As you see from the video, after coming back from details screen, refresh button doesn't click on the first click..
I'm showing the details form like so:
private void listView_SelectedIndexChanged(object sender, EventArgs e)
{
(new FormDetails()).ShowDialog();
}
Is there any way to show the details form after event finishes, or am i doing it completely wrong?
PS! Tried the same with a Button and it's click event, then all worked nicely..
As I know ListView's SelectedIndexChanged event fired twice on almost case not like Button's Click event which fired once, this maybe what cause that weird interaction. Maybe try changing to ItemSelectionChanged event as suggested in here.
Your problem is caused by using the SelectedIndexChanged event. When you select an item in your list you'll set the SelectedIndex, if you select the same item again the index won't be changed so you'll never call the event.
You could use the Click event to trigger the wanted response.
Here is an example:
private void listView1_Click(object sender, EventArgs e)
{
var firstSelectedItem = listView1.SelectedItems[0]; //This is your selected item.
//do stuff
}
When you use ShowDialog() you open a form in modal mode. All further processing of following code will not take place until the modal form is closed or returns a DialogResult.
Better use a modeless form using .Show().
private void listView_SelectedIndexChanged(object sender, EventArgs e)
{
(new FormDetails()).Show(); //will not stop processing of events in mainForm
}
If the new FormDetails is finished, it can use a simple Hide or Close to bring up the main form to foreground.
Remember that the main form is still there and will not wait for the FormDetails being closed (as it is a modeless dialog).

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!

Is there any way to detect a mouseclick outside a user control?

I'm creating a custom dropdown box, and I want to register when the mouse is clicked outside the dropdown box, in order to hide it. Is it possible to detect a click outside a control? or should I make some mechanism on the containing form and check for mouseclick when any dropdownbox is open?
So I finally understand that you only want it to close when the user clicks outside of it. In that case, the Leave event should work just fine... For some reason, I got the impression you wanted it to close whenever they moved the mouse outside of your custom dropdown. The Leave event is raised whenever your control loses the focus, and if the user clicks on something else, it will certainly lose focus as the thing they clicked on gains the focus.
The documentation also says that this event cascades up and down the control chain as necessary:
The Enter and Leave events are hierarchical and will cascade up and down the parent chain until the appropriate control is reached. For example, assume you have a Form with two GroupBox controls, and each GroupBox control has one TextBox control. When the caret is moved from one TextBox to the other, the Leave event is raised for the TextBox and GroupBox, and the Enter event is raised for the other GroupBox and TextBox.
Overriding your UserControl's OnLeave method is the best way to handle this:
protected override void OnLeave(EventArgs e)
{
// Call the base class
base.OnLeave(e);
// When this control loses the focus, close it
this.Hide();
}
And then for testing purposes, I created a form that shows the drop-down UserControl on command:
public partial class Form1 : Form
{
private UserControl1 customDropDown;
public Form1()
{
InitializeComponent();
// Create the user control
customDropDown = new UserControl1();
// Add it to the form's Controls collection
Controls.Add(customDropDown);
customDropDown.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
// Display the user control
customDropDown.Show();
customDropDown.BringToFront(); // display in front of other controls
customDropDown.Select(); // make sure it gets the focus
}
}
Everything works perfectly with the above code, except for one thing: if the user clicks on a blank area of the form, the UserControl doesn't close. Hmm, why not? Well, because the form itself doesn't want the focus. Only controls can get the focus, and we didn't click on a control. And because nothing else stole the focus, the Leave event never got raised, meaning that the UserControl didn't know it was supposed to close itself.
If you need the UserControl to close itself when the user clicks on a blank area in the form, you need some special case handling for that. Since you say that you're only concerned about clicks, you can just handle the Click event for the form, and set the focus to a different control:
protected override void OnClick(EventArgs e)
{
// Call the base class
base.OnClick(e);
// See if our custom drop-down is visible
if (customDropDown.Visible)
{
// Set the focus to a different control on the form,
// which will force the drop-down to close
this.SelectNextControl(customDropDown, true, true, true, true);
}
}
Yes, this last part feels like a hack. The better solution, as others have mentioned, is to use the SetCapture function to instruct Windows to capture the mouse over your UserControl's window. The control's Capture property provides an even simpler way to do the same thing.
Technically, you'll need to p/invoke SetCapture() in order to receive click events that happen outside of your control.
But in your case, handling the Leave event, as #Martin suggests, should be sufficient.
EDIT: While looking for an usage example for SetCapture(), I came across the Control.Capture property, of which I was not aware. Using that property means you won't have to p/invoke anything, which is always a good thing in my book.
So, you'll have to set Capture to true when showing the dropdown, then determine if the mouse pointer lies inside the control in your click event handler and, if it doesn't, set Capture to false and close the dropdown.
UPDATE:
You can also use the Control.Focused property to determine if the control has got or lost focus when using a keyboard or mouse instead of using the Capture with the same example provided in the MSDN Capture page.
Handle the Form's MouseDown event, or override the Form's OnMouseDown
method:
enter code here
And then:
protected override void OnMouseDown(MouseEventArgs e)
{
if (!theListBox.Bounds.Contains(e.Location))
{
theListBox.Visible = false;
}
}
The Contains method old System.Drawing.Rectangle can be used to indicate if
a point is contained inside a rectangle. The Bounds property of a Control is
the outer Rectangle defined by the edges of the Control. The Location
property of the MouseEventArgs is the Point relative to the Control which
received the MouseDown event. The Bounds property of a Control in a Form is
relative to the Form.
You are probably looking for the leave event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.leave.aspx
Leave occurs when the input focus leaves the control.
I just wanted to share this. It is probably not a good way of doing it that way, but looks like it works for drop down panel that closes on fake "MouseLeave", I tried to hide it on Panel MouseLeave but it does not work because moving from panel to button leaves the panel because the button is not the panel itself. Probably there is better way of doing this but I am sharing this because I used about 7 hours figuring out how to get it to work. Thanks to #FTheGodfather
But it works only if the mouse moves on the form. If there is a panel this will not work.
private void click_to_show_Panel_button_MouseDown(object sender, MouseEventArgs e)
{
item_panel1.Visible = true; //Menu Panel
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!item_panel1.Bounds.Contains(e.Location))
{
item_panel1.Visible = false; // Menu panel
}
}
I've done this myself, and this is how I did it.
When the drop down is opened, register a click event on the control's parent form:
this.Form.Click += new EventHandler(CloseDropDown);
But this only takes you half the way. You probably want your drop down to close also when the current window gets deactivated. The most reliable way of detecting this has for me been through a timer that checks which window is currently active:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
and
var timer = new Timer();
timer.Interval = 100;
timer.Tick += (sender, args) =>
{
IntPtr f = GetForegroundWindow();
if (this.Form == null || f != this.Form.Handle)
{
CloseDropDown();
}
};
You should of course only let the timer run when the drop down is visible. Also, there's probably a few other events on the parent form you'd want to register when the drop down is opened:
this.Form.LocationChanged += new EventHandler(CloseDropDown);
this.Form.SizeChanged += new EventHandler(CloseDropDown);
Just don't forget to unregister all these events in the CloseDropDown method :)
EDIT:
I forgot, you should also register the Leave event on you control to see if another control gets activated/clicked:
this.Leave += new EventHandler(CloseDropDown);
I think I've got it now, this should cover all bases. Let me know if I'm missing something.
If you have Form, you can simply use Deactivate event just like this :
protected override void OnDeactivate(EventArgs e)
{
this.Dispose();
}

MDI window list not updating child title bar texts

I have a MDI container form, and some child forms that update their title bar texts themselves, independently. After the Text property is changed on the child form, the new title bar text from the child is not updated in the window list menu when the menu is opened. This is the auto-generated window list provided by .NET via the MdiWindowListItem property.
The change only propagates when another event changes the window list physically (opening a new child, closing a child, switching to another child).
Is there a way to force an update of the window list programmatically? I already have some code in place to do menu enabling/disabling at the same time the child's title bar text is changed.
I tried the following with no success:
Update() on the main MenuStrip
Refresh() on the main MenuStrip
Invalidate() on the window MenuStrip
Invalidate() on one of the window list items at runtime
Toggling the Checked state twice on one of the window list items at runtime
There don't seem to be any other remotely viable functions to call on the menu item, its parent ToolStrip, or the parent form that contains the menu system.
The above solution did not work for me. But I followed the link, and found this, which works perfectly:
private void windowMenu_DropDownOpening(object sender, EventArgs e)
{
if (this.ActiveMdiChild != null)
{
Form activeChild = this.ActiveMdiChild;
ActivateMdiChild(null);
ActivateMdiChild(activeChild);
}
}
Thank you!
You need to add a TextChanged event to the child form, with this handler:
private void childForm_TextChanged(object sender, EventArgs e) {
this.ActivateMdiChild( null );
this.ActivateMdiChild( sender as Form );
}
http://social.msdn.microsoft.com/forums/en-US/winforms/thread/a36b89aa-57aa-48b5-87a6-49fbddc9c92d
Instead of activate/deactivate, you can send WM_MDIREFRESHMENU message to the MDI client (not frame) window whenever a window title changed.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644919%28v=VS.85%29.aspx

Categories

Resources