I have a one-window WPF application (Win8.1 / .net4.7), the Window.Closing-Event is unhandled, the Window.Closed-Event is handled as follows:
private void Window_Closed(object sender, EventArgs e)
{
Properties.Settings.Default.WinMainLocationX = this.Left; // ok
Properties.Settings.Default.WinMainLocationY = this.Top; // ok
Properties.Settings.Default.WinMain_size = new Size(this.Width, this.Height); // crucial setting
Properties.Settings.Default.WinMain_state = this.WindowState; // ok
Properties.Settings.Default.Save();
}
I'm closing the app (at this point always in idle state) once a day by a batch file containing C:\WINDOWS\system32\shutdown.exe /s /t 20 and nothing afterwards. By this the computer shuts down properly. The parameters of shutdown.exe can be seen by command line input of shutdown /?.
Problem: Every 7 or 8 days the window size gets corrupted in a way that the application (after having started in the morning) looks like this:
How can I protect my application settings from interference by shutdown.exe?
I think the problem is storing the settings while the application window is minimized. Width and Height of the window will be 0 in this case.
You can use the RestoreBounds property of your window to get its restored size independent of its current state:
Properties.Settings.Default.WinMainLocationX = this.RestoreBounds.Left;
Properties.Settings.Default.WinMainLocationY = this.RestoreBounds.Top;
Properties.Settings.Default.WinMain_size = new Size(this.RestoreBounds.Width, this.RestoreBounds.Height);
Properties.Settings.Default.WinMain_state = this.WindowState;
Some answers to this question show another approach using the WinAPI functions GetWindowPlacement / SetWindowPlacement:
.NET WPF Remember window size between sessions
Adding Environment.Exit(0)has solved the issue. I can imagine the cause of the problem was that the Window.Closed-Handler has been reached twice.
private void Window_Closed(object sender, EventArgs e)
{
Properties.Settings.Default.WinMainLocationX = this.Left; // ok
Properties.Settings.Default.WinMainLocationY = this.Top; // ok
Properties.Settings.Default.WinMain_size = new Size(this.Width, this.Height); // crucial setting
Properties.Settings.Default.WinMain_state = this.WindowState; // ok
Properties.Settings.Default.Save();
Environment.Exit(0);
}
Related
I am doing an image processing project using Windows Forms (c#). You can see the design of my application below.
What does this app do : take the original image, create a copy and modify the copy.
My app is working well but, if I process the same original image another time without closing the app, I get an error due to (I think) the display of the modified image. I think that the display on the bottom right corner uses the resources of the image and, when I try to modify it again, the system considers that the image is already used by another program so it can't be modified.
So my question is : "How can I stop using the modified image if the user clicks on PROCESS again ?"
I tried to use the .Dispose() method but it didn't work.
Code of the c# function linked to the PROCESS button :
private async void button8_Click(object sender, EventArgs e)
{
// start the waiting animation
progressBar1.Visible = true;
progressBar1.Style = ProgressBarStyle.Marquee;
if (csI != csP)
{
MessageBox.Show("The selected profil does not match the selected image. Colorspaces are different.", "WARNING",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
pictureBox2.Image = null;
if (checkBox2.Checked == false)
{
rendered = false;
button8.Enabled = false;
await Task.Run(() => wrapper.DominantColors(trackBar1.Value, rendered));
//wrapper.DominantColors(trackBar1.Value, rendered);
}
else
{
rendering = comboBox1.Text;
string outputImage = wrapper.Link(rendering, bpc);
rendered = true;
button8.Enabled = false;
await Task.Run(() => wrapper.DominantColors(trackBar1.Value, rendered));
//wrapper.DominantColors(trackBar1.Value, rendered);
}
// re-enable things
button8.Enabled = true;
progressBar1.Visible = false;
MessageBox.Show("processing done");
Bitmap bit = new Bitmap(imgDstPath);
float WidthImg = bit.Width;
float HeightImg = bit.Height;
float alpha = WidthImg / pictureBox2.Width;
float beta = HeightImg / pictureBox2.Height;
alpha = Math.Max(alpha, beta);
float newWidthf = WidthImg / alpha;
float newHeightf = HeightImg / alpha;
int newHeight = (int)newHeightf;
int newWidth = (int)newWidthf;
pictureBox2.ClientSize = new Size(newWidth, newHeight);
pictureBox2.Image = bit;
pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
}
}
If possible, I'd like to clear the use of the resources when I click on the process button.
Thank you in advance for your help
The basic rule is that all objects you create that implements IDisposable need to be disposed. When writing winforms apps all controls added to a forms are disposed when the form is disposed. But whenever you change things you might need to handle disposal yourself.
For example:
pictureBox2.Image = bit;
If pictureBox2.Image is already set to something you need to ensure that it is disposed.
var oldImage = pictureBox2.Image;
pictureBox2.Image = bit;
oldImage.Dispose();
I'm not sure this is the actual problem you are having, your example code is insufficient to make that determination. To discover this you need to debug your program! Start by examining your exceptions, does it fail when opening a file or some other resource? Where was that resource created? where is it disposed? Perhaps even use a memory debugger to produce a list of all objects that are alive to see if there are any suspicious objects kept around. Will disposal correctly occur if any arbitrary code throws an exception?
It is sometimes useful to check the identity of objects in the debugger, to see if it has been switched out, or see what object your breakpoint was triggered in. You can rightclick an object in the watch panel in visual studio and select "Make ObjectId", this will associate a number with the object that appears at the end of the value.
If anyone in the future wants to know the solution I found, here it is :
At the beginning of the PROCESS function I added those simple lines :
if (pictureBox2.Image != null)
{
pictureBox2.Image.Dispose();
pictureBox2.Image = null;}
I am trying to print from a web browser control in a winform application.The matter is it sets letter as default paper size but I need A4. Also it automatically sets some margins wrong, I can set them to correct settings manually but I want to do it programmatically.
How is it possible?
Here is my code to print.
private void metroButton1_Click(object sender, EventArgs e)
{
loadprintData();
// Create a WebBrowser instance.
WebBrowser webBrowserForPrinting = new WebBrowser();
// Add an event handler that prints the document after it loads.
wa.DocumentCompleted +=
new WebBrowserDocumentCompletedEventHandler(ShowPrintDocument);
wa.ShowPrintPreviewDialog();
reloadpage();
}
private void ShowPrintDocument(object sender,WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).ShowPrintPreviewDialog();
// Dispose the WebBrowser now that the task is complete.
// ((WebBrowser)sender).Dispose();
reloadpage();
}
private void PrintDocument(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Print the document now that it is fully loaded.
((WebBrowser)sender).Print();
// Dispose the WebBrowser now that the task is complete.
// ((WebBrowser)sender).Dispose();
}
To change the Margin size you have to edit the (HKCU) registry before printing:
string pageSetupKey = "Software\\Microsoft\\Internet Explorer\\PageSetup";
bool isWritable = true;
RegistryKey rKey = Registry.CurrentUser.OpenSubKey(pageSetupKey, isWritable);
if (stringToPrint.Contains("something"))
{
rKey.SetValue("margin_bottom", 0.10);
rKey.SetValue("margin_top", 0.25);
}
else
{
//Reset old value
rKey.SetValue("margin_bottom", 0.75);
rKey.SetValue("margin_top", 0.75);
}
Dont forget to set it back to the default.
Ref Microsoft KB Article
To change the Paper size you have to edit the (HKCU) registry in another place before printing:
string pageSetupKey2 = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
isWritable = true;
rKey = Registry.CurrentUser.OpenSubKey(pageSetupKey2, isWritable);
// Use 1 for Portrait and 2 for Landccape
rKey.SetValue("PageOrientation", 2, RegistryValueKind.DWord);
// Specifies paper size. Valid settings are 1=letter, 5=Legal, 9=A4, 13=B5.Default setting is 1.
rKey.SetValue("PaperSize", 9, RegistryValueKind.DWord);
// Specifies print quality
rKey.SetValue("PrintQuality ", 1, RegistryValueKind.DWord);
Ref MSDN
Well i have tried so many things but at the end i found that it is not possible to program the printer setting from the code easily. but i could do the margin by the answer of #jeremy.
And i found out that For printing from WebBrowser control it uses internet explorer all we know but at the beginning it was using explorer 7 and i had to change it to explorer 11 as default.
Then i saw it explorer does not have his own print settings. it uses the default printers settings.
So you have to change the Default printers previews.You will see the preview will show that way.
See my code please :
private void Button_Click(object sender, RoutedEventArgs e)
{
WrapPanel wp=new WrapPanel ();
this.Content = wp;
for (int i = 0; i < 10; i++)
{
MediaElement video = new MediaElement(); video.Width = video.Height = 200;
video.Source = new Uri("E:\\testVideo.avi");
wp.Children.Add(video);
}
}
It takes a few seconds to display the videos when this code start.
At this time, If you close the program, all videos remains in the memory. (can even hear their voices)
Q: 1- why?
Q: 2- How to prevent it?
I'm guessing your application is still running even though the main window is closed. Since the MediaElements are still initializing and playing it is probably keeping your application open. In order to kill your application when the main window is closed, listen the Window.Closed event and shutdown the application by calling:
Application.Current.Shutdown();
I have a small, simple C# application which updates an icon in the system tray. I use it to graphically show the CPU usage. The application works great. I keep the Window hidden and don't show it in the taskbar so it doesn't get in the way.
My issue is that it will run great for a while. Often several hours. But then it will mysteriously quit. No warnings. Nothing. The icon is just gone and the program is no longer running. I have tested the program in the debugger under varying conditions, so I don't think that is it. Is there something obvious I am missing? If the program encounters an error and quits should I be expecting a message if the Form is hidden? Is there some "keep-alive" message or something that I need to handle?
Here is the relevant section of code:
public Form1()
{
InitializeComponent();
trayIcon = new NotifyIcon();
trayIcon.Text = "CPU Utilization";
trayIcon.Icon = new Icon(SystemIcons.Application, 40, 40);
trayIcon.Visible = true;
update = new Thread(new ThreadStart(UpdateCPU));
update.Start();
}
protected override void OnLoad(EventArgs e)
{
Visible = false;
ShowInTaskbar = false;
base.OnLoad(e);
}
private void UpdateCPU()
{
Bitmap bm = new Bitmap(32, 32);
Graphics g = Graphics.FromImage(bm);
while (true)
{
g.FillRectangle(new SolidBrush(c3), 17, 17, 15, 15);
trayIcon.Icon = System.Drawing.Icon.FromHandle(bm.GetHicon());
Thread.Sleep(1000);
}
}
Any help would be greatly appreciated!
I would suggest you add an Unhandled Exception Handler
Global Exception Handling for winforms control
An Exception is likely being thrown, causing your program to exit.
Then, introduce logging to log what the Exception was. Personally I prefer NLog.
I'm a bit surprised that you can update trayIcon from a non-UI thread without receiving a cross-thread exception.
The documentation seems to agree with Viktor Latypov's comment, you should be doing something like this:
Icon newIcon = Icon.FromHandle(bm.GetHicon());
trayIcon.Icon = newIcon;
DestroyIcon(newIcon.Handle);
I have a NotifyIcon in my program which displays a baloon tip in the taskbar. I wrote code as
notifyIcon1.Icon = new Icon(SystemIcons.Application, 40, 40);
notifyIcon1.Visible = true;
notifyIcon1.Text = "Test Notify Icon Demo";
notifyIcon1.BalloonTipText =count+ " Alerts";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.BalloonTipTitle = "Alert!";
notifyIcon1.ShowBalloonTip(999999999);
The baloon tip is invisible after the set time (999999999). But I want to show the baloon tip until it is clicked as I have baloontipclicked event.
How to make baloontip visible forever?
from MSDN:
Minimum and maximum timeout values are enforced by the operating
system and are typically 10 and 30 seconds, respectively, however this
can vary depending on the operating system. Timeout values that are
too large or too small are adjusted to the appropriate minimum or
maximum value. In addition, if the user does not appear to be using
the computer (no keyboard or mouse events are occurring) then the
system does not count this time towards the timeout.
it seems not be possible to override the maximum timeout (eventually adjusted by Windows and limited to 30 seconds even if you specify a longer one) so the Notification will fade away, will not wait for you to click on it after 2 minutes.
if you want to really have a different behavior you should probably use something else, other objects or simulate something similar with forms where you have the full control on the behavior and you can show, hide and close as you wish from your code.
You can show it again if it hasn't been clicked.
You have the close event (BalloonTipClosed), if user hasn't ckicked it just show it again.
private void ShowBalloonTip(int minutes) {
notifyIcon.BalloonTipIcon = ToolTipIcon.Error;
notifyIcon.BalloonTipText = "Text";
notifyIcon.BalloonTipTitle = "Title";
notifyIcon.ShowBalloonTip(minutes* 60 * 1000);
m_showUntil = DateTime.Now.AddMinutes(minutes);
}
private void notifyIcon_BalloonTipClosed(object sender, EventArgs e) {
if (m_showUntil > DateTime.Now)
notifyIcon.ShowBalloonTip(60 * 1000);
}
private void notifyIcon_BalloonTipClicked(object sender, EventArgs e) {
m_showUntil = DateTime.MinValue;
(..)
}