我想要做的是拥有一个可以在复合应用程序中使用的多功能设置类。当我添加功能和组件并使用MEF&组合应用程序时Prism我想有一个设置窗口,可以自动将每个模块的设置界面加载到一个窗口中(使用Prism& MEF)
处理设置有很多种不同的方式,吸引我的方法如下:
public class AppData : ApplicationSettingsBase
{
[UserScopedSetting()]
[DefaultSettingValue("true")]
public bool Clipboard
{
get { return ((bool)this["Clipboard"]); }
set { this["Clipboard"] = (bool)value; }
}
}
它允许我设置一个默认值,我假设如果应用程序找不到.settings文件,那么它将创建一个默认值。但是,我需要为每个模块设置部分编写一堆自定义代码,并为每个模块创建一个唯一的对话框,或者尝试让设置管理器手动加载它们。
有一些设置也会有多个值,看起来上面的例子看起来不能容纳它。如果我的设置存储了某个列表,该怎么办?例如,如果我有一个设置为ValidBlock,并且在开始时有两个块可能有效,但将来可能需要添加更多?你有一个列表设置并为该设置指定多个默认值吗?
创建一个以某种方式使用ApplicationSettingsBase的Isettings接口是可以接受的,这样我就可以使用MEF在目录中的所有模块中查找所有Isettings实现,然后为它找到的每个实现组成一个带有选项卡的对话框?在Isettings界面中,我可以使用一些基本属性,例如Name以及在MEF WPF窗口中标记和描述模块所需的任何其他属性。
我唯一不喜欢的是整个地方都有字符串和属性。有没有办法以流畅的方式处理设置?我正在考虑使用ISettings实现,您将明确地编写类似于以下内容的设置:
public class AppData : ISettings
{
Setting Clipboard = new Setting();
Clipboard.Scope = SettingScope.User;
Clipboard.SettingType = List<String>;
List<String> DefaultClipboards = new List<String>();
DefaultClipboards.Add("FoxClipboard");
Clipboard.DefaultSetting = DefaultClipboards;
}
我知道上面的语法并不完全正确,我认为Clipboard.SettingType不会占用太多水,但它可以让我知道我在想什么。因此,如果可以在保持创建设置文件的同时实现这样的事情,那么缺少一个理想的设置文件。对于类似的东西,MEF可以找到所有ISettings实现并为每个实现创建一个选项卡,然后根据代码中的设置添加每个设置。
这是正确的轨道吗?是否有一个框架或项目,我错过了处理我的目标?我想可能有比我概述的更好的方法吗?
我确信复合应用程序开发中出现了这个问题,但我没有找到概述这种情况的框架或答案。
我已经能够创建一个松散耦合的复合应用程序,并使用MEF&amp; amp;动态地连接我的模块。 Prism但我无法找到一种以复合方式处理设置的令人满意的方法。
答案 0 :(得分:1)
我在工作中为我的一个应用程序解决了类似问题。我们进一步倾向于你的第二个想法,那里只有一个我们用于MEF组合的基本设置界面“ISettings”。
我们创建了一个自定义导出提供程序来处理加载设置,并让管理员使用某些序列化程序来保存设置。
对于UI,我们拥有面向用户设置的模块也会导出我们将加载到设置UI中的“设置工作区”。使用反射,我们编写了一个方法,它将创建一个设置对象的深层副本,以便我们可以直接将mvvm绑定到克隆对象(用于取消功能),以及获取一个对象并将其复制回来。
反射是为了允许通用克隆/拷贝而不为每个设置对象编写代码。
此外,我们今天仍然喜欢数据模型绑定的一件事是“INotifyPropertyChanged”界面。我们的基础ISettings对象需要它。这不仅允许设置UI直接绑定到设置并监听更改,但是当我们点击apply或ok时,我们需要设置的所有数据模型都会为prop更改事件注册,因此当设置具有设置时,它们都会自动得到通知改变。
如果您打算进行通知路由,请查看Property Observer。该应用程序已经部署,我仍然觉得我们的设置框架非常成功。
如果您需要,我可以在某些方面提供更多详细信息。
希望这有帮助!
答案 1 :(得分:1)
免责声明:我没有使用ApplicationSettingsBase的自定义实现的经验,因此我无法协助其实际实现,也没有积极地说这种方法可行。但是,如果你真的想使用ApplicationSettingsBase,我建议的可能是一条值得探索的路径。
首先,ISettings不能继承 ApplicationSettingsBase,因为接口只能继承其他接口。
我的建议是创建一个自定义的ApplicationSettingsBase实现,该实现使用ISettings实例进行参数化。这样,每当您从组件中收到ISettings时,都会实例化一个新的CustomAppSettings(见下文)并将其与您的组件相关联。
由于ApplicationSettingsBase使用字符串到对象的键值对映射,我提出了一个相同的接口。
public interface ISettings
{
Dictionary<string,object> Values{ get; set; }
public object GetDefaultValue(string key);
// Whatever else you might need
}
public class CustomAppSettings : ApplicationSettingsBase
{
public ISettings Settings { get; set; }
public override object this[string propertyName]
{
get
{
return this.Settings.Values[propertyName];
}
set
{
this.Settings.Values[propertyName] = value;
}
}
// There will be more implementation work for this class I'm sure
}
此外,您还需要ISetting实例的序列化机制。
编辑:修正了一些代码语法错误