Open Window from Button without creating new windowFoo instances - c#

The problem with this is that each time you move between Windows you are creating a new object instance and adding to the memory heap (process memory, not entirely sure please correct if wrong term!). This is wasteful and poor taste in my opinion, and I'm wondering if there is another solution out there for this since I'm sure someone has thought about it before. I don't like the Pages, the navigation buttons look too much like IE in Windows 7 for a desktop application.
I have seen the solutions like this (i realize I'm not using good naming conventions, but I'm just tinkering with WPF for fun):
public GoogleAPI()
{
InitializeComponent();
Closing += GoogleAPI_Closing;
}
private void GoogleAPI_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
MainWindow main = new MainWindow();
main.Show();
}
This works with MainWindow creating a new GoogleAPI (my window name) instance in MainWindow in a button event.
private void Button1_Click(object sender, RoutedEventArgs e)
{
GoogleAPI googleapi = new GoogleAPI();
googleapi.Show();
this.Hide();
}

isn't it obvious to declare the Window instance in class level ?
public class Abc()
{
MainWindow mw = new MainWindow();
///GoogleApi gp = new GoogleApi
private void Show()
{
mw.Show();
//gp.Show();
}
However , the above code won't work if the window is the mainwindow , rather try this :
Application.Current.MainWindow.Show();

Another thing I found that is a better solution, for some forms, is to use the ShowDialog method rather than showing/hiding forms.

Related

What is the previous window called in WPF

I know the current window can be used with "this" but is there anything I can use to call the previous window?
For example I have this code going off when I press a button
Buyer_Login BuyerWindow = new Buyer_Login();
Visibility= Visibility.Hidden;
BuyerWindow.Show();
I need to be able to go back to the first window and I need to close the BuyerWindow and I was going to do it with this.Close();
What can I do to make the first window's visibility visible again?
You could handle the Window.Closed event:
MainWindow.xaml.cs
private void OnClick(object sender, EventArgs e)
{
var loginWindow = new BuyerLogin();
loginWindow.Closed += OnBuyerLoginWindowClosed;
this.Visibility = Visibility.Hidden;
loginWindow.Show();
}
private void OnBuyerLoginWindowClosed(object sender, EventArgs e)
=> this.Visibility = Visibility.Visible;
You should consider to show the login window from the App.xaml.cs before you show your main window (recommended):
App.xaml.cs
private async void App_OnStartup(object sender, StartupEventArgs e)
{
var loginWindow = new BuyerLogin();
bool? dialogResult = loginWindow.ShowDialog();
if (dialogResult.GetValueOrDefault())
{
var mainWindow = new MainWindow();
mainWindow.Show();
}
}
App.xaml
<Application Startup="App_OnStartup">
<Application.Resources>
</Application.Resources>
</Application>
There is a collection of open windows.
App.Current.Windows;
It depends on exactly what you're doing opening windows.
If you start up then mainwindow will be [0] in that collection.
Say you then open an instance of window1.
That in turn opens an instance of window2.
There is a bit of a complication if you f5 in visual studio because it opens adorner windows.
Setting that aside for a moment.
When I write code to do what I describe above.
In Window2 I handle content rendered:
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
var wins = App.Current.Windows;
wins[1].Close();
}
}
That instance of Window1 is closed.
Your new window is very likely the last window in that zero based collection and the previous one the window before that.
You could perhaps search the collection and find index for "this" and subtract one if you're doing more complicated things.
The chances are though, you want to close the window indexed by the count of that collection minus 2. Because it's zero based.
With my exploratory code, window1 closes with this:
private void Window_ContentRendered(object sender, EventArgs e)
{
var wins = App.Current.Windows;
wins[wins.Count - 2].Close();
}
Personally, I prefer single window apps and switch out the content in part of mainwindow. Leaving navigation buttons etc static in mainwindow.
If you're effectively opening one other window and closing the previous to do things then maybe you could consider a single window app instead.

bringing a windows form, form to the front without minimising other windows

