Based on an Code Project article on Windows Forms User Settings by David Veeneman, I have been playing around with saving the start location and start size of an application.
It works perfectly in the single instance, but when I expand it to multiple instance I run into problems.
I've wrapped the section dealing with loading the setting and saving the settings in a mutex to protect writing to and from the settings file.
I would like the windows to stack from the last known location. This seems to work fine most of the time, but if I open up four or five windows in rapid sucession the first three will open perfectly, then there will be a gap, and after that some of them start to open at the same location.
Render the Form/Application:
private Mutex saveSetting;
private const int START_LOCATION_OFFSET = 20;
private void MainForm_Load(object sender, EventArgs e)
{
// Get the mutex before the reading of the location
// so that you can't have a situation where a window drawn
// in the incorrect position.
this.saveSetting = new Mutex(false, "SaveSetting");
this.saveSetting.WaitOne();
this.LoadWindowStartSizeAndLocation();
.
.
.
.
.
this.saveSetting.ReleaseMutex();
}
Loading the settings:
private void LoadWindowStartSizeAndLocation()
{
// Set window location
if (Settings.Default.WindowLocation != null)
{
System.Drawing.Point startLocation =
new System.Drawing.Point
(Settings.Default.WindowLocation.X + START_LOCATION_OFFSET,
Settings.Default.WindowLocation.Y + START_LOCATION_OFFSET);
this.Location = startLocation;
Settings.Default.WindowLocation = startLocation;
Settings.Default.Save();
}
// Set window size
if (Settings.Default.WindowSize != null)
{
this.Size = Settings.Default.WindowSize;
}
}
Saving the settings:
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
this.SaveWindowSizeAndLocationForNextStart();
}
catch (Exception ex)
{
System.Diagnostics.Debug.Assert(false, ex.Message);
}
}
/// <summary>
/// Save the Window Size And Location For the next Application Start up.
/// </summary>
private void SaveWindowSizeAndLocationForNextStart()
{
if (this.WindowState != FormWindowState.Minimized)
{
// Copy window location to app settings
Settings.Default.WindowLocation = this.Location;
Settings.Default.WindowSize = this.Size;
}
try
{
this.saveSetting = new Mutex(false, "SaveSetting");
this.saveSetting.WaitOne();
Settings.Default.Save();
}
catch
{
// Do nothing. It won't permanently disable the system if we
// can't save the settings.
}
finally
{
this.saveSetting.ReleaseMutex();
}
}
Can anyone tell me what I'm doing worng? Or how based on the code above could I get two instances rendered to the same start location??
Thanks
A
The problem is that settings are loaded before the mutex is acquired. Call Settings.Default.Reload() after acquiring the mutex.
Related
I have created AutoCAD plugins to measure a distance of line .Alongside i have created a windows form application that load the plugins i have created. I try to return the value measured using command in my AutoCAD plugins to the windows form application but all went in vain.Some of the way i do are:
I insert the result obtained in autocad and try to retrive that.
I try the interface technique.
You can store your distance in the USERR1 to USERR5 system variables, then read it with Document.GetVariable COM API from an external process.
You can install an handler on the EndCommand event to detect when your command is finished.
Here is some code:
using Autodesk.AutoCAD.Interop;
[..]
void button1_Click(object sender, EventArgs e)
{
const uint MK_E_UNAVAILABLE = 0x800401e3;
AcadApplication acad;
try
{
// Try to get a running instance of AutoCAD 2016
acad = (AcadApplication) Marshal.GetActiveObject("AutoCAD.Application.20.1");
}
catch (COMException ex) when ((uint) ex.ErrorCode == MK_E_UNAVAILABLE)
{
// AutoCAD is not running, we start it
acad = (AcadApplication) Activator.CreateInstance(Type.GetTypeFromProgID("AutoCAD.Application.20.1"));
}
activeDocument = acad.ActiveDocument;
activeDocument.EndCommand += ActiveDocument_EndCommand;
activeDocument.SendCommand("YOURCOMMAND ");
}
void ActiveDocument_EndCommand(string CommandName)
{
if (CommandName != "YOURCOMMAND") return;
try
{
double value = activeDocument.GetVariable("USERR1");
// Process the value
MessageBox.Show(value.ToString());
}
finally
{
// Remove the handler
activeDocument.EndCommand -= ActiveDocument_EndCommand;
}
}
I am trying to restart my application and run a command. For example, when the user clicks the language he wants it goes checked true and ignores the other one with checked = false. When that is done, the application restarts and checks what language the users checked after the restart and gets the language.
public Application()
{
InitializeComponent();
check_language();
languages();
}
private void lang_english_Click(object sender, EventArgs e)
{
// problem *******
Application.Restart();
// if i remove this is works ok.
// when app is restarted it is like starting it so i dont think
// this works at all. is there an other way to read this?
// maybe with a bool?
lang_english.Checked = true;
//Ignore
lang_portuguese.Checked = false;
MessageBox.Show("Language was set to English.\r\nCliente will now restart.", "Language", MessageBoxButtons.OK, MessageBoxIcon.Information);
check_language();
}
private void lang_portuguese_Click(object sender, EventArgs e)
{
lang_portuguese.Checked = true;
//Ignore
lang_english.Checked = false;
MessageBox.Show("Language was set to Portuguese.\r\nCliente will now restart.", "Language", MessageBoxButtons.OK, MessageBoxIcon.Information);
check_language();
}
private void languages()
{
//Languages
}
}
private void check_language()
{
if (lang_english.Checked == true)
{
languages(); //Get the languages
//Ignore
lang_portuguese.Checked = false;
}
else if (lang_portuguese.Checked == true)
{
languages(); //Get the languages
//Ignore
lang_english.Checked = false;
}
}
First I would save the selected language in the app.config file, the you can check the config on start-up and check the appropriate language.
Second for restarting the application I would use one of two options:
1) Application.Restart()
2) Start a second application and then end the first. See this post: Restart WinForms Application
You may also want to look into changing the language at run-time Change language at run-time
You are checking your language AFTER restarting the application inside the SAME application controls. You should write and read the language in a file so you can check it in there:
private void lang_portuguese_Click(object sender, EventArgs e)
{
new System.IO.StreamWriter(new System.IO.FileStream("File.ext", System.IO.FileMode.Create)).Write("Portuguese");
}
private void check_language()
{
String lang = new System.IO.StreamReader("YouFile.ext").ReadLine();
if (lang == "English")
{
languages(); //Get the languages
//Ignore
lang_portuguese.Checked = false;
}
else if (lang == "Portuguese")
{
languages(); //Get the languages
//Ignore
lang_english.Checked = false;
}
}
This are EXAMPLES. you should write and read with validation and creating instances of your stream, so you close it after finishing Reading/writting.
This is the idea I can give you.
I just updated my phone to WP8.1 and I created an update for my app yesterday and removed and added a few functions and suddenly one page doesn't work and throws a System.Reflection.TargetInvocationException.
App.xaml.cs:
using System;
using System.Diagnostics;
using System.Resources;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using Knowledge_Organizer.Resources;
namespace Knowledge_Organizer
{
public partial class App : Application
{
/// <summary>
/// Provides easy access to the root frame of the Phone Application.
/// </summary>
/// <returns>The root frame of the Phone Application.</returns>
public static PhoneApplicationFrame RootFrame { get; private set; }
/// <summary>
/// Constructor for the Application object.
/// </summary>
public App()
{
// Global handler for uncaught exceptions.
UnhandledException += Application_UnhandledException;
// Standard XAML initialization
InitializeComponent();
// Phone-specific initialization
InitializePhoneApplication();
// Language display initialization
InitializeLanguage();
// Show graphics profiling information while debugging.
if (Debugger.IsAttached)
{
// Display the current frame rate counters.
Application.Current.Host.Settings.EnableFrameRateCounter = true;
// Show the areas of the app that are being redrawn in each frame.
//Application.Current.Host.Settings.EnableRedrawRegions = true;
// Enable non-production analysis visualization mode,
// which shows areas of a page that are handed off to GPU with a colored overlay.
//Application.Current.Host.Settings.EnableCacheVisualization = true;
// Prevent the screen from turning off while under the debugger by disabling
// the application's idle detection.
// Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
// and consume battery power when the user is not using the phone.
PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
}
}
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
}
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
}
// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
}
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
}
// Code to execute if a navigation fails
private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
if (Debugger.IsAttached)
{
// A navigation has failed; break into the debugger
Debugger.Break();
}
}
// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
Debugger.Break();
}
}
#region Phone application initialization
// Avoid double-initialization
private bool phoneApplicationInitialized = false;
// Do not add any additional code to this method
private void InitializePhoneApplication()
{
if (phoneApplicationInitialized)
return;
// Create the frame but don't set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
RootFrame = new PhoneApplicationFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;
// Handle navigation failures
RootFrame.NavigationFailed += RootFrame_NavigationFailed;
// Handle reset requests for clearing the backstack
RootFrame.Navigated += CheckForResetNavigation;
// Ensure we don't initialize again
phoneApplicationInitialized = true;
}
// Do not add any additional code to this method
private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
{
// Set the root visual to allow the application to render
if (RootVisual != RootFrame)
RootVisual = RootFrame;
// Remove this handler since it is no longer needed
RootFrame.Navigated -= CompleteInitializePhoneApplication;
}
private void CheckForResetNavigation(object sender, NavigationEventArgs e)
{
// If the app has received a 'reset' navigation, then we need to check
// on the next navigation to see if the page stack should be reset
if (e.NavigationMode == NavigationMode.Reset)
RootFrame.Navigated += ClearBackStackAfterReset;
}
private void ClearBackStackAfterReset(object sender, NavigationEventArgs e)
{
// Unregister the event so it doesn't get called again
RootFrame.Navigated -= ClearBackStackAfterReset;
// Only clear the stack for 'new' (forward) and 'refresh' navigations
if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh)
return;
// For UI consistency, clear the entire page stack
while (RootFrame.RemoveBackEntry() != null)
{
; // do nothing
}
}
#endregion
// Initialize the app's font and flow direction as defined in its localized resource strings.
//
// To ensure that the font of your application is aligned with its supported languages and that the
// FlowDirection for each of those languages follows its traditional direction, ResourceLanguage
// and ResourceFlowDirection should be initialized in each resx file to match these values with that
// file's culture. For example:
//
// AppResources.es-ES.resx
// ResourceLanguage's value should be "es-ES"
// ResourceFlowDirection's value should be "LeftToRight"
//
// AppResources.ar-SA.resx
// ResourceLanguage's value should be "ar-SA"
// ResourceFlowDirection's value should be "RightToLeft"
//
// For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072.
//
private void InitializeLanguage()
{
try
{
// Set the font to match the display language defined by the
// ResourceLanguage resource string for each supported language.
//
// Fall back to the font of the neutral language if the Display
// language of the phone is not supported.
//
// If a compiler error is hit then ResourceLanguage is missing from
// the resource file.
RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage);
// Set the FlowDirection of all elements under the root frame based
// on the ResourceFlowDirection resource string for each
// supported language.
//
// If a compiler error is hit then ResourceFlowDirection is missing from
// the resource file.
FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection);
RootFrame.FlowDirection = flow;
}
catch
{
// If an exception is caught here it is most likely due to either
// ResourceLangauge not being correctly set to a supported language
// code or ResourceFlowDirection is set to a value other than LeftToRight
// or RightToLeft.
if (Debugger.IsAttached)
{
Debugger.Break();
}
throw;
}
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
}
private void ApplicationBarIconButton_Click_1(object sender, EventArgs e)
{
}
}
}
Error: > Knowledge Organizer.ni.DLL!Knowledge_Organizer.App.RootFrame_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e) Line 92 C#
// Code to execute if a navigation fails
private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
if (Debugger.IsAttached)
{
// A navigation has failed; break into the debugger
Debugger.Break();
}
}
EDIT.
Solution was extremely simple - the page.xaml.cs used 1 & 2 as reference when initialized the appbar instead of 0 & 1 - which caused it to not find the number 2 AppBarIconButton - that threw the exception. Solution:
// Initialize these so that we can edit them
deletenotesBtn = ApplicationBar.Buttons[0] as Microsoft.Phone.Shell.ApplicationBarIconButton;
addnoteBtn = ApplicationBar.Buttons[1] as Microsoft.Phone.Shell.ApplicationBarIconButton;
I wrote a simple c# wpf code as below,
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
label1.Content = "Before restart";
System.Diagnostics.Process.Start("ShutDown", "-r"); //restart
label2.Content = "After restart";
}
}
Now the problem is I wanted to resume my application automatically after restart and and display message as "After restart". Please help me how to achieve this...
The solution to this problem is maintain the state in hard disk or some permanent memory like custom transaction file.
For e.g.
There will be different stage in the application. I will enter each stage after processing into file. one the machine is stopped then if the application launch automatically it will read the stage from this file and then process from that stage.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Read stage from transaction file as **Stage**
if(Stage == Stage1)
{
label1.Content = "Before restart";
WriteTransaction(Stage2);
}
System.Diagnostics.Process.Start("ShutDown", "-r"); //restart
if(Stage == Stage2)
{
label2.Content = "After restart";
//Finish transaction and delete the transaction file.
}
}
This way you can solve the problem.
To restart the application automatically you can put your executable under start up folder or even you can think of making it as windows service.
Here's a concept (pseudo code):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// initialize defaults
bool isRestarted = false;
label1.Content = "";
label2.Content = "";
// Check the state
if (stateFile.Exists) // stateFile is something like type FileInfo
{
var text = File.ReadAllText(stateFile.FullName);
isRestarted = ParseForBool(text);
label1.Content = ParseForLabel(text); // if you want that to be restored as well
}
if (isRestarted)
{
label2.Content = "After restart";
DoSomeMagicRemoveAutostart(); // just if you want to restart only once
}
else
{
label1.Content = "Before restart";
stateFile.Write(true); // is restarted
stateFile.Write(label1.Content); // if you want to restore that as well
DoSomeMagicAutoStartOperation(); // TODO: Autostart folder or Registry key
System.Diagnostics.Process.Start("ShutDown", "-r"); //restart
}
}
You have two choices: Adding the application to Startup Folder or adding the appropiate key to the run key in Windows registry.
http://msdn.microsoft.com/en-us/library/aa376977(v=vs.85).aspx
My Excel AddIn is written in NetOffice, ExcelDNA, C#
It calls web service to get data. It takes a while to fetch a large amount of data.
During the process of data fetch, if network connection is lost, then Excel will hung, shows like "not responding". Now if I try to close Excel, it will ask you to close or debug. I simply close it.
Then when I restart Excel, there is an annoying message box comes up saying
"Excel experienced a serious problem with the 'commodity add-in' add-in. If you have seen this message multiple times, you should disable this add-in and check to see if an update is available. Do you want to disable this add-in?."
I wonder how to handle the situation when connection is lost appropriately? Thanks
Make the web service call asynchronously, if possible. Most WS will provide async versions and non-async versions of the calls that you can make.
If this is not possible, consider executing the web service data fetch within a separate thread.
In both scenarios, you should put some plumbing code in place to kill the job after a certain period, and probably some means to notify the user that not all is well.
"Excel experienced a serious problem with the 'XXX add-in' add-in. If
you have seen this message multiple times, you should disable this
add-in and check to see if an update is available. Do you want to
disable this add-in?."
You get this problem when an unhandled exception occurs. Excel will prompt you to disable the Add-In next start up. This can lead users to posts like this to fix it.
The pain is worse when you have to support clients using Citrix in non-admin environments. To get around the problem of Excel wanting to diable the add-In you have to add a Global Exception handler so the exception isn't referred back to Excel to avoid prompting users to disable the Add-In.
public YouAddInCtrl()
{
InitializeComponent();
// Add the event handler for handling UI thread exceptions to the event.
System.Windows.Forms.Application.ThreadException += ApplicationThreadException;
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += ApplicationUnhandledException;
}
private void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
{
addInManager.TopLevelExceptionHandler(e.Exception);
}
private void ApplicationUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
addInManager.TopLevelExceptionHandler((Exception)e.ExceptionObject);
}
// Any exceptions returned to Excel will cause the Addin to be disabled
// So we must swallow them here.
internal void TopLevelExceptionHandler(Exception ex)
{
var e = new NotificationEventArgs(NotificationEventArgs.NotificationEnum.TopLevelException);
if (NotifyEventTopLevelException != null)
{
if (NotifyEventTopLevelException(ex,e))
{
System.Diagnostics.Process.Start("mailto:Support#XYZ.com%3e?subject=XYZ%202%20PROD%20Environment%20Problem&body=Hi,%0A%0AIssue:%0A%0ASteps%20to%20Reproduce:");
}
}
LogExceptions(ex);
}
I would also suggest that you run the WebService request on a different thread, eg:
BackgroundWorker1.WorkerReportsProgress = true;
BackgroundWorker1.WorkerSupportsCancellation = true;
BackgroundWorker1.DoWork += DoWorkExecuteQuery;
BackgroundWorker1.RunWorkerCompleted += RunWorkerCompletedExecuteQuery;
private bool QueryData()
{
var thinkProgBar = new ThinkingProgressBar();
thinkProgBar.ShowCancelLink(true);
thinkProgBar.SetThinkingBar(true);
BackgroundWorker1.RunWorkerAsync(thinkProgBar);
thinkProgBar.ShowDialog();
if (thinkProgBar.Tag != null && thinkProgBar.Tag.ToString() == "Cancelled")
{
CancelGetDataByFilters();
thinkProgBar.SetThinkingBar(false);
return false;
}
thinkProgBar.SetThinkingBar(false);
return true;
}
private void DoWorkExecuteQuery(object sender, DoWorkEventArgs e)
{
dtQueryData = null;
e.Result = e.Argument;
((ThinkingProgressBar)e.Result).SetThinkingBar(true);
dtQueryData = WEBSERVICE.GetData(); //CALL YOUR WEBSERVICE HERE
}
private void RunWorkerCompletedExecuteQuery(object sender, RunWorkerCompletedEventArgs e)
{
var dlg = e.Result as ThinkingProgressBar;
if (dlg != null) {
((ThinkingProgressBar)e.Result).SetThinkingBar(false);
dlg.Close();
}
}
Here is the ThinkingProgress bar:
public partial class ThinkingProgressBar : Form
{
private System.DateTime startTime = DateTime.Now;
public ThinkingProgressBar()
{
InitializeComponent();
}
private void lblClose_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
this.Tag = "Cancelled";
this.Hide();
}
public void ShowCancelLink(bool show)
{
lblClose.Visible = show;
}
public void SetThinkingBar(bool on)
{
if (on)
{
lblTime.Text = "0:00:00";
startTime = DateTime.Now;
timer1.Enabled = true;
timer1.Start();
}
else
{
timer1.Enabled = false;
timer1.Stop();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
var diff = new TimeSpan();
diff = DateTime.Now.Subtract(startTime);
lblTime.Text = diff.Hours + ":" + diff.Minutes.ToString("00") + ":" + diff.Seconds.ToString("00");
lblTime.Invalidate();
}
}