WPF 与Xamarin.Forms:共性与差异

控件模板

WPF 支持控件模板的概念,该概念为控件(ButtonListBox 等)提供可视化说明。 如上所述,Xamarin.Forms 对此内容使用具体的渲染类,这些类与本机平台(iOS、Android 等)交互来可视化控件。

但是,Xamarin.Forms 确实有一个 ControlTemplate 类型 - 它用于设置 Page 对象的主题。 它为 Page 提供了一个定义,该定义提供一致的内容,但允许页面用户更改颜色和字体等,甚至添加元素来使其对应用程序具有唯一性。

它的常见用法包括身份验证对话框、提示,还包括提供一个标准化的但可在应用中自定义的可主题化页面外观。 作为这种支持的一部分,使用了许多熟悉的 WPF 命名控件:

  1. ContentPage
  2. ContentView
  3. ContentPresenter
  4. TemplateBinding

但是,必须知道这些功能在 Xamarin.Forms 中不会起到相同的作用。 若要详细了解此功能,请参阅文档页

XAML

XAML 用作 WPF 和 Xamarin.Forms 的声明性标记语言。 在大多数情况下,语法是相同的,主要区别是 XAML 图形定义/创建的对象。

  • Xamarin.Forms 支持 XAML 2009 规范;这使得能够更加轻松地定义数据(例如 stringint 等),还能更容易地定义泛型类型和将参数传递给构造函数。

  • 目前无法像 WPF 使用 XamlReader 加载 XAML 一样动态加载 XAML。 不过,可以使用 NuGet 包获取相同的基本功能。

标记扩展

Xamarin.Forms 支持通过标记扩展来扩展 XAML,这与 WPF 非常类似。 此功能开箱即用,具有相同的基本构建基块:

  1. {x:Array}
  2. {Binding}
  3. {DynamicResource}
  4. {x:Null}
  5. {x:Static}
  6. {StaticResource}
  7. {x:Type}

此外,它还包括来自 XAML 2009 规范的 {x:Reference},还包括一个 {TemplateBinding} 标记扩展,用于 Xamarin.Forms 支持的 ControlTemplate 的专用版本。

警告

ControlTemplate 支持是不同的 - 即使它具有相同的名称。

Xamarin.Forms 也支持自定义标记扩展,但实现略有不同。 在 WPF 中,必须派生自 MarkupExtension - 它是一个抽象基类。 在 Xamarin.Forms 中,它被 IMarkupExtension 接口或更灵活的 IMarkupExtension<T> 接口取代。

与 WPF 一样,只需要 ProvideValue 方法,它用于从标记扩展返回值。

绑定基础结构

保留的核心概念之一是将视觉对象属性连接到 .NET 数据属性的数据绑定基础结构。 这可实现 MVVM 等体系结构模式。 基本设计是相同的 - 在 WPF 中有一个可绑定基类 BindableObject,这是 DependencyObject 类。 这个基类用作将作为目标参与数据绑定的所有对象的根上级。 然后,派生类公开 BindableProperty 对象,这些对象充当属性值的后备存储(这些对象在 WPF 中被定义为 的 DependencyProperty 对象)。

定义可绑定属性

Xamarin.Forms 中可绑定属性的定义与 WPF 中的相同:

  1. 此类型必须派生自 BindableObject
  2. 必须声明 BindableProperty 类型的公共静态字段来定义属性的后备存储密钥。
  3. 应该有一个公共实例属性包装器,该包装器使用 GetValueSetValue 来检索和更改属性值。

有关完整示例,请参阅 Xamarin.Forms 中的可绑定属性

附加属性

附加属性是可绑定属性的子集,它们的工作方式与在 WPF 中的工作方式相同。 主要区别是,在本例中省略了属性包装器,并在拥有类上替换为一组静态的 get/set 方法。 有关详细信息,请参阅 Xamarin.Forms 中的附加属性

使用绑定引擎

使用绑定引擎的过程与 WPF 中的相同。 要子啊代码隐藏中使用它,可以创建一个绑定到源对象的 Binding 对象(任何 .NET 类型)和一个可选属性值(如果省略,它将源对象视为属性本身,就像 WPF 一样)。 然后,你可以在任何 BindableObject 上使用 SetBinding 来将绑定关联到 BindableProperty

或者,可以使用 BindingExtension 在 XAML 中定义绑定关系。 它与 WPF 中的扩展具有相同的基本值。

与 WPF 相比,绑定支持和引擎更类似于 Silverlight 实现。 缺失几项功能,它们未在 Xamarin.Forms 中实现:

  • 绑定中不支持以下功能:
    • BindingGroupName
    • BindsDirectlyToSource
    • IsAsync
    • 多重绑定
    • NotifyOnSourceUpdated
    • NotifyOnTargetUpdated
    • NotifyOnValidationError
    • UpdateSourceTrigger
    • UpdateSourceExceptionFilter
    • ValidatesOnDataErrors
    • ValidatesOnExceptions
    • ValidationRules 集合
    • XPath
    • XmlNamespaceManager

