【问题标题】:How would I create composite settings for an application?如何为应用程序创建复合设置?
【发布时间】:2011-08-27 17:48:54
【问题描述】:

我想做的是有一个通用的设置类,我可以在复合应用程序中使用它。当我添加功能和组件并使用 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 界面中,我可以拥有一些基本属性,例如名称以及在 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 和 Prism 动态连接我的模块,但我还没有找到一种令人满意的方法来以复合方式处理设置。

【问题讨论】:

    标签: c# settings mef application-settings composite


    【解决方案1】:

    我在工作中的一个应用程序中处理了类似的问题。我们进一步倾向于您的第二个想法,其中只有一个基本设置界面“ISettings”,我们用于 MEF 合成。

    我们创建了一个自定义导出提供程序来处理加载设置,并有一个管理器使用一些序列化程序保存设置。

    对于 UI,我们的模块具有面向用户的设置,还导出了一个“设置工作区”,我们将加载到设置 UI 中。使用反射,我们编写了一个方法,该方法将对设置对象进行深层复制,以便我们可以将 mvvm 直接绑定到克隆对象(用于取消功能),以及获取对象并将其属性复制回来。

    反思是允许通用克隆/复制,而无需为每个设置对象编写代码。

    此外,我们为数据模型绑定所做的一件我至今仍喜欢的事情是“INotifyPropertyChanged”接口。我们的基础 ISettings 对象需要它。这不仅允许设置 UI 直接绑定到设置并监听更改,而且当我们点击应用或确定时,我们所有需要设置的数据模型都会为 prop changed 事件注册,因此它们都会在设置发生时自动得到通知改变了。

    如果您打算执行通知路线,请查看Property Observer。此应用程序已部署,我仍然觉得我们的设置框架非常成功。

    如果您需要,我可以在某些方面提供更多详细信息。

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      免责声明:我没有自定义实现 ApplicationSettingsBase 的经验,因此我无法协助其实际实现,也不能肯定地说这种方法会起作用。但是,如果您真的想使用 ApplicationSettingsBase,我提出的可能是一条值得探索的路径。

      首先,ISettings不能继承ApplicationSettingsBase,因为接口只能继承其他接口。

      我的建议是创建一个使用 ISettings 实例参数化的自定义 ApplicationSettingsBase 实现。这样,每当您从组件收到 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 实例提供序列化机制。

      编辑:修正了一些代码语法错误

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-17
        • 2011-10-29
        • 1970-01-01
        • 2012-02-11
        • 1970-01-01
        相关资源
        最近更新 更多