WPF setting the owner of a window to its parent window MVVM - c#

Hypothetically let's say I have an application where I have Users and Tasks, each User have different Tasks assigned to them. I have a MainWindow that lists the users, and when you click on a User a ManageTasksWindow is opened, showing the Tasks assigned to the User and on this ManageTasksWindow you can remove, update and assign Tasks to this User. If I want to add a new Task to the User an AddTaskToUserWindow will be opened on a button click. My problem is that the logic that handles the opening of this AddTaskToUserWindow is in a class called TaskLogic and I have no idea how to reference the currently opened SubWindow, so that I can set the AddTaskToUserWindow's Owner property to the SubWindow.
I have tried this:
AddTaskToUserWindow window = new AddTaskToUserWindow();
window.Owner = Application.Current.Windows.OfType<ManageTasksWindow>().First();
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
But I want a solution, where each AddTaskToUserWindow's Owner property can be set to the corresponding SubWindow.

You can add a property to ViewModel of the main window (say SelectedWindow or ActiveWindow) and set its value whenever you select a user. Then, listening to the NotifyPropertyChanged of the main window, your TaskLogic can find the ActiveWindow whenever it changes automatically.

Related

Passing Details From One Window to Another Window

I have a selection of TextBoxes that a user fills in when they wish to note that they have had contact with another person. Most of the TextBoxes are imply filled in by typing into them. However, for one of them I would like the user to be able to select from a list of People that appears when they click on a button.
This is where I am having problems. So far I have just made a DataGrid appear and handled it's SelectionChanged method to fill in the TextBoxes text property. This has worked fine, however now there is not enough space on the current page to show an entire DataGrid with all the people they can select from.
I've decided to show the People in a separate, smaller Window that appears when the user clicks a Button. The issue I have is that when the user selects the Person they wish to mark the contact for in the new Window, I have no idea how I can notify the original Window that a Person has been selected, close the new smaller Window and fill in the appropriate TextBox on the original Window.
What would be the most intuitive way to fill in the TextBox on the original Window, based on the selection on the Window that opens?
I would use delegates,which call a function of the original window and parse the changed variable with it. So you know when the user clicked something and you can directly react to this "event".
Link:
https://msdn.microsoft.com/en-us/library/ms173171.aspx
If you use a framework like Galasoft's MVVM Light (http://www.galasoft.ch/), they have a messenger system just for this purpose. It allows you to "broadcast" messages that can be "received" by any other part of the application
This is when considering using Domain, Model, Presentation (Winforms/WPF version of MVC formatting) to do your app.
You can have each form as its own class, well they are their own class. Create each form class but add some public members to it if the controls are private. Have them have "get" properties only and to return the values of whatever controls or variables are in that form. Your main form will be the controlling form. All forms will be handled by the main form so when you open it, it is a class the main form can access.
Now, if I remember (been doing more MVC and not any Winforms lately) I believe if you use the ShowDialog() method it will freeze the main thread so when you close out the main form you can continue and read in public members you have in your forms class you opened. Synchronous I believe it runs as. If you use just Show() the thread will keep on trucking, asynchronous. With asynchronous you may then have to use a main form in your startup code so there is always a window there but subscribe to the close event of your forms and have a method that can grab those public members out. Be sure to instantiate the extra forms at the root of the main class so it doesn't fall out of scope when it exists the method that calls it. You may even be able to make the method that calls is a async call and have an await before the command that runs the Show method on the form.
Summary, treat each form as its own class but add public members that can read the values from the controls and/or variables you want. Read that data from the class when it closes via an event or synchronously when the thread closes out from the form closing. The form closing doesn't discard the object, just the visualization of the form.
Oh, if you are passing info from the main form to a child for you are opening, either add a constructor for that form class that takes your input as a model or values to fill in the appropriate variables or forms before showing it or create a public property you can put your values you want to send in before showing the class.
Remember, everything is a class, once you look at it as such and treat it as such, the answer will come. :-)
I should warn, I am a long winded explainer.
At work putting all this down from memory so some errors may exist. Let me know if there are.
I think the problem is to access the controls of the main window, isn`t it?
You can define an event of changing user`s choise and access MainWindow control by using the following construction:
((MainWindow)Application.Current.MainWindow).MyTextBox

Changing Content of Window from Button Click in User Control

I am working on a program that has a main window with only a ContentControl element.
In the class for this main window, I can change the content by ContentHolder.Content = new UserControlMain(). In UserControlMain, I have a button to once again change the content of the window to a new user control.
I am running into issues with changing the window content the second time. If I do not instantiate a class of MainWindow, I cannot access the Content property from anywhere except its own class. I also cannot access the ContentControl element I have associated with that class. However, if I do instantiate a MainWindow object, I run into an error message stating that the content has already been set.
Any tips on how I may get around this?
My advice is:
In MainWindow create a Grid with a name
<Grid name = "mainGrid">
</Grid>
Then, in code behind you can do easily this:
mainGrid.Children.Clear();
mainGrid.Children.Add(new UserControlMain());
Regards,

Make Notifyicon Appear on the MDIParent

In my Application I had a Main Menu Which is the MDIParent It has a menustrip in top to navigate to different forms and a panel in the bottom which contains a labelcontrol used to dispaly error messages and status.
My requirement is when there is any pending jobs left for the user ( it will be optained by a select query) I want to show a pop up like "You have pending jobs ", I wish to use a notify icon for that .
But my problem is the notify icon is always apperaing in the start bar of my Pc not on my application mdiparent
Can anyone suggest any remedy for that or any better ideas
I wish to use a notify icon for that
Use a ToolTip class:
var toolTip = new ToolTip
{
IsBalloon = true,
ToolTipIcon = ToolTipIcon.Info,
ToolTipTitle = "Pending jobs"
};
// 'this' means form
toolTip.Show("You have pending jobs", this, yourMdiParent.Location);

