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

在 Expression Blend 扩展中添加选项

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2010年7月31日

CPOL

5分钟阅读

viewsIcon

15765

通常,Expression Blend 的扩展需要存储一些全局变量。为什么不使用 Blend 本身提供的机制呢?

引言

通常,Expression Blend 的扩展需要存储一些全局变量。为什么不使用 Blend 本身提供的机制呢?我想向您展示如何为选项对话框添加自定义选项页面。

我通过创建一个名为 ExtendingBlendOptionsTutorial 的新的 C# WPF 自定义控件库项目来启动示例项目。有关如何创建新的 Blend 扩展的详细信息,可以在此处找到。您需要确保您的项目中引用了 Microsoft.Expression.Extensibility Microsoft.Expression.Framework 程序集。这两个程序集都可以在您计算机上的 Expression Blend 安装文件夹中找到。

架构设计借鉴了 Blend 当前使用的选项页面。每个现有页面都使用一个 “...Page” ,一个包含对话框 XAML 的 “...Control” 以及一个 “...Model”Model 绑定到 Control 。本教程中的示例遵循相同的模式。

IPackage 实现

让我们从头开始。当 Blend 启动时,它会使用 MEF 加载扩展。因此,扩展必须是 IPackage 接口的实现,并且必须用 Export 属性进行装饰。

image

代码非常简单。从 Blend 提供的 IServices 中,请求 IOptionsDialogService 的实例。此服务包含所有选项页面的集合。每个选项页面都是 IOptionsPage 的实现。

在这种情况下,在 Load 方法中创建了一个新的 TutorialOptionsPage 。并将一个新的 TutorialOptionsModel 传递给了它。之后,将 TutorialOptionsPage 添加到选项页面列表中。

[Export(typeof(IPackage))]
public class OptionsTutorialPackage:IPackage 
{   
    public void Load(IServices services)
    {
       IOptionsDialogService optionsDialogService = 
                services.GetService<IOptionsDialogService>();
            
        TutorialOptionsPage optionsPage = 
               new TutorialOptionsPage(new TutorialOptionsModel(services));
        optionsDialogService.OptionsPages.Add(optionsPage);
    }
 
    public void Unload()
    {
    }
}  

选项页面

TutorialOptionPage 基本上是 IOptionPage 接口的实现。

image

属性

  • Content - 包含一个框架元素,该元素包含选项页面的视图。它应包含输入元素来设置配置选项。
  • Title - 包含选项页面的标题。它显示在选项对话框左侧的列表中。
  • Name - 包含页面的内部名称。

方法

  • Cancel - 当用户单击选项对话框的取消按钮时调用。
  • Commit - 当用户单击“确定”按钮时调用。
  • Load - 在 Blend 启动时调用。

首先,让我们看一下声明和构造函数。TutorialOptionPage 类必须实现 IOptionsPage 接口才能正常工作。此接口可以在 Microsoft.Expression.Framework.Configuration 命名空间中找到。保留对 TutorialOptionsControlTutorialOptionsModel 的引用。以及对 IConfigurationObject 接口的引用。

构造函数接收 TutorialOptionsModel 的实例并将其存储。

public class TutorialOptionsPage:IOptionsPage
{      
    private TutorialOptionsControl tutorialOptionsControl;
    private TutorialOptionsModel tutorialOptionsModel;
    private IConfigurationObject configurationObject;
 