Hi I'm relatively new to C# and completely new to windows form and basically trying to create a subliminal messaging program that at timed intervals will quickly display a message for it to then be hidden again.
I've managed to by looking through various other posts created another form that will pop up and then hide very quickly using
msgObject.Activate();
that brings the form to the front. However it is stopping me from being able to type when I'm working and I basically wanting to know if it is possible to make some kind of message or form appear at the front of all my other programs without it interrupting my current work or opening or closing of other windows and tasks if that makes sense. As currently it brings the form to the front of everything but will also stop me from being able to type etc.
I'm not sure if this is possible with my current method of using a form but if there is a way of achieving the result I'm after I'd be very grateful to find out
Thanks.
Here is more of my code to clarify
public partial class FormHomePage : Form
{
private bool startSubliminal = false;
msg msgObject = new msg();
List<string> subliminalMessages = new List<string>();
public FormHomePage()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
if (startSubliminal)
{
msgObject.Show();
msgObject.BringToFront();
msgObject.Activate();
}
}
private void button1_Click(object sender, EventArgs e)
{
subliminalMessages.Add(txtBox1.Text);
msgObject.LabelText = txtBox1.Text;
txtBox1.Text = string.Empty;
startSubliminal = true;
msgObject.Show();
msgObject.BringToFront();
}
private void timer2_Tick(object sender, EventArgs e)
{
msgObject.Hide();
}
}
How are you showing the second form (the message form) in the first place? You're probably using .Show() (right?), which will make the form "steal" the focus anyway. The same applies to .Activate() and .BringToFront().
Instead, what you can do is to show the message form and make sure it stays on top the current form, and then activate the current/main form once again.
Something like this should work:
var frm = new YourMsgForm();
frm.Show(this);
this.Activate();
Here's a demonstration:
Note that I used .Show(this) instead of .Show(), that's in order to set the current form as the Owner of the new one, that way we guarantee that the new form will stay on top of the current one. This is equivalent to calling frm.Owner = this; then frm.Show();.
Another way to make sure the form stays on top is by setting the TopMost property instead of the Owner property. However, doing so will make the new form on top of the other windows as well (not just your application).

C# Accessing dotnetBrowser from a UserControl

So essentially I'm using the dotNetBrowser for a project that i'm loading into a panel on my main form, and I have a button in a usercontrol for user input so it can interact with the browser. Here's what I have:
public partial class Form1 : Form
{
public BrowserView browserView = new WinFormsBrowserView();
public Form1()
{
InitializeComponent();
this.panel1.Controls.Add((Control)browserView);
browserView.Browser.LoadURL("URL TO BE LOADED");
browserView.Browser.FinishLoadingFrameEvent += delegate (object sender, FinishLoadingEventArgs e)
{
if (e.IsMainFrame)
{
// Do stuff when loaded
} else return;
}
};
}
}
That works fine, in my usercontrol.cs I have:
public void button1_Click(object sender, EventArgs e)
{
BrowserView br = (this.Parent as Form1).Controls["browserView"] as BrowserView;
br.Browser.LoadURL("NEW URL");
}
So that when the button is clicked it can load a new url. But this is throwing a null exception.
Basically I need these two components to be able to pass information on to eachother. The method I've used worked fine for other Form1 controls, but not the browser it seems.
Any advice?
In your case, browserView is a name of the public variable, so you can simply use(this.Parent as Form1).browserView to access it.
Your are adding browserView to Form1.panel1, but trying to get it from (this.Parent as Form1).
You don't need to search for BrowserView when you have explicit reference to it. I suggest giving this reference to the user control. User control having the knowledge of the innards of the hosting form means that information is flowing in the wrong direction.
Names of controls are given to them by IDE, and are empty when controls are created in code.

How to bring MainWindow into view when closing a window?

