关闭屏幕更新,如果已经开启则重新开启?

6

在运行使用Excel的过程中,我通常会在过程开始时关闭一些应用程序设置,然后在过程结束时再重新打开它们。

关闭和打开应用程序设置的代码:

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;
        }
    }
}
我会按照以下方式调用这些过程:
API.TurnAppSettingsOff();
// my code
API.TurnAppSettingsOn();

这很有效。

但是,如果我只想要打开在运行 API.TurnAppSettingsOff() 前已经存在的应用程序设置,有什么好的编码方法呢?

一些想法:

  • 我想我需要以某种方式保存应用程序设置的先前状态。例如,写入:

Boolean screenUpdating = AddinModule.CurrentInstance.ExcelApp.ScreenUpdating;

  • 我希望即使一个将appsettings开和关的函数也调用另一个将app settings开和关的函数,最终结果也是正确的。

  • 我不知道是最好一次使用一个命令来设置所有设置,如API.TurnAppSettingsOff(),还是更明智地使用API.TurnScreenUpdatingOff()API.TurnEventsOff()

4个回答

1
我会为您编写一个内部管理类,处理整个事情,类似于以下方式:
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);
        }
    }
}

应该就可以了。您可以按以下方式使用它;

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();

完成了!


0
这是我自己想出来解决问题的方案。对我来说,它似乎比其他建议的解决方案更简单。如果您认为您有更好的解决方案,请告诉我! (我的代码如下所示,恰好是VB.NET) 用于处理设置更改和存储原始状态的类:
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

接下来是我在代码中的使用方法:

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

-1

您可以使用 Stack<T> 类来实现后进先出(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
没有解释如何使用这个,这只是一个注释而已。 - Sayse
我正在这些时刻准备一个例子。 - Stefan Wanitzek

-1
我建议使用整数来表示状态,并使用布尔值隐藏它。这就是我的意思:
this.Working = true;

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

然后像这样实现Working属性:

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

在内部,它只是记住了设置工作次数的整数。如果working0,那么你就回到了正常状态。

您可以随意设置Working的工作次数。只要它是> 0,它就会返回true。不要忘记将您的代码包装在try...catch中,否则您将失去计数。

如果Working设置为false,则可以进行API调用。然后将其设置为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();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,