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

Windows Phone 7 的 MixModes Synergy Toolkit

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (3投票s)

2011年1月30日

CPOL

6分钟阅读

viewsIcon

17062

介绍 Synergy Toolkit for Windows Phone 7 版本 1.0 的功能

引言

Synergy 是一个平台工具包,可释放 WPF、Silverlight 和 Windows Phone 7 平台的强大功能。在本博文中,我将讨论该库的 Windows 7 手机部分,以及它如何帮助将开发实践某种程度上统一到 WPF 的方式,并利用数据绑定功能。

可以在其 CodePlex 主页访问 Synergy 工具包,在那里,圣诞老人(我)每天都会带来新的礼物和愿望。我已在 下载区发布了 Windows Phone 7 库的 v1 版本。

有关 WPF Synergy Toolkit 的背景信息,您可以参阅我之前的博客 此处。我还为 Synergy 的 WPF 版本编写了一个停靠窗口框架,您可以参阅 此处,以及一篇关于窗口主题的文章 此处

您可以在 Twitter 上关注我 @ashishkaila

言归正传,让我带您了解 v1 版本的功能。

Windows Phone 7 开发的基础框架

命令支持

CommandBase 类为自定义命令提供了灵活的实现。此类使用 Action<object> 实例进行命令调用,并使用可选的 Predicate<object> 进行命令执行评估。如果未指定谓词,则假定命令可以随时执行。简单来说,可以使用以下方式实例化 CommandBase 类:

CommandBase myCommand = new CommandBase(arg=>Foo(arg), arg=>CanFoo(arg));

此外,WP7 和 Silverlight 默认不提供绑定的能力。

依赖系统增强

依赖系统提供了一些增强功能,可帮助开发人员轻松利用该框架进行与绑定和依赖属性相关的更高级操作。这些增强功能如下:

可观察绑定

顾名思义,ObservableBinding 类会观察绑定以进行值更改,并提供绑定的最新值。此类在自定义行为和触发器操作中非常有用,在这些操作中,关联对象的数据上下文不会传播到这些实体。这是因为行为和触发器是 static Interaction 类(在 System.Windows.Interactivity 程序集中声明)中的附加属性,因此与依赖系统分离。

通过声明一个类型为 Binding 的依赖属性,并在 Behavior/TriggerAction 中使用 ObservableBinding ,您可以同时挂钩到关联对象的依赖属性系统,以及评估绑定的最新值。

例如,EventToCommand 触发器操作定义了一个类型为 Binding 的依赖属性 Command

public static DependencyProperty CommandProperty = 
DependencyProperty.Register("Command", 
                            typeof (Binding),
                            typeof (EventToCommand),
                            new PropertyMetadata(null, OnCommandChanged)); 

它还声明了命令的 ObservableBinding

private readonly ObservableBinding _observableCommandBinding = new ObservableBinding(); 

_observableCommandBinding 成员将为我们提供 Command 属性公开的 Binding 的最新值。

有一些规则可确保 ObservableBinding Binding 属性按预期工作。基本上,每当 Binding 属性发生更改时,我们都必须从旧的 Binding 中取消挂钩,并挂钩到新的 binding。这在 OnCommandChanged 方法中完成,该方法在 Binding 属性更改时被调用(即实际的 Binding 属性,而不是 Binding 的值)。

private static void OnCommandParameterChanged
	(DependencyObject d, DependencyPropertyChangedEventArgs e)  
{
    EventToCommand eventToCommand = d as EventToCommand; 

    if (eventToCommand == null)  
    {
        return;
    } 

    eventToCommand._observableCommandParameterBinding.Detach(); 
             
    if ((e.NewValue != null) && (eventToCommand.AssociatedObject != null))  
    {  
           eventToCommand._observableCommandParameterBinding.Attach
		(eventToCommand.Command eventToCommand.AssociatedObject);
    }
} 

另外,当关联对象最初附加到 TriggerAction / Behavior 时,我们需要附加到 ObservableBinding