I'm trying to bring my MainWindow into view when I close a specific window within the same application. I have tried to do this but with the code I have created it just creates a new instance of MainWindow and I end up having 2 MainWindows instead of a desired one. Here is the code below that I have got.
private void Weight_Click(object sender, RoutedEventArgs e)
{
try
{
MultipleConverters.Windows.Weight WeightCalculation = new Windows.Weight();
WeightCalculation.Show();
this.WindowState = WindowState.Minimized;
}
// This code above works fine and minimizes the mainwindow and brings into view the selected window.
private void Quit_Click(object sender, RoutedEventArgs e)
{
this.Close();
MainWindow bringIntoView = new MainWindow();
bringIntoView.Show();
}
// Now with this code above is the problem code. This code is within the new window and what Iam trying to achieve is when this window is closed the mainwindow will be brought back into scope rather than creating a new instance of it, and leaving me with 2 Mainwindows rather than the desired 1 Mainwindow. any help would be great.
Use the Owner property to store the reference to the main window, you can then use that property to bring the window back up.
private void Weight_Click(object sender, RoutedEventArgs e)
{
try
{
MultipleConverters.Windows.Weight WeightCalculation = new Windows.Weight();
WeightCalculation.Owner = this;
WeightCalculation.Show();
this.WindowState = WindowState.Minimized;
}
elsewhere
private void Quit_Click(object sender, RoutedEventArgs e)
{
this.Close();
Owner.WindowState = WindowState.Normal;
}
However based on the behavior you are showing you may want to look in to using ShowDialog() instead of minimizing the parent window and use that instead.
private void Weight_Click(object sender, RoutedEventArgs e)
{
try
{
MultipleConverters.Windows.Weight WeightCalculation = new Windows.Weight();
WeightCalculation.Owner = this;
WeightCalculation.ShowDialog(); //The code pauses here till the dialog is closed.
}
Application.Current.MainWindow.Activate();
There is a handy property Application.Current.MainWindow that you can use to access the main window declared in App.xaml, you should just be able to show it by calling:
Application.Current.MainWindow.Show();
Application.Current.MainWindow.Activate();
To simplify things, you could create a static method on your MainWindow which handles all this:
public static void TryReveal()
{
var mainWindow = Application.Current.MainWindow;
if (mainWindow == null)
{
// The main window has probably been closed.
// This will stop .Show() and .Activate()
// from throwing an exception if the window is closed.
return;
}
if (mainWindow.WindowState == WindowState.Minimized)
{
mainWindow.WindowState = WindowState.Normal;
}
// Reveals if hidden
mainWindow.Show();
// Brings to foreground
mainWindow.Activate();
}
And then your other windows can just call MainWindow.TryReveal(). That way your windows don't need any reference to the main window as the static method handles it.
The best way you could handle this in WPF though is (I think) using a messaging implementation (eg. MVVM Light's Messaging system, or Caliburn.Micro's EventAggregator). Your MainWindow would subscribe to a "MainWindowViewStateMessage" or something like that (defined by you) and your other windows would pass it through the messaging system. The main window would intercept it and do the necessary work.
private void Quit_Click(object sender, RoutedEventArgs e)
{
this.Close();
MainWindow bringIntoView = new MainWindow();
bringIntoView.Show();
}
You're creating a new instance of MainWindow and then showing it. This is why a new MainForm is shown.
One thing you can do is set a property on the WeightCalculation window like this:
public MainWindow _mainWindow { get; set; }
Before showing the WeightCaculation, set _mainWindow to your current instance of MainWindow :
MultipleConverters.Windows.Weight WeightCalculation = new Windows.Weight();
WeightCalculation._mainWindow = this;
WeightCalculation.Show();
this.WindowState = WindowState.Minimized;
and from the new form you can now interact with the MainWindow.

Freeing or clearing created objects

I have 2 windows forms; Form1.cs and Form2.cs.
Here are the code for Form1.cs in which will show the Form2.cs and Hide the the current Form1.cs
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
this.Hide();
}
Here are the code for Form2.cs in which will show the Form1.cs and Hide the the current Form2.cs
private void button1_Click(object sender, EventArgs e)
{
Form2 f2 = new Form2();
f2.Show();
this.Hide();
}
I have monitored the memory usage of the application and I have noticed that the memory usage of the application is increasing every time I execute the code above.
You're creating new forms on each button click, so you hold many instances in memory after clicking the buttons multiple times.
You're probably looking for this.Close() instead of this.Hide(), as the former will close and dispose the current form while the latter will only hide it.
If you want to hide and re-show the forms, you need to keep a reference to the forms. There are a lot of considerations (should a form be instantiated only once, or each time it is requested? Should it be possible for multiple instances of the same form be opened? And so on) and possible patterns and (third-party) solutions (e.g. Application Controller, What is a proper way of building Winform apps with multiple “screens”).
One solution would be to simply create your own form registry where each form has a singleton:
public static class FormRegistry
{
private static Lazy<Form1> _form1 = new Lazy<Form1>(() => new Form1());
public static Form1 Form1
{
get
{
return _form1.Value;
}
}
private static Lazy<Form2> _form2 = new Lazy<Form2>(() => new Form2());
public static Form2 Form2
{
get
{
return _form2.Value;
}
}
}
Then anywhere in code, you can just do FormRegistry.Form1.Show(). Please note this code is a proof of concept with many issues and much room for improvement, but it's there to give you the general idea.

Categories