    public TutorialOptionsPage(TutorialOptionsModel model)
    {
        tutorialOptionsModel = model;
    }

Title Name 属性的实现非常简单。它们都只返回一个 string

public string Title
{
    get { return "TutorialOptionsTitle"; }
}
 
public string Name
{
    get { return "TutorialOptionsName"; }
}

Content 属性返回 TutorialOptionsControl 的实例,即选项页面的 UI。它需要 IConfigurationObject 的实例来加载模型的数据。此接口传递给 Load 方法,我将在稍后进行描述。

如果模型未加载(当选项对话框中的更改被取消时发生),则必须实例化一个新的模型。在这种情况下,还需要加载配置数据。

模型上的 Load 方法被调用。之后,它被传递给 TutorialOptionsControl 的构造函数,在那里它将被绑定到 UI。

public object Content
{
    get
    {
        if (this.tutorialOptionsModel == null)
        {
            this.tutorialOptionsModel = new TutorialOptionsModel();
            this.tutorialOptionsModel.Load(configurationObject);
        }
        if (this.tutorialOptionsControl == null)
        {
            this.tutorialOptionsControl = 
                new TutorialOptionsControl(this.tutorialOptionsModel);
        }
        return this.tutorialOptionsControl;
    }
}

好的,TutorialOptionsPage 类的 Load 方法。它将 IConfigurationObject 接口作为参数,该接口由 Blend 提供。它被存储在类中以便以后再次使用。模型通过使用 IConfigurationObject 加载。

public void Load(IConfigurationObject value)
{            
    configurationObject = value;
    this.tutorialOptionsModel.Load(this.configurationObject);    
}

当用户单击选项对话框上的“取消”按钮时,将调用 Cancel 方法。TutorialOptionsControl TutorialOptionsModel 都设置为 null ,以确保它们将在下次打开选项对话框时重新加载。

public void Cancel()
{
    this.tutorialOptionsControl = null;
    this.tutorialOptionsModel = null;
}

当用户单击选项对话框上的“确定”按钮以保存设置时,将调用 Commit 方法。首先必须清除 configurationObject 以删除可能遗留的任何不需要的设置。调用模型上的 Save 方法,并将 configurationObject 传递给它。

最后,TutorialOptionsControl TutorialOptionsModel 都重置为在下次需要时重新加载。

public void Commit()
{
    if(this.tutorialOptionsModel!=null)
    {
        this.configurationObject.Clear();
        tutorialOptionsModel.Save(configurationObject);
        this.tutorialOptionsControl = null;
        this.tutorialOptionsModel = null;              
    }
}

模型

在此示例中,模型仅包含两个属性,两个字符串。为确保 UI 更新正确,实现了 INotifyPropertyChanged 接口。

属性的保存和加载在 Load Save 方法中完成。这两种方法都使用 IConfigurationObject。属性使用 IConfigurationObject 接口的 SetProperty 方法保存。要加载属性,将为每个属性调用 GetProperty 方法。使用与保存相同的键,并将返回的对象强制转换为正确的类型。

public class TutorialOptionsModel : INotifyPropertyChanged
{  
    private string _value1;
    public string Value1
    {
        get { return _value1; }
        set
        {
            _value1 = value;
            InvokePropertyChanged("Value1");
        }
    }
 
    private string _value2;
    public string Value2
    {
        get { return _value2; }
        set
        {
            _value2 = value;
            InvokePropertyChanged("Value2");
        }
    }      
 
    public void Save(IConfigurationObject configurationObject)
    {
        configurationObject.SetProperty("OptionsTutorialValue1", this.Value1);
        configurationObject.SetProperty("OptionsTutorialValue2", this.Value2);
    }
 
    public void Load(IConfigurationObject configurationObject)
    {
        Value1 = 
            configurationObject.GetProperty("OptionsTutorialValue1") as string;
        Value2 = 
            configurationObject.GetProperty("OptionsTutorialValue2") as string;
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    public void InvokePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

在实际的扩展中,模型可以在扩展的其他部分中使用,以使配置可供其他类使用。只需确保调用 Load 方法即可。

用户界面

选项对话框的用户界面只是 XAML。在此示例中,我创建了一个 WPF UserControl,其中包含两个文本框,供用户输入文本。这两个值都存储在 Blend 的配置文件中。文本框绑定到模型的两个属性。

image

用于创建此 UI 的 XAML

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="48" />
        <RowDefinition Height="48" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="124" />
        <ColumnDefinition Width="176*" />
    </Grid.ColumnDefinitions>
    <TextBox Margin="4"  
                VerticalAlignment="Center"                 
                Grid.Column="1" 
                Text="{Binding Value1}" />
    <Label Content="Value 1:"                
            HorizontalAlignment="Right" 
            VerticalAlignment="Center" />
    <TextBox  Margin="4,12" 
                Grid.Column="1" 
                Grid.Row="1" 
                Text="{Binding Value2}"/>
    <Label Content="Value 2:" 
            HorizontalAlignment="Right" 
            VerticalAlignment="Center"  
            Grid.Row="1"  />
</Grid>

UserControl 的数据上下文需要设置为 TutorialOptionsModel 的实例。这是通过控件的构造函数完成的。

public partial class TutorialOptionsControl : UserControl
{
    public TutorialOptionsControl(TutorialOptionsModel tutorialOptionsModel)
    {
        InitializeComponent();
        this.DataContext = tutorialOptionsModel;
    }
}

编译并运行后,选项页面现在应该看起来像这样

image

类和接口

这是教程中使用的类和接口的图表。

image

image

源代码

项目代码可以在此处下载。

 

© . All rights reserved.