RelativeSource

不支持 RelativeSource 绑定。 在 WPF 中,可通过它们绑定的到 XAML 中定义的其他可视元素。 在 Xamarin.Forms 中,可以使用 {x:Reference} 标记扩展实现相同的功能。 例如,假设我们有一个名为“otherControl”且具有 Text 属性的控件,我们可以按如下所示来绑定它:

WPF

Text={Binding RelativeSource={RelativeSource otherControl}, Path=Text}

Xamarin.Forms

Text={Binding Source={x:Reference otherControl}, Path=Text}

此功能可用于 {RelativeSource Self} 特性。 但是,不支持按类型查找上级 ({RelativeSource FindAncestor})。

绑定上下文

在 WPF 中,可以定义一个 DataContext 属性值,该值表示默认绑定源。 如果未定义绑定的源,则使用此属性值。 该值在可视化树中向下继承,这样就可在更高级别定义它,然后由子级使用。

在 Xamarin.Forms 中,此功能相同,但属性名称为 BindingContext

值转换器

就像 WPF 一样,Xamarin.Forms 中完全支持值转换器。 使用了相同的接口形状,但 Xamarin.Forms 在 Xamarin.Forms 命名空间中定义接口。

模型-视图-视图模型

WPF 和 Xamarin.Forms 都完全支持 MVVM。

WPF 包含内置的 RoutedCommand(有时会使用此功能);Xamarin.Forms 在 ICommand 接口定义之外没有内置命令支持。 可包含各种 MVVM 框架,以添加实现 MVVM 所需的基类。

INotifyPropertyChanged 和 INotifyCollectionChanged

Xamarin.Forms 绑定完全支持这两个接口。 与许多基于 XAML 的框架不同,可以在 Xamarin.Forms中的后台线程上触发属性更改通知(这一点与 WPF 相同),并且绑定引擎将正确转换为 UI 线程。

此外,环境支持 SynchronizationContextasync/await 来执行适当的线程封送。 WPF 在所有可视元素上包含 Dispatcher 类,Xamarin.Forms 具有一种静态方法 Device.BeginInvokeOnMainThread(虽然 SynchronizationContext 是跨平台编码的首选方法,但也可使用此方法)。

  • Xamarin.Forms 包含 ObservableCollection<T>,它支持集合更改通知。
  • 可使用 BindingBase.EnableCollectionSynchronization 为集合启用跨线程更新。 API 与 WPF 变体略有不同,请查看文档了解使用情况详细信息

数据模板

Xamarin.Forms 支持数据模板以自定义 ListView 行(单元格)的呈现。 WPF 可对任何面向内容的控件使用 DataTemplate,与它不同,Xamarin.Forms 目前仅对 ListView 使用它们。 可内联定义模板定义(分配给 ItemTemplate 属性),也可将它定义为 ResourceDictionary 中的资源。

此外,它们不像 WPF 等效功能那样灵活。

  1. DataTemplate 的根元素必须始终是一个 ViewCell 对象。
  2. 数据模板中完全支持数据触发器,但这些触发器必须包含一个 DataType 属性,该属性指示与触发器关联的属性的类型。
  3. 还支持 DataTemplateSelector,但它派生自 DataTemplate,并因此直接分配给 ItemTemplate 属性(在 WPF 中则分配给 ItemTemplateSelector)。

ItemsControl

没有与 Xamarin.Forms 中的 ItemsControl 等效的内置功能;但此处提供的 Xamarin.Forms 有一个自定义功能

用户控件

在 WPF 中,UserControl 用于提供具有关联行为的 UI 部分。 在 Xamarin.Forms 中,我们使用 ContentView 来实现这一点。 在 XAML 中,这两者都支持绑定和包含。

WPF 包含很少使用的 NavigationService,它可用于提供“类似浏览器”的导航功能。 但是,大多数应用不担心这一点,而是使用了不同的 Window 元素或者窗口的不同部分来显示数据。

在手机设备上,解决方案通常是使用不同的屏幕,因此 Xamarin.Forms 包括对多种导航形式的支持:

导航样式 页面类型
基于堆栈(推送/弹出) NavigationPage
母版/详细信息 MasterDetailPage
选项卡 TabbedPage
向左/向右轻扫 CarouselView

NavigationPage 是最常见的方法,每个页面都有一个 Navigation 属性,可用于在导航堆栈上推送或弹出页面以及让页面消失。 这是与 WPF 中找到的 NavigationService 最接近的等效项。

URL 导航

WPF 是一种面向桌面的技术,可以接受命令行参数来定向启动行为。 Xamarin.Forms 在启动时可以使用 深层 URL 链接跳转到页面。