65.9K
CodeProject 正在变化。 阅读更多。
Home

自动生成设置页面

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2011年9月6日

CPOL

3分钟阅读

viewsIcon

25343

downloadIcon

362

自动生成 Windows Phone 7 设置页面。

引言

由于我们的大部分 Windows Phone 7 应用程序都需要一个配置页面,以便用户对应用程序本身进行任何调整,并且这项任务始终是一个重复性的任务,不需要任何额外的处理,所以我决定创建一个简单的应用程序,其中包含一个自动生成的配置页面,这对我们 Windows Phone 7 开发人员可能有所帮助。

背景

一段时间以来,在编程中,将应用程序的设置保存在 XML 格式中已成为标准。我决定使用 XML 格式,因为它非常通用,而且当然有一些实用程序可以从 XML 架构生成类,因此使用 .NET 中的序列化类来保存或检索这些设置非常容易。

代码解释

XML 架构

下图显示了用于生成配置的 XML 架构。如图所示,配置必须具有名称和数据类型,如果不想自行生成控件,还可以包含 XAML 代码;或者,如果数据类型定义为字符串数组,则必须提供字符串项目列表。

Settings-schema.JPG

我使用 JDeveloper 创建此 XML 架构,因为我认为它是 XML 架构的最佳可视化编辑器之一,而且它是免费的。JDeveloper 有点慢,因此建议使用具有良好 CPU、足够内存的体面硬件,如果您有固态硬盘,那就更好了。

将数据类型分配给配置设置有助于自动生成配置控件:如果设置了 StringNumeric 数据类型,则会生成一个 TextBox;如果是 Boolean 数据类型,它将生成一个 ToggleSwitch,如果是 StringArray 数据类型,它将生成一个 ListPicker 控件。

MVVM 项目

我们简单的应用程序由两个页面组成:MainPageSettingsPage,一个包含 XML 架构的数据模型,转换为代码(XSD 到类),以及一个示例配置文件 (settings.xml)。反过来,此应用程序遵循 Model-View-View-Model 的约定 (MVVM Light) 由 Laurent Bugnion 提供。

Solution.JPG

该项目还引用了 Isolated Storage Explorer for WP7,这是因为应用程序可能需要对默认配置进行一些调整,以便我们可以从一个相当基本的配置开始,并最终确定一个配置文件 (settings.xml 经过调整和测试,一旦应用程序部署到 marketplace,它将成为默认配置文件)。

Isolated-Storage-Explorer.JPG

在我们的应用程序中,如果您愿意,我们使用了琐碎且毫无意义的设置,但它足以用于演示目的。

现在让我们详细看看代码。

<settings xmlns="http://www.inputstudiowp7.com/schemas">
    <Setting Name="Use Location" Type="Boolean" Value="True"/>
    <Setting Name="Providers" Type="StringArray" Value="Item 2">
        <StringItem Value="Item 1"/>
        <StringItem Value="Item 2"/>
        <StringItem Value="Item 3"/>
    </Setting>
    <Setting Name="Nick Name" Type="String" Value="Undefined"/>
    <Setting Name="Age" Type="Integer" Value="18"/>
</settings>

主页只有我们主 Model-View 的几个属性和一个指向设置页面的超链接。设置页面是一个空的 Grid,页面加载后会自行生成控件。

主页
设置页面
MvvmSettings-Home.JPG MvvmSettings-SettingsPage.JPG

至于设置页面中自行生成的控件,当页面加载发生时,代码会迭代每个设置,并根据其类型生成输入控件,并分配一个 TextBlock 作为标签(Caption)和一个数字或文本输入范围(如果适用)。离开配置页面后,将保存设置。

public partial class SettingsPage : PhoneApplicationPage
{
    public MainViewModel model { get { return this.DataContext as MainViewModel; } }

    
    public SettingsPage()
    {
        InitializeComponent();
        this.Loaded += new System.Windows.RoutedEventHandler(Settings_Loaded);
    }

    void Settings_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
        Grid grid = this.FindName("LayoutRoot") as Grid;
        if (null != grid)
        {
            StackPanel spContent = new StackPanel();
            foreach (Setting setting in model.Settings.Setting)
            {
                TextBlock tbCaption = 
                  new TextBlock() { Text = string.Format("{0}", 
                  setting.Name.Trim()), Margin = new Thickness(12, 0, 0, 0) };
                switch (setting.Type)
                {
                    case eDataType.Boolean:
                        ToggleSwitch tsOption = new ToggleSwitch() 
                        { 
                            Name = string.Format("ts{0}", 
                              setting.Name.Replace(" ", string.Empty)), 
                              Header = setting.Name 
                        };
                        tsOption.SetBinding(ToggleSwitch.IsCheckedProperty, 
                          new Binding("Value") 
                          { Mode = BindingMode.TwoWay, Source = setting });
                        spContent.Children.Add(tsOption);
                        break;
                    case eDataType.String:
                    case eDataType.Integer:
                    case eDataType.Decimal:
                        TextBox txtValue = new TextBox()
                        {
                            Name = string.Format("txt{0}", 
                              setting.Name.Replace(" ", string.Empty)),
                            Height = 72,
                            MaxLength = 50,
                            TextWrapping = TextWrapping.NoWrap
                        };
                        txtValue.SetBinding(TextBox.TextProperty, 
                          new Binding("Value") { Mode = BindingMode.TwoWay, 
                          Source = setting });
                        txtValue.InputScope = new InputScope()
                        {
                            Names = { new InputScopeName() { 
                                NameValue = (setting.Type.Equals(eDataType.String) 
                                ? InputScopeNameValue.Text
                                : InputScopeNameValue.Number) } }
                        };

                        spContent.Children.Add(tbCaption);
                        spContent.Children.Add(txtValue);
                        break;
                    case eDataType.StringArray:
                        ListPicker lpValue = new ListPicker()
                        {
                            Header = string.Format("{0}", setting.Name.Trim())
                        };

                        List<string> items = new List<string>();
                        foreach (StringItem item in setting.StringItem)
                            items.Add(item.Value);

                            lpValue.ItemsSource = items;
                            lpValue.SetBinding(ListPicker.SelectedItemProperty, 
                              new Binding("Value") 
                              { Mode = BindingMode.TwoWay, Source = setting });
                            spContent.Children.Add(lpValue);
                        break;
                }
            } 
            grid.Children.Add(spContent);
        }
    }

    protected override void OnNavigatedFrom(
              System.Windows.Navigation.NavigationEventArgs e)
    {
        model.saveSettings();

        base.OnNavigatedFrom(e);
    }
}

另外,当发生灾难性故障时,应用程序会发送电子邮件。

关注点

如果您发现此自动生成的设置页面很有用,则可以修改 Visual Studio 模板以包含此页面并设置配置项目。

这只是构建完全可配置设置页面的起点。

历史

此帖子的第一个版本。 这是我在 CodeProject 中的第二个帖子。

© . All rights reserved.