WPF 与Xamarin.Forms:共性与差异
控件模板
WPF 支持控件模板的概念,该概念为控件(Button
、ListBox
等)提供可视化说明。 如上所述,Xamarin.Forms 对此内容使用具体的渲染类,这些类与本机平台(iOS、Android 等)交互来可视化控件。
但是,Xamarin.Forms 确实有一个 ControlTemplate
类型 - 它用于设置 Page
对象的主题。 它为 Page
提供了一个定义,该定义提供一致的内容,但允许页面用户更改颜色和字体等,甚至添加元素来使其对应用程序具有唯一性。
它的常见用法包括身份验证对话框、提示,还包括提供一个标准化的但可在应用中自定义的可主题化页面外观。 作为这种支持的一部分,使用了许多熟悉的 WPF 命名控件:
ContentPage
ContentView
ContentPresenter
TemplateBinding
但是,必须知道这些功能在 Xamarin.Forms 中不会起到相同的作用。 若要详细了解此功能,请参阅文档页。
XAML
XAML 用作 WPF 和 Xamarin.Forms 的声明性标记语言。 在大多数情况下,语法是相同的,主要区别是 XAML 图形定义/创建的对象。
Xamarin.Forms 支持 XAML 2009 规范;这使得能够更加轻松地定义数据(例如
string
、int
等),还能更容易地定义泛型类型和将参数传递给构造函数。目前无法像 WPF 使用
XamlReader
加载 XAML 一样动态加载 XAML。 不过,可以使用 NuGet 包获取相同的基本功能。
标记扩展
Xamarin.Forms 支持通过标记扩展来扩展 XAML,这与 WPF 非常类似。 此功能开箱即用,具有相同的基本构建基块:
{x:Array}
{Binding}
{DynamicResource}
{x:Null}
{x:Static}
{StaticResource}
{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 中的相同:
- 此类型必须派生自
BindableObject
。 - 必须声明
BindableProperty
类型的公共静态字段来定义属性的后备存储密钥。 - 应该有一个公共实例属性包装器,该包装器使用
GetValue
和SetValue
来检索和更改属性值。
有关完整示例,请参阅 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 线程。
此外,环境支持 SynchronizationContext
和 async
/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 等效功能那样灵活。
DataTemplate
的根元素必须始终是一个ViewCell
对象。- 数据模板中完全支持数据触发器,但这些触发器必须包含一个
DataType
属性,该属性指示与触发器关联的属性的类型。 - 还支持
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 链接跳转到页面。