protected override void OnAttached()  
{
    base.OnAttached(); 

    if (Command != null) 
    { 
        _observableCommandBinding.Attach(Command, AssociatedObject);
    } 
} 

如果跳过以上步骤,ObservableBinding 将不会跟踪 Binding 的初始值。

可观察依赖属性

另一方面,ObservableDependencyProperty 通过事件通知提供了跟踪另一个 DependencyObject 中声明的依赖属性更改的能力。ObservableDependencyProperty 的构造函数接受两个参数:一个表示要观察的依赖属性名称的 string,以及一个将在依赖属性更改时调用的 DependencyPropertyChangedEventHandler 类型委托。

ObservableDependencyProperty _verticalScrollChange = 
	new ObservableDependencyProperty("VerticalOffset", OnVerticalScroll); 

要跟踪实际 DependencyObject 的依赖属性更改,必须通过 AddValueChanged 方法将 ObservableDependencyProperty 实例附加到它。

_verticalScrollChange.AddValueChanged(_scrollViewer);

同样,要分离或停止属性更改跟踪,可以调用 RemoveValueChanged 方法。

_verticalScrollChange.RemoveValueChanged(); 

完整的 MVVM 框架

通过继承基类 ViewModelBase,即可实现自定义视图模型。要引发 PropertyChanged 事件,可以调用类型安全的 RaisePropertyChanged 方法,并传入包含属性引用的表达式,例如:

RaisePropertyChanged(x=>MyProperty);

ViewModelBase 还包含一个 Navigate 方法,可以导航手机到绑定的视图,并在后台执行数据绑定(更多内容将在下一节介绍),例如:

MyViewModel viewModel = new MyViewModel();
  
viewModel.Navigate(); // Note: For this to work, 
	// your application must inherit from PhoneApplication class (see below) 

通过声明性的视图-视图模型绑定简化导航

在 WPF 中,DataTemplates 可以在应用程序级别将 ViewModel 绑定到 View。此绑定使得在 ContentPresenter 内可以运行时生成视图。我希望将相同的想法扩展到 Windows Phone 7 屏幕导航,因为应用程序内的基于 URL 的导航似乎容易出错,并且传递查询参数很麻烦。

ViewSelector 类提供了与 ViewBinding 类结合使用的声明性绑定功能。基本上,您可以在应用程序资源中定义此映射:

<Framework:ViewSelector x:Key="ApplicationViewSelector">  
    <Framework:ViewBinding ViewModelType="INameU.ViewModels.NameListViewModel"  
                           ViewUri="/Views/NameListView.xaml" />
    <Framework:ViewBinding ViewModelType="INameU.ViewModels.NameDetailViewModel"  
                           ViewUri="/Views/NameDetailView.xaml" />  
</Framework:ViewSelector> 

其中,Framework 被映射为:

xmlns:Framework="clr-namespace:MixModes.Phone.Synergy.Framework;
	assembly=MixModes.Phone.Synergy" 

完成此操作后,您可以从 ViewModel 实例调用 Navigate 方法,导航到映射的视图,同时进行数据绑定,而无需使用任何 URL!

DockPanel 和 WrapPanel 控件

我已将 Silverlight Toolkit for Windows Phone 7 中的 DockPanel WrapPanel 移植过来,因此如果您除了这些面板之外不使用任何其他附加功能,则无需引用该工具包。

EventToCommand 触发器操作

一个常见的痛点是,诸如 Button 和 ListBoxItem 等控件缺少 Command CommandParameter 属性。为了填补这一空白,可以使用 EventToCommand 触发器操作将 RoutedEvent 映射到 ICommand 实例以及 CommandParameter 实例。要将 RoutedCommand 绑定到 EventToCommand 触发器,您需要将触发器添加到关联的框架元素:

