I've made a Windows Forms solution. In the main shell, there is added a MenuStrip, and it's possible to add more Views onto it.
The problem is, that when I add/open a new View, it is opened behind the MenuStrip.
Somehow, I want the MenuStrip to have a border, so it is not possible to drag things behind it, but I have no idea how.
The same case should be with other Views.
You should set the Dock property for the control that you want to add.
OK, I have a solution - I don't totally like it but it works! You will need the usual MDI suspects in terms of flags, etc.
The main form that is the MDI container needs to have something like:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
int BodyCount = 0;
private void fileToolStripMenuItem_Click(object sender, EventArgs e)
{
MDIChildForm child = new MDIChildForm();
child.TitleText = String.Format("Child window {0}", ++BodyCount);
child.MdiParent = this;
child.Show();
}
/*
** This could be fun - shouldn't recurse!
*/
public void ShifTheChild(MDIChildForm spoiltBrat)
{
var m = menuStrip1.Height;
if (spoiltBrat.Location.Y < m)
spoiltBrat.Location = new Point(spoiltBrat.Location.X, 0);
return;
}
}
The child forms need the location changed event hooking:
public partial class MDIChildForm : Form
{
public String TitleText
{
get { return this.Text; }
set { this.Text = value; }
}
MainForm parent = null;
public MDIChildForm()
{
InitializeComponent();
this.ShowIcon = false;
}
private void MDIChildForm_LocationChanged(object sender, EventArgs e)
{
if (parent != null)
parent.ShifTheChild(this);
}
private void MDIChildForm_Load(object sender, EventArgs e)
{
parent = this.MdiParent as MainForm;
}
}
When you move a child into the twilight zone under the menu it will be snapped back out - the method that moves it will cause the event to fire again but the second time nothing should happen (so no recursion).
I don't like this solution simply because I can't get my brain around whether there is a condition that would make it recurse, and I don't like uncertainty.
Good luck.
Related
Scenario:
Three forms: MainWindow, Positions, Calibration self-named (MainWindow : Window etc.)
MainWindow creates an instance of three objects:
Vars: Model Vars = new Model();
Positions: Positions PositionsWindow = new Positions();
Calibration: Calibration CalibrationWindow = new Calibration();
A button in MainWindow is used to Show and Hide the child windows. Form fields in MainWindow update fields in class Vars.
MainWindow code:
public partial class MainWindow : Window
{
Model Vars = new Model();
Positions PositionsWindow = new Positions();
Calibration CalibrationWindow = new Calibration();
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
PositionsWindow.Show();
}
private void TextBoxUpdate_Click(object sender, RoutedEventArgs e)
{
Vars.TestVar = TestBox.Text;
}
}
Question: How can form fields in the child windows update the parent form fields and/or fields in the class "Vars", i.e. passing data from child to parent and trigger an action in the parent form?
Attempts: A similar question suggested passing the main window this, example: Positions PositionsWindow = new Positions(); however, this only works when the object is created in a method. At this point, PositionsWindow.Show(); is no longer valid. i.e. it is only suitable for a child window created and closed in a single method.
I would not really recommend initializing the variables before the constructor. Don't get used to that.
I would change the constructor of each of the three Windows:
public partial class Model : Window{
MainWindow MW;
Model(MainWindow MW){
this.MW = MW;
// other constructor stuff
}
}
Do the same thing for Positions and Calibration.
Obviously, you cannot use this when you are INITIALIZING the Windows BEFORE the constructor is called, because there is still no this to pass.
Therefore, in your MainWindow:
public partial class MainWindow : Window
{
Model Vars; // = new Model(this); <- the constructor was not yet called, there is no this
Positions PositionsWindow; // = new Positions();
Calibration CalibrationWindow; // = new Calibration();
MainWindow(){
Vars = new Model(this);
Positions = new Positions(this);
CalibrationWindow = new Calibration(this);
}
private void OpenButton_Click(object sender, RoutedEventArgs e)
{
PositionsWindow.Show();
}
private void TextBoxUpdate_Click(object sender, RoutedEventArgs e)
{
Vars.TestVar = TestBox.Text;
}
}
Edit: (to complete the answer to the question):
Now, if you want the Windows to change stuff to each other, just create functions in MainWindow that change stuff in each of the Windows. And with MW you can call these functions from any child Window
For me the best is using Subscribe/Publisher event-based way, here is the way to do it. (i recreate the code so that you can understand)
1) add an event publisher in your child windows.
public partial class ChildWindows : Window
{
// the is the event publisher
public event Action<string> ChildUpdated;
public ChildWindows()
{
InitializeComponent();
}
private void updateParentBtn_Click(object sender, RoutedEventArgs e)
{
// pass the parameter.
ChildUpdated(updateTb.Text);
}
}
2) Subscribe the publisher in your parent windows.
public partial class MainWindow : Window
{
Model Vars;
ChildWindows childWindows;
public MainWindow()
{
InitializeComponent();
Vars = new Model();
childWindows = new ChildWindows();
//this is the event subscriber.
childWindows.ChildUpdated += ChildWindows_ChildUpdated;
}
//do whatever you want here.
void ChildWindows_ChildUpdated(string obj)
{
// Update your Vars and parent
Vars.TestVar = obj;
updateLbl.Content = Vars.TestVar;
}
private void openButton_Click(object sender, RoutedEventArgs e)
{
childWindows.Show();
}
private void textBoxUpdate_Click(object sender, RoutedEventArgs e)
{
}
}
3) In this case, when i type inside the textbox in my child windows, and press a button, it will appear on a label inside my parent windows.
P/S : i had changed the ParentUpdated to ChildUpdated. thanks to #Adrian for constructive feedback
example
Im running into a bit of an issue regarding Children and parents.
I have 2 forms which have the same dropdown menus, both of which have the ability to add additional options to them. When the "(add new)" option is selected in any of the combo boxes my third form is loaded which enables the addition of a new option.
This is the code for that third window (as it stands)
public partial class taskNewDropdownEntry : Form
{
taskWindow _owner;
applianceWindow _owner2;
int windowType;
int manufacturer_id;
sqlMod data = new sqlMod();
public int setManufacturerID {get { return manufacturer_id; } set { manufacturer_id = value; } }
public taskNewDropdownEntry(taskWindow owner, int type)
{
InitializeComponent();
this._owner = owner;
this.windowType = type;
}
public taskNewDropdownEntry(applianceWindow owner, int type)
{
InitializeComponent();
this._owner2 = owner;
this.windowType = type;
}
private void taskNewDropdownEntry_Load(object sender, EventArgs e)
{
if (windowType == 1)
{
instructionLabel.Text = "Input the new appliance type below";
}
else if (windowType == 2)
{
instructionLabel.Text = "Input the new manufacturer below";
}
else if (windowType == 3)
{
instructionLabel.Text = "Input the new model below";
}
}
private void btnOK_Click(object sender, EventArgs e)
{
if (windowType == 1)
{
data.insertApplianceType(textField.Text);
_owner.refreshTypeCombo();
}
else if (windowType == 2)
{
data.insertManufacturerSimple(textField.Text);
_owner.refreshManuCombo();
}
else if (windowType == 3)
{
data.insertModelSimple(manufacturer_id, textField.Text);
_owner.refreshModelCombo();
}
this.Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
Now, my issue is that the 2 forms that call this third form are different - thus my only thought of how to solve this would be to duplicate some of the code and modify the methods (you can see the second constructor already added).
Instead of having multiple constructors, and duplicated methods (in this class, or in a seperate one) is there a way whereby I can use the same constructor but different owners depending on the form that calls it?
You have too much implementation in your child form. The way I would tackle this is to
Add a property to your child form:
public string InstructionLabel { get; set; }
This allows your parent forms to individually set the label text when instantiating the form, and also set up an event handler for when the form is closing. So your parent form would have code something like
var newItemForm = new taskNewDropdownEntry();
newItemForm.InstructionLabel = "Input the new appliance type below";
newItemForm.FormClosing += new FormClosingEventHandler(ChildFormClosing);
Then somewhere early in your child form's life cycle (FormLoading event) set
instructionLabel.Text = InstructionLabel;
Then also add a property in the child form for
public string NewItem { get; set; }
your child form should set this public property in the btnOK_Click event
private void btnOK_Click(object sender, EventArgs e)
{
this.NewItem =textField.Text;
}
Then your parent form listens for a FormClosing event, and when it hits that event it takes the NewItem text, adds it to the relevant combo and refreshes it. So in the parent form, the handler looks like
private void ChildFormClosing(object sender, FormClosingEventArgs e)
{
sqlMod data = new sqlMod();
data.insertApplianceType(textField.Text);
refreshTypeCombo();
}
Pretty hard to understand the question but code speaks for all.
There are 2 options, worse (because keeping the parent reference is not a good practice first of all):
create an interface that both classes taskWindow and applianceWindow (where is the naming convention for god's sake!) implement, ex
intrerface IRefreshable {
void refreshManuCombo();
}
then constructor and your poperty can have type of IRefreshable
IRefreshable _owner;
public taskNewDropdownEntry(IRefreshable owner, int type)
{
InitializeComponent();
this._owner = owner;
}
better option, use child form events like Closed to implement refreshing logic in parent. You just need to register event handler before showing the form and voila. Check examples here:
https://msdn.microsoft.com/en-us/library/system.windows.forms.form.closed(v=vs.110).aspx
You can also implement your own public form event for more custom usage (ex. DataChanged, ResultGenerated).
I am new to windows application. with C# and .NET.
I want something like the image i have attach. when my popup gets open, i want the mdi parent page to be shadowed or disbaled. (like we do in web application or Jquery popup)
Is it possible to do? if yes how can i do that.
Please help.
You can Achive this by making use of the opacity property of the Windows.Form
For this create a new form, sets its opacity (for eg: .75) and show this over the parent for when ever you are showing a child window.
An Example is given Below
There are three windows used here
1. ParentForm
2. OverlayForm
3. ChildForm
1. Parent Form
1. Create an instance of the Child form
2. Create an Instance of the Overlayform, Pass the objects Instances of Child and Parent(current form) as a parameter to the Constructor
3. Then Show the OverLay Form by using ShowDialog Method.
Code:
public partial class ParentForm : Form
{
public ParentForm()
{
InitializeComponent();
}
private void ParentForm_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
ChildForm child1 = new ChildForm();
// Create a new form.
OverlayForm form2 = new OverlayForm(this, child1);
child1.OverLay = form2;
// Display the form as a modal dialog box.
form2.ShowDialog(this);
}
}
2. Overlay Form
1. In the constructor store the childForm and ParentForm object in a local variables.
And Set the The properties (like width,height) to the Overlay Window
2. In the OverlayForm_Load show the ChildForm window.
public partial class OverlayForm : Form
{
public Form ParentForm { get; set; }
public Form child { get; set; }
public OverlayForm(Form parent, Form child)
{
InitializeComponent();
this.child = child;
this.ParentForm = parent;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.ShowInTaskbar = false;
this.Width = ParentForm.Width;
this.Height = ParentForm.Height;
this.Top = ParentForm.Top;
this.Left = ParentForm.Left;
this.StartPosition = ParentForm.StartPosition;
// Set the opacity to 75%.
this.Opacity = .75;
}
private void OverlayForm_Load(object sender, EventArgs e)
{
child.Show();
child.TopMost = true;
child.Focus();
child.BringToFront();
}
}
This will give the parent form a blur look. We should also write some code to close the overlay in the Child Form
3. Child Form
1. Set the object of the Overlay to a property in Child Window
2. And in the Form_Closing event of the child window, close the Overlay window.
public partial class ChildForm : Form
{
//This is set in the Parent form where the child form instatce is created
public Form OverLay { get; set; }
public ChildForm()
{
InitializeComponent();
}
private void ChildForm_Load(object sender, EventArgs e)
{
}
private void ChildForm_FormClosing(object sender, FormClosingEventArgs e)
{
this.OverLay.Close();
}
}
With Microsoft Windows there isn't really a concept of child windows. Pop-ups, or modal / modeless dialogues are just like any other windows in that they can be positioned anywhere on screen, so can be outside of the bounds of what you are thinking of as the parent window.
There are some web concepts that just do not work well on the desktop!
it works fine for me.
But after open child fucus should be on child form first button.
I have found most elegant solution on this link, it even has animation (although, I removed that part for my purpose). Author is "TommyCarlier", here is definition:
class FadingOverlayForm : Form
{
readonly double fFinalOpacity;
public FadingOverlayForm(Form owner, double finalOpacity)
{
StartPosition = FormStartPosition.Manual;
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
Owner = owner;
BackColor = Color.FromArgb(235, 245, 255); // or pick your own color
fFinalOpacity = finalOpacity;
if (fFinalOpacity < 0.01) fFinalOpacity = 0.01;
else if (fFinalOpacity > 1.0) fFinalOpacity = 1.0;
}
public void FadeIn(TimeSpan duration)
{
Opacity = 0.01;
Rectangle lWorkingArea = CalculateTotalScreenBounds();
Bounds = new Rectangle(lWorkingArea.X - 150, lWorkingArea.Y - 150, 100, 100);
Show();
Bounds = new Rectangle(Owner.PointToScreen(Point.Empty), Owner.ClientSize);
Animator.Animate(this, "Opacity", 0.01, fFinalOpacity, duration);
}
public void FadeOut(TimeSpan duration)
{
Animator.Animate(this, "Opacity", Opacity, 0, duration, EndFadeOut);
}
void EndFadeOut()
{
Form lOwner = Owner;
Dispose();
if (lOwner != null && !lOwner.IsDisposed)
ActivateFirstOwnedForm(lOwner);
}
static void ActivateFirstOwnedForm(Form form)
{
foreach(Form lOwnedForm in form.OwnedForms)
if (!lOwnedForm.IsDisposed)
{
ActivateFirstOwnedForm(lOwnedForm);
return;
}
form.Activate();
}
static Rectangle CalculateTotalScreenBounds()
{
Rectangle lBounds = Rectangle.Empty;
foreach(Screen lScreen in Screen.AllScreens)
lBounds = Rectangle.Union(lBounds, lScreen.Bounds);
return lBounds;
}
}
And here is how to use it:
DialogResult ShowMyDialog(Form owner)
{
using(MyDialog lDialog = new MyDialog())
{
FadingOverlayForm lOverlay = new FadingOverlayForm(owner, 0.6);
lDialog.Owner = lOverlay;
lOverlay.FadeIn(TimeSpan.FromSeconds(0.7));
DialogResult lResult = lDialog.ShowDialog(lOverlay);
lOverlay.FadeOut(TimeSpan.FromSeconds(0.1));
return lResult;
}
}
I want to close a window form that is hosting a WPF user control. Something like this as used while closing a current form in window application. But for WPF application I am not able to get reference to user controls parent
How to get Form which is hosting this control so that I can close my form
this.Close()
Add to your WpfControl property
public Form FormsWindow { get; set; }
In your WinForm add event handler for ElementHost's event ChildChanged:
using System.Windows.Forms.Integration;
public MyForm() {
InitializeComponent();
elementHost.ChildChanged += ElementHost_ChildChanged;
}
void ElementHost_ChildChanged(object sender, ChildChangedEventArgs e) {
var ctr = (elementHost.Child as UserControl1);
if (ctr != null)
ctr.FormsWindow = this;
}
After that you can use the FormsWindow property of your WpfControl to manipulate window. Example:
this.FormsWindow.Close();
An alternative solution could be,
Window parent = Window.GetWindow(this);
parent.Close();
Just want to add to #The_Smallest's otherwise very clear answer.
If you just copy and past the event handler code, you will still need to set your Forms's ChildChanged event to ElementHost_ChildChanged. I missed that step and spent 30 minutes trying to figure out why FormsWindow was null.
In order to call the Form object of the MyControl class already. We have in it a Form field to which we pass an instance object open Form. Having an assigned object we can freely manipulate it (including also call the function form.Close ();
WPF Control (with XAML):
public class MyControl : UserControl
{
public Form form = null;
public MyControl()
{
InitializeComponent();
this.PreviewKeyDown += new KeyEventHandler(HandleEsc);
}
private void HandleEsc(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
form.Close();
}
}
}
Form:
public class MainForm
{
//...
public Form form = null;
public MainForm(MyControl myControl)
{
InitializeComponent();
//...
myControl.form = (Form)this;
}
}
I'd like to know what's the best way (read most elegant) to have a single instance of a given Window per application in WPF.
I'm a newcomer to .NET and WPF and what I came up with looks pretty lame.
private static readonly Object MUTEX = new Object();
private static AboutWindow INSTANCE;
public static AboutWindow GetOrCreate() {
lock (MUTEX) {
if (INSTANCE == null) {
INSTANCE = new AboutWindow();
}
INSTANCE.Show();
return INSTANCE;
}
}
private AboutWindow() {
InitializeComponent();
}
private void AboutWindow_Closed(object sender, EventArgs e) {
// the Closed events are handy for me to update values across
// different windows.
lock (MUTEX) {
INSTANCE = null;
}
}
Thing is... this looks like utter crap. There must be some way to achieve the same goal in a much more elegant way, right?
PS: I'm often using the Closed event to change values in other open windows. For instance I have the SettingsWindow with the "Account" button. When I push that button, the AccountWindow pops up. When I close AcountWindow, I want something in the SettingsWindow to change (a label). Hence the constant creation of windows.
Besides, Close is something you always have to deal with because of the X button on the window frame...
there are probably better ways to do this, but here is a relatively simple way....
put a static bool on your window class to flag if its open or not. then, in the load() event set it to true, and on the close event set it to false. Then, in the code that opens the window, check the flag.
here is some pseudo-code to give you an idea...
public class AboutWindow
{
public static bool IsOpen {get;private set;}
onLoadEvent(....)
{
IsOpen = true;
}
onUnloadEvent(...)
{
IsOpen = false;
}
}
public void OpenAbout()
{
if ( AboutWindow.IsOpen ) return;
AboutWindow win = new AboutWindow();
win.Show();
}
If you truly need to enforce a single instance of a window, then a static instance (some flavor of what you have) with a factory creation method is certainly a viable option, much like a single DataContext instance when working with a database.
You could also write your own WindowManager class, although that seems like overkill, and will essentially be the same thing (except the Factory methods would be in a single class).
However, re-reading your post, I wonder if this is a case of missing the forest for the trees. Your mentioning of your SettingsWindow, which in turn calls AccountWindow, makes me think that you should simply be using ShowDialog(). This opens a window modally, meaning that there can be no interaction with the calling window (or any other window in your application). You simply set a property in that dialog, set the DialogResult to true when the OK button is pressed, and read that property in the parent window.
Basically, you just use the ShowDialog like this. I am leaving out a lot of the implementation details, as far as binding vs. hard-coding to controls. Those details aren't as important as just seeing how ShowDialog works.
For simplicity, assume that you have a class called MyAppOptions that, well, reflect the options of your application. I will leave off most of the implementation details of this for simplicity, but it would likely implement INotifyPropertyChanged, have methods and fields and properties, etc.
public class MyAppOptions
{
public MyAppOptions()
{
}
public Boolean MyBooleanOption
{
get;
set;
}
public String MyStringOption
{
get;
set;
}
}
Then, let's make this simple, and assume that you want to show an Options dialog when you press a button on some window. Furthermore, I will assume that there are variables that have been set with your options, which were loaded at startup.
void btnOptions_Click(object sender, RoutedEventArgs e)
{
MyAppOptions options = new MyAppOptions();
options.MyBooleanOption = mSomeBoolean;
options.MyStringOption = mSomeString;
OptionsDialog optionsDialog = new optionsDialog(options);
if (optionsDialog.ShowDialog() == true)
{
// Assume this function saves the options to storage
// and updates the application (binding) appropriately
SetAndSaveOptions(optionsDialog.AppOptions);
}
}
Now assume that the OptionsDialog is a window you've created in your project, and it has a CheckBox on it related to MyBooleanOption and a TextBox for MyStringOption. It also has an Ok button and a Cancel button. The code-behind will likely use Binding, but for now we'll hard code the values.
public class OptionsDialog : Window
{
public OptionsDialog(MyAppOptions options)
{
chkBooleanOption.IsChecked = options.SomeBooleanOption;
txtStringOption.Text = options.SomeStringOption;
btnOK.Click += new RoutedEventHandler(btnOK_Click);
btnCancel.Click += new RoutedEventHandler(btnCancel_Click);
}
public MyAppOptions AppOptions
{
get;
set;
}
void btnOK_Click(object sender, RoutedEventArgs e)
{
this.AppOptions.SomeBooleanOption = (Boolean) chkBooleanOption.IsChecked;
this.AppOptions.SomeStringOption = txtStringOption.Text;
// this is the key step - it will close the dialog and return
// true to ShowDialog
this.DialogResult = true;
}
void btnClose_Click(object sender, RoutedEventArgs e)
{
// this will close the dialog and return false to ShowDialog
// Note that pressing the X button will also return false to ShowDialog
this.DialogResult = false;
}
}
This is a pretty basic example as far as implementation details. Search online for ShowDialog for more details. The important keys to remember are:
ShowDialog opens a window modally,
meaning it is the only window in your
application that can be interacted
with.
Setting DialogResult to true
will close the dialog, which can be
checked for from the calling parent.
Setting DialogResult to false will
also close the dialog, in which case
you skip updating the values in the
calling window.
Pressing the X button
on the window automatically sets the
DialogResult to false
You can have public properties in the dialog window that can be set before doing the ShowDialog, and can get values from after the dialog disappears. It will be available while the dialog is still in scope.
The following extends on the above solution to reshow the window if it is already open. In this case it is a help window.
///<summary>
/// Show help from the resources for a particular control by contextGUID
///</summary>
///<param name="contextGUID"></param>
private void ShowApplicationHelp(string contextGUID = "1")
{
if (HelpWin != null)
{
if (HelpWin.IsOpen)
{
HelpWin.BringToFront();
return;
}
}
HelpWin = new MigratorHelpWindow();
HelpWin.Owner = Application.Current.MainWindow;
HelpWin.ResizeMode = ResizeMode.CanResizeWithGrip;
HelpWin.Icon = new Image()
{
Source =
new BitmapImage(
new Uri(
"pack://application:,,,/ResourceLibrary;component/Resources/Images/Menu/Help.png",
UriKind.RelativeOrAbsolute))
};
HelpWin.Show();
HelpWin.BringToFront();
}
This code is all in a viewmodel (MVVM) associated with the window. It is called by an ICommand hooked to a button on the window (naturally, it shows a question mark!!)
The following property is involved (in this case it is a Telerik RadWindow but it can be any window object, and you can probably also just store the window handle but using this property permits manipulation of the object more smoothly e.g. HelpWin.BringToFront() as in the above example...
...
...
private Telerik.Windows.Controls.RadWindow **HelpWin**
{
get;
set;
}
...
...
In the window itself (WPF window)
///<summary>
/// Flag to indicate the window is open - use to prevent opening this particular help window multiple times...
///</summary>
public static bool IsOpen { get; private set; }
...
...
...
private void HelpWindowLoaded(object sender, RoutedEventArgs e)
{
IsOpen = true;
}
private void HelpWindowUnloaded(object sender, RoutedEventArgs e)
{
IsOpen = false;
}
and in the view Xaml
...
...
DataContext="{Binding Path=OnlineHelpViewModelStatic,Source={StaticResource Locator}}"
RestoreMinimizedLocation="True"
**Loaded="HelpWindowLoaded" Unloaded="HelpWindowUnloaded"** >
Here's an alternative approach that doesn't require a static property to set and update in each of your window:
public static bool IsWindowInstantiated<T>() where T : Window
{
var windows = Application.Current.Windows.Cast<Window>();
var any = windows.Any(s => s is T);
return any;
}
Usage:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if (IsWindowInstantiated<SettingsWindow>())
return;
var window = new SettingsWindow();
window.Show();
}
How about using a Singleton?
public class MyWindow : Window {
private static MyWindow instance;
public static MyWindow Instance
{
get
{
if (instance == null)
{
instance = new MyWindow();
}
return instance;
}
}
}
Then just use
MyWindow.Instance.Show() and MyWindow.Instance.Hide()
I found this because I am trying to ensure my users do not open multiple instances of an rtsp stream window. I like Aybe's answer, it works well and is easy to understand.
I have built on it a bit as I wanted to bring the window into focus if it is open.
Here is my code:
public static void OpenWindow<T>() where T: Window
{
var windows = System.Windows.Application.Current.Windows.Cast<Window>();
var any = windows.Any(s => s is T);
if (any)
{
var win = windows.Where(s => s is T).ToList()[0];
if (win.WindowState == WindowState.Minimized)
win.WindowState = WindowState.Normal;
win.Focus();
}
else
{
var win = (Window)Activator.CreateInstance(typeof(T));
win.Show();
}
}
I am also quite new to C# and WPF so I am sure this can be improved even more.
Call it using
OpenWindow<SettingsWindow>();
public static void ShowWindow<T>() where T : Window, new()
{
var existingWindow = Application.Current.Windows.OfType<T>()
.SingleOrDefault();
if (existingWindow == null)
{
new T().Show();
return;
}
existingWindow.WindowState = WindowState.Normal;
existingWindow.Activate();
}
Usage:
ShowWindow<AboutWindow>();
When windows is created then Window.IsLoaded == true. My implementation of singleton windows is:
public partial class MySingletonWindow : Window
{
private static MySingletonWindow _instance = null;
private MySingletonWindow()
{
InitializeComponent();
}
public static MySingletonWindow Show(System.Windows.Window owner = null)
{
// On First call _instance will be null, on subsequent calls _instance will not be null but IsLoaded is false if windows was closed.
if (_instance == null || !_instance.IsLoaded)
_instance = new MySingletonWindow();
_instance.Owner = owner; // Optional owner
_instance.Show(); // Display the window
_instance.Focus(); // Bring it to front
return _instance; // Return instance if user needs it
}
}
Simply show windows using this call:
MySingletonWindow.Show(ParentWindow);
OR
MySingletonWindow.Show();