Window manipulation and inctences control

In my application there are only 2 windows — win_a & win_b, on each of these windows there is button that call another window, e.g. click on btn1 of win_a will call win_b, click on btn2 of win_b will show win_a.
Desired behaviour:
1. Only one instance of object is premitted at the same time, e.g. situation, where 2 instances of win_a running at the same time is not permitted.
When you click on button that calls windows that already exist this action will only change a focus to needed window.
If you call a window that previously had been created, but after this has been closed this action will create a new instance of this window. E.g. there are 2 running windows. you close one of them and after try to call this window back, so related button will create it.
How to write it in WPF (XAML + C#). For the moment I wrote a version that can create a lot of instances of the same window (no number of instances control implemented), but I want to see only one instance of the same window, as we can see it in a lot of applications.
Example of my code:
Window win = new Window();
win.Show();
Thanks.
first you need 2 references on each other window. on button click
you need to check one reference.
say in win_a
//win_b is a member on Windows_a class
if(_win_b.IsVisible())
{
// set focus on it
}
else
{
//show win_b
}
make the same for windows_b
I would suggest a different approach:
make a singleton class, that holds a list of tuples List>
when creating windows you can check if the window is in the collection or not.
if the collection holds a window you can set it activ win.Activate(),
else you can create it and add a reference to the collection list.add(tuple(win,"windowA"))
3.finally on the windows that you can add to the collection, on closing you need to remove the window from the singletons list, you can do this handling the Close event of the window
i don't have the code i wrote here, but i hope it helps.

WPF owner window on top of child window

Is it possible for Owner window in WPF be on top of Child window when you click on it while Owner window is below Child window?
here is example how I call child window:
Window2 window = new Window2();
window.Owner = this;
window.Show();
Parent/Owner window will always be under child window.
To get the behavior you want, you don't want to set the Owner on either window.
You, of course will have to handle the logic yourself when closing either of the windows to close your imaginary "child" window.
There may be some other logic you'll have to implement related to minimizing, maximizing, etc.
Many of the answers on this page involve nulling-out the Window.Owner property for some or all of the (non-MainWindow) windows in your System.Windows.Application. While this is a simple and easy fix that does indeed, in isolation, fix the issue of Window overlap, unfortunately it also inhibits a lot of useful application-wide functionality that WPF seems otherwise eager to provide in the areas of:
Application acti­vation/deactivation (via mouse-click, desktop Alt-Tab switching, etc...),
correct observance of the Application.​ShutdownMode property, and generally,
orderly cleanup, resource disposal, and exit of your Application upon shutdown.
It is possible fix the Window overlap issue while still preserving these system-wide WPF features by instead designating a special invisible window instance as your Application.MainWindow.
Modify your application so that the first Window it creates--which is the Window that gets assigned to Application.MainWindow--is a special dummy Window that is then made invisible by setting its Visibility to Visibility.Hidden or calling Window.Hide(). This will not hide its owned windows. Then, ensure that your desired "main" window containing your true content, plus all the other windows, owned by this invisible window.
Once hidden, the dummy Window will not show in the Windows 10 taskbar. You can set the Window.ShowInTaskbar property on whichever of the visible windows you deem appropriate to simulate apparent special designation, as required.
This approach allows any of the visible windows in your Application to be on top of the others, while still preserving WPF features and behaviors for system-wide app activation. For example, when the Application is activated (by clicking on any one of the windows, or via Alt-tab), all of the application's windows are together brought above any other desktop app windows, while still preserving the most recent "in-app" Z-order. WPF shutdown functionality is also preserved, including correct observation of the Application.ShutdownMode logic in accordance with the invisible MainWindow (or all the others) being closed.
I ran into a similar situation. I solved this by simply removing the owner after showing the window.
Window2 window = new Window2();
window.Owner = this;
window.Show();
window.Owner = null;
Edit:
Someone replied to this, and while looking at it, I decided I wanted to make an extension method.
public static void ShowAsIfChildOf(this Window childWindow, Window parentWindow)
{
childWindow.Owner = parentWindow;
childWindow.Show();
childWindow.Owner = null;
}
Please note that the solution mentioned by Licht
Window2 window = new Window2();
window.Owner = this;
window.Show();
window.Owner = null;
seems to me to be the same as
Window2 window = new Window2();
window.Show();
i.e., as if no ownership relationship has been set, i.e., when you close the owner window the owned windows do not close, etc., and may not be a solution when one would wish to have all of the ownership relationship features except "An owner window can never cover an owned window."
Once this relationship is established, the following behaviours are exhibited:
If an owner window is minimized, all its owned windows are minimized as well.
If an owned window is minimized, its owner is not minimized.
If an owner window is maximized, both the owner window and its owned windows are restored.
An owner window can never cover an owned window.
Owned windows that were not opened using ShowDialog are not modal. The user can still interact with the owner window.
If you close an owner window, its owned windows are also closed.
The best solution here looks to me to be the one with hidden main dummy window described by Glenn Slayden, at the link below, though it would be nice if there was a simpler one.
https://stackoverflow.com/a/66110288/19683309
Don't set Owner for child window, then in MainWindow handle OnClosing event like this:
private void MainWindow_OnClosing(object? sender, CancelEventArgs e)
{
foreach (var window in Application.Current.Windows)
{
if (window is Window appWindow)
{
if(appWindow.Equals(Application.Current.MainWindow))
continue;
appWindow.Close();
}
}
}

Categories