<Button Content="Click Me">  
    <Custom:Interaction.Triggers>  
        <Custom:EventTrigger EventName="Click">
            <Triggers:EventToCommand Command=
		"{Binding Path=DataContext.ShowDetailsCommand, ElementName=Page}" 
		PassEventArgsToCommand="True"/>
        </Custom:EventTrigger>  
    </Custom:Interaction.Triggers>  
</Button> 

PassEventArgsToCommand 属性设置为 true 时,会将 RoutedEventArgs 作为 CommandParameter 传递给关联 ICommandExecute 方法。

ScrollLoadBehavior

ScrollLoadBehavior 允许用户垂直滚动到滚动查看器的底部时异步加载数据。ScrollLoadBehavior 有一个关联的 ICommand CommandParameter,在滚动查看器到达最底部时随时执行。加载通过 ICommandCanExecute 方法检测。例如:

<ListBox DataContext="{Binding}"                 
            ItemsSource="{Binding Path=Names}">  
    <Custom:Interaction.Behaviors>  
        <Behavior:ScrollLoadBehavior Command="{Binding Path=LoadNamesCommand}" />
    </Custom:Interaction.Behaviors>
</ListBox>

请注意 ListBox 中显式的 DataContext=”{Binding}”。这是必需的,因为如果没有显式的父数据绑定,ItemsSource 会将 DataContext 设置为其值,从而导致 ScrollLoadBehavior 的绑定失败。

开箱即用的转换器

工具包中提供了许多常用的开箱即用转换器:

  • EnumMatchConverter – 匹配枚举成员的值与常量值,并返回一个布尔值指示是否匹配。例如,如果您想在状态为 StateEnum.IsError 时启用控件,可以执行以下操作:
    Enabled="{Binding Path=State, Converter={StaticResource EnumConverter}, 
    	ConverterParameter=IsError}"
  • NotConverter – 反转布尔表达式的值。
  • VisibilityConverter – 根据布尔值,显示(如果值为 true)或折叠(如果值为 false)控件的可见性。
  • PipeConverter – 将一个值通过多个转换器进行传递,以计算绑定表达式的最终值。例如,如果您想匹配一个值到一个枚举成员“Loading”,然后确定控件的可见性,可以如下声明一个管道转换器:
    <conv:PipeConverter x:Key="LoadingMessageVisibilityConverter">      
        <conv:EnumMatchConverter />      
        <conv:VisibilityConverter />      
    </conv:PipeConverter>  

    值从上到下进行传递,因此首先调用 EnumMatchConverter ,然后调用 VisibilityConverter。要使用它,只需如下引用 PipeConverter

    Visibility="{Binding Path=State, 
    Converter={StaticResource LoadingMessageVisibilityConverter}, 
    ConverterParameter=Loading}"
  • ThemeBasedResourceConverter – 此转换器根据 Windows 7 Phone 的主题(暗色或亮色)返回资源。要使用此转换器,需要通过 LightThemeResource DarkThemeResource 属性指向两个主题的资源。例如,如果您的应用程序具有两种主题的导航按钮图像,如 NavigationLight.pngNavigationDark.png,您可以使用 ThemeBasedResourceConverter 将适当的图像设置为按钮的背景,如下所示:
    <phone:PhoneApplicationPage.Resources>      
        <Converters:ThemeBasedResourceConverter x:Key="ThemeBasedResourceConverter"
    	LightThemeResource="../Resources/NavigationLight.png"
    	DarkThemeResource="../Resources/NavigationDark.png" />      
    </phone:PhoneApplicationPage.Resources> 

    然后,在按钮中引用上述 ThemeBasedResourceConverter

    <Button>      
        <Image Stretch="None"      
               Source="{Binding Path=., RelativeSource={RelativeSource Self}, 
    		Converter={StaticResource ThemeBasedResourceConverter}}">      
        </Image>      
    </Button>  

以上就是 v1 的全部内容,各位!非常乐意收到您的任何反馈,并将不断开发 Synergy 工具包,让您在 WPF、WP7 或 Silverlight 中进行开发更加轻松!

历史

  • 2011 年 1 月 30 日:初次发布
© . All rights reserved.