Turn off screen refresh and turn it on if it starts?

When executing procedures that use Excel, I usually turn off some application settings at the beginning of the procedure, and then turn them back on at the end of the procedure.

Code to enable or disable application settings:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace XLTimeTracker { class API { public static void TurnAppSettingsOff() { AddinModule.CurrentInstance.ExcelApp.EnableEvents = false; AddinModule.CurrentInstance.ExcelApp.ScreenUpdating = false; } public static void TurnAppSettingsOn() { if (AddinModule.CurrentInstance.ExcelApp == null) return; AddinModule.CurrentInstance.ExcelApp.EnableEvents = true; AddinModule.CurrentInstance.ExcelApp.ScreenUpdating = true; } } } 

I call these procedures as follows:

 API.TurnAppSettingsOff(); // my code API.TurnAppSettingsOn(); 

It works well.

But say that I want to enable the application settings that were turned on before I ran the API.TurnAppSettingsOff() . What would be a good way to code this?

Some thoughts:

  • I think I need to somehow save the previous state of the application settings. For example, by writing:

Boolean screenUpdating = AddinModule.CurrentInstance.ExcelApp.ScreenUpdating;

  • I would like the end result to be correct, even if a function that disables appsettings also calls another function that disables and disables application settings.

  • I do not know if it is better to set all the settings with a single command, for example, API.TurnAppSettingsOff() , or if it would be more reasonable for the user to use API.TurnScreenUpdatingOff() and API.TurnEventsOff() .

+6
source share
4 answers

I would just type in an inner manager class that handles everything that looks like the following:

 public sealed class ApplicationSettingsManager { readonly object app; readonly Dictionary<string, object> appSettings; public ApplicationSettingsManager(object app) { this.app = app; appSettings = new Dictionary<string, object>(); } public object Application { get { return app; } } public void SaveSetting(string settingName) { var propInfo = app.GetType().GetProperty(settingName); if (propInfo == null) throw new ArgumentException("Specified name is not a valid storable setting.", "setting"); var value = propInfo.GetValue(app); if (appSettings.ContainsKey(settingName)) { appSettings[settingName] = value; } else { appSettings.Add(settingName, value); } } public void SaveAllSettings() { var properties = app.GetType().GetProperties().Where(p => p.CanWrite && p.CanRead && p.SetMethod.IsPublic && p.GetMethod.IsPublic); foreach (var p in properties) { var value = p.GetValue(app); if (appSettings.ContainsKey(p.Name)) { appSettings[p.Name] = value; } else { appSettings.Add(p.Name, value); } } } public void RestoreSetting(string settingName) { if (!appSettings.ContainsKey(settingName)) throw new ArgumentException("Specified name does not correspond to a valid stored setting.", "settingName"); var propInfo = app.GetType().GetProperty(settingName); propInfo.SetValue(app, appSettings[settingName]); } public void RestoreAllSettingas() { foreach (var p in appSettings) { RestoreSetting(p.Key); } } } 

That should do the trick. You would use it as follows:

 var excelSettingsManager = new ApplicationSettingsManager(AddinModule.CurrentInstance.ExcelApp); //store all settings you are going to tamper with... excelSettingsManager.SaveSetting("EnableEvents"); excelSettingsManager.SaveSetting("ScreenUpdating"); //change excel setting and do your thing... //... //when done, restore settings excelSettingsManager.RestoreAllSettings(); 

And you're done!

+1
source

Here is my own solution that I came up with to solve the problem. It seems simpler to me than other proposed solutions. Let me know if you think you have the best solution!

(My code below is in VB.NET)

Class for handling settings changes and saving the initial state:

 Public Class ApplicationSettings Implements IDisposable Private ScreenUpdating As Boolean Private Events As Boolean Private Production As Boolean = True Public Sub New() MyBase.New() ScreenUpdating = AddinModule.ExcelApp.ScreenUpdating Events = AddinModule.ExcelApp.EnableEvents End Sub Public Sub Dispose() Implements IDisposable.Dispose AddinModule.ExcelApp.ScreenUpdating = ScreenUpdating AddinModule.ExcelApp.EnableEvents = Events End Sub End Class 

And this is how I use it in the code:

 Private Sub AdxRibbonButton1_OnClick(sender As Object, control As IRibbonControl, pressed As Boolean) Handles AdxRibbonButton1.OnClick Using New ApplicationSettings 'My code End Using End Sub 
0
source

You can use the Stack<T> class to implement the last time behavior for the first time (LIFO).

 struct ExcelEventSettings { public bool EnableEvents; public bool ScreenUpdating; } class Example { private Stack<ExcelEventSettings> settingStack = new Stack<ExcelEventSettings>(); // you can call this function as often as you called SaveAppSettings public void RestoreAppSettings() { if (settingStack.Count == 0) throw new Exception("There is no previous state!"); ExcelEventSettings prevState = settingStack.Pop(); setCurrentEnableEvents(prevState.EnableEvents); setCurrentScreenUpdating(prevState.ScreenUpdating); } public void SetAppSettings(bool enableEvents, bool screenUpdating) { ExcelEventSettings currentState; currentState.EnableEvents = getCurrentEnableEvents(); currentState.ScreenUpdating = getCurrentScreenUpdating(); settingStack.Push(currentState); setCurrentScreenUpdating(enableEvents); setCurrentEnableEvents(screenUpdating); } private bool getCurrentEnableEvents() { // Here you would call your Excel function } private bool getCurrentScreenUpdating() { // Here you would call your Excel function } private void setCurrentEnableEvents(bool value) { // Here you would call your Excel function } private void setCurrentScreenUpdating(bool value) { // Here you would call your Excel function } } 
-1
source

I would recommend using an integer to represent the state and hide it with a boolean. Here is what I mean:

 this.Working = true; try { // do something } finally { this.Working = false; } 

Then we implement the Working property as follows:

 private int working; public bool Working { get { return working > 0; } set { if (value) { working++; } else { working--; } } } 

Internally, he simply remembers how many times it worked, as it was found, using this integer. If Working is 0 , you will return to normal.

You can install Working as many times as you want. As long as it is > 0 , it will return true . Remember to wrap your code in try...catch or you will lose count.

You can make an API call if Working set to false . Then set to true :

 if (!this.Working) { // do API call this.TurnAppSettingsOff(); } this.Working = true; try { // do something } finally { this.Working = false; } if (!this.Working) { // do reset API call this.TurnAppSettingsOn(); } 
-1
source

All Articles