问题在于每次装上新版应用程序时,程序集版本都会更改,导致所有用户设置被重设为默认值(或者更准确地说,一个名字带有不同版本号的文件夹中创建了一个新的user.config文件)。
如何在升级版本时保留相同的设置,因为使用ini文件或注册表似乎受到反对?
当我们使用ClickOnce时,它似乎可以处理这个问题,所以看起来应该能够解决,但我不确定具体怎么做。
问题在于每次装上新版应用程序时,程序集版本都会更改,导致所有用户设置被重设为默认值(或者更准确地说,一个名字带有不同版本号的文件夹中创建了一个新的user.config文件)。
如何在升级版本时保留相同的设置,因为使用ini文件或注册表似乎受到反对?
当我们使用ClickOnce时,它似乎可以处理这个问题,所以看起来应该能够解决,但我不确定具体怎么做。
ApplicationSettingsBase有一个名为Upgrade的方法,可以迁移先前版本的所有设置。
为了在每次发布新版本应用程序时运行合并,您可以在设置文件中定义一个布尔标志,默认值为true。将其命名为UpgradeRequired或类似名称。
然后,在应用程序启动时,检查标志是否已设置,如果是,则调用Upgrade方法,将标志设置为false并保存配置。
if (Settings.Default.UpgradeRequired)
{
Settings.Default.Upgrade();
Settings.Default.UpgradeRequired = false;
Settings.Default.Save();
}
请前往MSDN了解更多关于升级方法的信息。如果需要进行一些自定义合并,GetPreviousVersion也值得一看。
appSettings
,userSettings
还是 applicationSettings
?作为 Settings.Settings 上的用户设置,一旦第一次将其更改为 false,它将永远不会再变为 true。新版本不会将该 UpgradeRequired 重置为 True。 - dialex当我们每个版本只需要升级一次时,下一个简短的解决方案适用于我。它不需要额外的设置,如UpgradeRequired
:
if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile)
Settings.Default.Upgrade();
我知道已经有一段时间了...
在一个WinForms应用程序中,只需在加载设置之前调用My.Settings.Upgrade()
。这将获取最新的设置,无论是当前版本还是以前的版本。
GetPreviousVersion()
无法正常工作。因此,您需要将设置保留在您的Settings
类中,但是添加一些属性/工件以确保您不会在代码其他地方意外使用它,使其过时。在VB.NET中,一个过时的设置示例如下(可以轻松转换为C#):<UserScopedSetting(),
DebuggerNonUserCode(),
DefaultSettingValue(""),
Obsolete("Do not use this property for any purpose. Use YOUR_NEW_SETTING_NAME instead."),
NoSettingsVersionUpgrade()>
Public Property OldSettingName() As String
Get
Throw New NotSupportedException("This property is obsolete")
End Get
Set
Throw New NotSupportedException("This property is obsolete")
End Set
End Property
请确保将此属性添加到与您的应用程序设置相同的命名空间/类中。在VB.NET中,这个类的名称是MySettings
,并且可以在My
命名空间中使用。您可以使用部分类功能来防止混淆已过时的设置和当前设置。
感谢jsharrison发布了一篇关于这个问题的优秀文章。您可以在那里阅读更多详细信息。
public abstract class UserSettingsBase : ApplicationSettingsBase
{
public UserSettingsBase() : base()
{
// Accessing a property attempts to load the settings for this assembly version
// If LastSaved has no value (default) an upgrade might be needed
if (LastSaved == null)
{
Upgrade();
}
}
[UserScopedSetting]
public DateTime? LastSaved
{
get { return (DateTime?)this[nameof(LastSaved)]; }
private set { this[nameof(LastSaved)] = value; }
}
public override void Save()
{
LastSaved = DateTime.Now;
base.Save();
}
}
public class MySettings : UserSettingsBase
{
[UserScopedSetting]
public string SomeSetting
{
get { return (string)this[nameof(SomeSetting)]; }
set { this[nameof(SomeSetting)] = value; }
}
public MySettings() : base() { }
}
并使用它:
// Existing settings are loaded and upgraded if needed
MySettings settings = new MySettings();
...
settings.SomeSetting = "SomeValue";
...
settings.Save();
这是我处理它的方式:
public virtual void LoadSettings(ServiceFileFormBaseSettings settings = null, bool resetSettingsToDefaults = false)
{
if (settings == null)
return;
if (resetSettingsToDefaults)
settings.Reset();
else
{
settings.Reload();
if (settings.IsDefault)
settings.Upgrade();
}
this.Size = settings.FormSize;
}
在设置类中,我定义了IsDefault属性:// SaveSettings always sets this to be FALSE.
// This will have the default value TRUE when first deployed, or immediately after an upgrade.
// When the settings exist, this is false.
//
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute("true")]
public virtual bool IsDefault
{
get { return (bool)this["IsDefault"]; }
set { this["IsDefault"] = value; }
}
public virtual void SaveSettings(ServiceFileFormBaseSettings settings = null)
{
if (settings == null) // ignore calls from this base form, if any
return;
settings.IsDefault = false;
settings.FormSize = this.Size;
settings.Save();
}