C# WPF MVVM开发框架Caliburn.Micro 关于Conventions⑧

2022-01-13 08:53:52 浏览数 (1)

01

关于Conventions

Caliburn.Micro的一个主要特性是,它能够通过一系列约定消除对锅炉铭牌代码的需求。有些人喜欢习俗,有些人讨厌习俗。这就是为什么CM的约定是完全可定制的,如果不需要,甚至可以完全关闭。如果您要使用约定,并且由于它们在默认情况下处于启用状态,那么最好了解这些约定是什么以及它们是如何工作的。这就是本文的主题。

View Resolution (ViewModel-First)

视图分辨率(视图模型优先)

基础

使用CM时可能遇到的第一个约定与视图分辨率有关。此约定影响应用程序的任何ViewModel优先区域。在ViewModel First中,我们有一个需要渲染到屏幕上的现有ViewModel。为此,CM使用一个简单的命名模式来查找UserControl1,它应该绑定到ViewModel并显示它。那么,这种模式是什么?让我们看一下ViewLocator.LocateForModelType以了解:

代码语言:javascript复制
public static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) =>{
    var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
    if(context != null)
    {
        viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
        viewTypeName = viewTypeName   "."   context;
    }

    var viewType = (from assmebly in AssemblySource.Instance
                    from type in assmebly.GetExportedTypes()
                    where type.FullName == viewTypeName
                    select type).FirstOrDefault();

    return viewType == null
        ? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
        : GetOrCreateViewType(viewType);
};

让我们先忽略“context”变量。为了导出视图,我们假设您在vm的命名中使用了文本“ViewModel”,因此我们只需通过删除单词“Model”将其更改为“view”。这具有更改类型名称和名称空间的效果。因此ViewModels.CustomerViewModel将成为Views.CustomerView。或者,如果您是按功能组织应用程序:CustomerManagement.CustomerServiceWModel变为CustomerManagement.CustomerView。希望这是非常直截了当的。获得名称后,我们将搜索具有该名称的类型。我们将通过AssemblySource.Instance搜索您向CM公开的任何程序集。2如果我们找到类型,我们将创建一个实例(如果已注册,则从IoC容器中获取一个实例),并将其返回给调用方。如果找不到类型,我们将生成一个带有适当“not found”消息的视图。

现在,回到“上下文”值。这就是CM如何支持同一ViewModel上的多个视图。如果提供了上下文(通常是字符串或枚举),我们将根据该值对名称进行进一步转换。通过从末尾删除单词“View”并附加上下文,此转换有效地假设您拥有用于不同视图的文件夹(命名空间)。因此,给定“Master”上下文,我们的ViewModels.CustomerViewModel将变成Views.Customer.Master。

其他需要知道的事情

除了实例化视图外,GetOrCreateViewType还将在视图上调用InitializeComponent(如果存在)。这意味着,对于由ViewLocator创建的视图,根本不需要代码落后。如果这让您感到高兴,您可以删除它们:)您还应该知道ViewLocator.LocateForModelType从不直接调用。它总是通过ViewLocator.LocateForModel间接调用。LocateForModel获取ViewModel的实例并返回视图的实例。LocateForModel的功能之一是检查ViewModel是否实现了IViewAware。如果是这样,它将调用它的GetView方法来查看您是否有缓存的视图,或者是否显式地处理视图创建。如果不是,则将ViewModel的类型传递给LocateForModelType。

定制

开箱即用的约定非常简单,它基于我们在现实世界中使用过和看到其他人使用过的许多模式。然而,您绝不局限于这些简单的模式。您会注意到上面讨论的所有方法都是作为Funcs实现的,而不是实际的方法。这意味着您可以通过简单地用自己的实现替换它们来定制它们。如果只想添加到现有行为,只需将现有Func存储在变量中,创建一个调用旧函数的新Func,然后将新Func分配给ViewLocator.LocateForModelType。

v1.1的更改v1.1中我们完全更改了LocateForModelType函数的实现。现在,我们使用新的NameTransformer类的一个实例以及预先配置的基于RexEx的规则来进行名称映射。我们支持与以前相同的现成约定,但现在您可以更轻松地添加自定义转换规则。

框架使用

框架使用ViewLocator的地方有三个;您可以期望应用视图位置约定的三个位置。第一名是Bootstrapper。在这里,您的根ViewModel被传递给定位器,以确定应用程序的shell应该如何呈现。在Silverlight中,这将导致设置或您的RootVisual。在WPF中,这将创建主窗口。事实上,在WPF中,引导程序将此委托给WindowManager,这使我想到……ViewLocator使用的第二个位置是WindowManager,它调用它来确定任何对话框ViewModels应如何呈现。利用这些约定的第三个也是最后一个地方是View.Model attached属性。每当您使用UIElement上的View.Model attached属性进行ViewModel首次合成渲染时,都会调用定位器以查看合成的ViewModel应如何在UI中的该位置进行渲染。您可以在UI中显式使用View.Model attached属性(可以选择将其与View.Context attached属性组合以进行上下文呈现),也可以按约定添加该属性,从而实现视图的常规组合。请参阅下面关于属性绑定约定的部分。

ViewModel Resolution (View-First)

视图模型分辨率(视图优先)

基础

尽管Caliburn.Micro更喜欢ViewModel-First开发,但有时您可能希望采用视图优先的方法,尤其是在使用WP7时。如果从视图开始,则可能需要解析ViewModel。我们在这个场景中使用了与视图位置类似的命名约定。这由ViewModelLocator.LocateForViewType处理。当使用视图位置时,我们将“ViewModel”的实例更改为“View”,而使用ViewModel位置时,我们将“View”更改为“ViewModel”。另一个有趣的区别在于我们如何获得ViewModel本身的实例。由于ViewModels可能由接口或具体类注册,因此我们也尝试生成可能的接口名称。如果我们找到匹配项,我们将从IoC容器中解析它。

其他需要知道的事情

实际上,框架从未直接调用ViewModelLocator.LocateForViewType。它由ViewModelLocator.LocateForView在内部调用。LocateForView首先检查视图实例的DataContext,查看您以前是否缓存或自定义创建了ViewModel。如果DataContext为null,则只有在该情况下才会调用LocateForViewType。最后要注意的是,自动初始化组件调用在性质上不受view first支持。

定制

在v1.1中,我们完全改变了LocateForViewType函数的实现。现在,我们使用新的NameTransformer类的一个实例以及预先配置的基于RexEx的规则来进行名称映射。我们支持与以前相同的现成约定,但现在您可以更轻松地添加自定义转换规则。

框架使用

ViewModelLocator仅由框架的WP7版本使用。FrameAdapter使用它,它确保每次导航到页面时,都提供了正确的ViewModel。如果需要的话,它可以很容易地适应Silverlight导航框架的使用。

ViewModelBinder

基础

当我们将视图和ViewModel绑定在一起时,无论是使用ViewModel优先还是视图优先方法,都会调用ViewModelBinder.bind方法。此方法将视图的Action.Target设置为ViewModel,并相应地将DataContext设置为相同的值。4它还检查ViewModel是否实现了IViewAware,如果实现了,则将视图传递给ViewModel。如果更适合您的场景,这将允许更具监督性的控制器样式设计。ViewModelBinder所做的最后一件重要事情是确定是否需要创建任何常规属性绑定或操作。为此,它在UI中搜索绑定/操作的候选元素列表,并将其与ViewModel的属性和方法进行比较。当找到匹配项时,它将代表您创建绑定或操作。

其他需要知道的事情

在所有平台上,约定都不能应用于DataTemplate的内容。这是Xaml模板系统的当前限制。我已经要求微软解决这个问题,但我怀疑他们是否会回应。因此,为了将绑定和操作约定应用于DataTemplate,必须将Bind.Model=“{Binding}”附加属性添加到DataTemplate内的根元素。这为Caliburn.Micro提供了必要的钩子,以便在每次从DataTemplate实例化UI时应用其约定。

在WP7平台上,如果要绑定的视图是PhoneApplicationPage,则此服务负责将操作连接到ApplicationBar的按钮和菜单。有关这方面的更多信息,请参阅WP7特定文档。

定制

如果您决定不喜欢ViewModelBinder的行为(更多细节见下文),它将遵循与上述框架服务相同的模式。它有几个函数,您可以用自己的实现来替换,例如Bind、BindActions和BindProperties。不过,定制最重要的方面可能是能够关闭活页夹的约定功能。为此,请将ViewModelBinder.ApplyConventionsByDefault设置为false。如果要逐个视图启用它,可以在视图中将view.ApplyConventions attached属性设置为true。此附加属性以两种方式工作。因此,如果默认情况下启用了约定,但需要逐个视图将其禁用,则只需将此属性设置为false。

框架使用

ViewModelBinder用于Caliburn.Micro内部的三个位置。第一个位置是View.Model附加属性的实现内部。此属性获取您的ViewModel,使用ViewLocator定位视图,然后将它们一起传递到ViewModelBinder。绑定完成后,视图被注入到定义属性的元素中。这是ViewModel的第一个使用模式。使用ViewModelBinder的第二个位置是Bind.Model attached属性的实现内部。此属性获取ViewModel并将其与定义该属性的元素一起传递到ViewModelBinder。换言之,这是视图优先,因为您已经在Xaml中内联实例化了视图,然后只是针对ViewModel调用绑定。使用ViewModelBinder的最后一个位置是框架的WP7版本。在FrameAdapter内部,当页面被导航到时,首先使用ViewModelLocator获取该页面的ViewModel。然后,使用ViewModelBinder将ViewModel连接到页面。

Element Location

基础

现在,您已经了解了ViewModelBinder的基本角色以及框架使用它的位置,我想深入了解它如何应用约定的细节。如上所述,ViewModelBinder“在UI中搜索绑定/操作的候选元素列表,并将其与ViewModel的属性和方法进行比较。”了解其工作原理的第一步是了解框架如何确定UI中哪些元素可能是约定的候选元素。它通过在名为GetNamedElementsInScope的静态ExtensionMethods类上使用func来实现这一点。5基本上,该方法有两个功能。首先,它确定了要在其中搜索元素的范围。这意味着它将遍历树,直到找到合适的根节点,例如窗口、UserControl或没有父节点的元素(表示我们在DataTemplate中)。一旦定义了作用域的“外部”边界,它就开始了第二项任务:定位该作用域中具有名称的所有元素。搜索会小心地遵守“内部”范围边界,不遍历子用户控件的内部。然后,ViewModelBinder使用此函数返回的元素应用约定。

其他需要知道的事情

GetNamedElementsInScope方法可以完成一些开箱即用的限制。它只能搜索可视化树ContentControl.Content和ItemsControl.Items。在WPF中,它还搜索HeaderContentControl.Header和HeaderEditsControl.Header。这意味着,当尝试应用约定时,将找不到上下文菜单、工具提示或任何其他不在可视化树中或这些特殊位置之一的内容。

定制

您可能不会遇到与上述元素位置限制相关的问题。但是如果您这样做了,您可以轻松地用自己的实现替换默认实现。您可能会选择使用以下一种有趣的技术:如果视图是用户控件或窗口,则不必遍历元素树,而是使用一些反射来发现从FrameworkElement继承的所有私有字段。我们知道,在编译Xaml文件时,会为所有具有x:Name的文件创建一个私有字段。利用这个优势。不过,您必须回到DataTemplateUI的现有实现。我不提供这种开箱即用的实现,因为它不能保证在Silverlight中成功。原因是Silverlight不允许您获取私有字段的值,除非调用代码是定义字段的代码。但是,如果所有视图都是在单个程序集中定义的,那么可以通过在与视图相同的程序集中创建新实现来轻松地进行我刚才描述的修改。此外,如果您有一个多程序集项目,您可以编写一点管道代码,让GetNamedElementsInScope funct找到可以实际执行反射的特定于程序集的实现。

框架使用

我已经提到,当ViewModelBinder尝试按约定绑定属性或方法时,会出现元素位置。但是,还有第二个地方使用此功能:解析器。每当您使用Message.Attach并且您的操作包含参数时,消息解析器必须找到您用作参数输入的元素。看起来我们可以只做一个简单的FindName,但是FindName是区分大小写的。因此,我们必须使用自定义实现,它执行不区分大小写的搜索。这确保了在两个地方使用相同的绑定语义。

Action Matching

基础

在找到约定绑定的元素后,ViewModelBinder要做的下一件事是检查它们是否与ViewModel上的方法匹配。它通过使用一些反射来获得ViewModel的公共方法来实现这一点。然后它在它们上面循环,寻找与元素匹配的不区分大小写的名称。如果找到匹配项,并且元素上没有任何预先存在的Interaction.Triggers,则会附加一个操作。检查预先存在的触发器用于防止约定系统创建与开发人员在标记中明确声明的操作重复的操作。为了安全起见,如果您在匹配的元素上声明了任何触发器,那么将跳过它。

其他需要知道的事情

常规操作是通过在元素上设置Message.Attach attached属性创建的。让我们看看这是如何建立起来的:

代码语言:javascript复制
var message = method.Name;
var parameters = method.GetParameters();

if(parameters.Length > 0)
{
    message  = "(";

    foreach(var parameter in parameters)
    {
        var paramName = parameter.Name;
        var specialValue = "$"   paramName.ToLower();

        if(MessageBinder.SpecialValues.Contains(specialValue))
            paramName = specialValue;

        message  = paramName   ",";
    }

    message = message.Remove(message.Length - 1, 1);
    message  = ")";
}

Log.Info("Added convention action for {0} as {1}.", method.Name, message);
Message.SetAttach(foundControl, message);

如您所见,我们构建了一个表示消息的字符串。此字符串仅包含消息的操作部分;未声明任何事件。您还可以看到,它循环遍历方法的参数,以便将它们包含在操作中。如果参数名与一个特殊的参数值相同,我们确保将“$”附加到它,以便解析器能够正确识别它,之后调用操作时MessageBinder能够正确识别它。

设置Message.Attach属性后,解析器立即启动,将字符串消息转换为某种类型的TriggerBase,其中包含关联的ActionMessage。因为我们没有将事件声明为消息的一部分,所以解析器会查找消息所附加到的元素类型的默认触发器。例如,如果消息被附加到一个按钮,那么我们将得到一个EventTrigger,其事件设置为Click。此信息通过ConventionManager配置,具有合理的现成默认值。请参阅下面有关ConventionManager和ElementConventions的部分以了解更多信息。ElementConvention用于创建触发器,然后解析器将操作信息转换为ActionMessage。这两个元素连接在一起,然后添加到Interaction.Triggers元素的集合中。

定制

ViewModelBinder.BindActions是一个Func,因此如果需要,可以完全替换。通过ConventionManager添加或更改ElementConventions也会影响操作的组合方式。下面将详细介绍。

框架使用

BindActions仅由ViewModelBinder使用。

Property Matching

基础

一旦动作绑定完成,我们就转到属性绑定。它遵循类似的过程,在命名元素中循环,并在属性上查找不区分大小写的名称匹配项。一旦找到匹配项,我们就可以从ConventionManager获取ElementConventions,这样我们就可以确定该元素上的数据绑定方式。ElementConvention定义了一个ApplyBinding Func,它接受视图模型类型、属性路径、属性信息、元素实例和约定本身。此Func负责使用提供的所有上下文信息在元素上创建绑定。最妙的是,如果需要,我们可以为每个元素定制绑定行为。CM为ConventionManager上的大多数元素定义了ApplyBinding的基本实现。这叫做挫折,看起来像这样:

代码语言:javascript复制
public static Func<Type, string, PropertyInfo, FrameworkElement, ElementConvention, bool> SetBinding =
    (viewModelType, path, property, element, convention) => {
        var bindableProperty = convention.GetBindableProperty(element);
        if(HasBinding(element, bindableProperty))
            return false;

        var binding = new Binding(path);

        ApplyBindingMode(binding, property);
        ApplyValueConverter(binding, bindableProperty, property);
        ApplyStringFormat(binding, convention, property);
        ApplyValidation(binding, viewModelType, property);
        ApplyUpdateSourceTrigger(bindableProperty, element, binding);

        BindingOperations.SetBinding(element, bindableProperty, binding);

        return true;
    };

此方法所做的第一件事是通过调用ElementConvention上的GetBindableProperty来获取应该绑定的依赖项属性。接下来,我们检查该属性是否已经存在绑定集。如果有,我们不想覆盖它。开发人员可能在这里做了一些特殊的事情,因此我们返回false,表示尚未添加绑定。假设不存在绑定,该方法基本上会委托ConventionManager上的其他方法来获取绑定应用程序的详细信息。希望这一部分有意义。一旦绑定被完全构造,我们将其添加到元素中,并返回true,指示应用了约定。

属性匹配还有另一个重要方面,我还没有提到。我们也可以通过约定在深层属性路径上进行匹配。因此,假设您的ViewModel上有一个Customer属性,它有一个FirstName属性,您希望将文本框绑定到该属性。只需给文本框一个x:Name“Customer_FirstName”,ViewModelBinder将完成所有工作以确保该属性有效,并将正确的视图模型类型、属性信息和属性路径传递给ElementConvention的ApplyBinding函数。

其他需要知道的事情

我在上面提到,“CM为大多数元素定义了ApplyBinding的基本实现。”它还为通常与特定使用模式或组合关联的元素定义了ApplyBinding Func的几个自定义实现。对于WPF和Silverlight,ItemsControl和Selector具有自定义绑定行为。除了在ItemsControl上绑定ItemsSource外,ApplyBinding函数还检查ItemTemplate、DisplayMemberPath和ItemTemplateSelector(WPF)属性。如果这些都没有设置,那么框架就会知道,由于您没有为项目指定呈现器,它应该按常规添加一个。7因此,我们将ItemTemplate设置为默认DataTemplate。下面是它的样子:

代码语言:javascript复制
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro">
    <ContentControl cal:View.Model="{Binding}" 
                    VerticalContentAlignment="Stretch"
                    HorizontalContentAlignment="Stretch" />
</DataTemplate>

由于此模板创建了一个带有View.Model附加属性的ContentControl,因此我们为ItemsControl创建了丰富组合的可能性。因此,无论项目是什么,View.Model attached属性都允许我们调用ViewModel First工作流:找到项目的视图,将项目和视图传递给ViewModelBinder(ViewModelBinder反过来设置自己的约定,可能会调用更多组合),然后获取视图并将其注入ContentControl。选择器的行为与ItemsControl相同,但在SelectedItem属性周围有一个附加约定。假设您的选择器称为Items。我们首先遵循上述约定,将ItemsSource绑定到Items,并检测是否需要添加默认的DataTemplate。然后,检查SelectedItem属性是否已绑定。如果没有,我们将在ViewModel上查找可以绑定到SelectedItem的三个候选属性:ActiveItem、SelectedItem和CurrentItem。如果找到其中一个,我们将添加绑定。因此,这里的模式是,我们首先调用ConventionManager.Singularize来指定集合属性的名称。在这种情况下,“Items”变为“Item”,然后我们称ConventionManager.DerivePotentialSelectionNames,它在“Active”、“Selected”和“Current”前面加上“Active”和“Current”以使上述三个候选项成为“Item”。然后,如果在ViewModel上找到其中一个,我们将创建一个绑定。对于WPF,我们为TabControl提供了一个特殊的ApplyBinding行为。8它采用选择器的所有约定(将其ContentTemplate而不是ItemTemplate设置为DefaultDataTemplate),并为选项卡标题的内容提供了一个附加约定。如果未设置TabControl的DisplayMemberPath,并且ViewModel实现IHaveDisplayName,则我们将其ItemTemplate设置为DefaultHeaderTemplate,如下所示:

代码语言:javascript复制
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <TextBlock Text="{Binding DisplayName, Mode=TwoWay}" />
</DataTemplate>

因此,对于命名的WPF TabControl,我们可以常规地在选项卡列表(ItemsSource)中绑定选项卡项的名称(ItemTemplate)、每个选项卡的内容(ContentTemplate),并保持所选选项卡与模型同步(SelectedItem)。对于这样一行Xaml来说,这还不错:

代码语言:javascript复制
<TabControl x:Name="Items" />

除了上面列出的特殊情况外,我们还有一个很重要的问题:ContentControl。在本例中,我们不提供自定义ApplyBinding函数,但提供自定义GetBindableProperty函数。对于ContentControl,当我们决定绑定到哪个属性时,我们检查ContentTemplate和ContentTemplateSelector(WPF)。如果它们都为null,则表示尚未为模型指定渲染器。因此,我们假设您希望使用ViewModel First工作流。我们通过让GetBindableProperty函数返回View.Model attached属性作为要绑定的属性来实现这一点。在所有其他情况下,ContentControl将绑定到Content属性。通过在没有ContentTemplate的情况下选择View.Model属性,我们可以实现丰富的合成。

我希望当你思考这些特殊情况时,你会发现它们是有道理的。一如既往,如果你不喜欢它们,你可以改变它们…

定制

正如您所想象的,通过替换ViewModelBinder上的Func,BindProperties功能完全可以自定义。例如,如果你喜欢动作约定而不是属性约定,你可以用一个不做任何事情的Func替换这个Func。然而,您可能需要更细粒度的控制。幸运的是,ConventionManager或特定ElementConvention的几乎每个方面都是可定制的。有关ConventionManager的更多详细信息如下。

配置约定的常用方法之一是向系统中添加新约定。最常见的情况是添加Silverlight toolkit控件或WP7 toolkit控件。下面是一个示例,说明如何为WP7 Pivot控件设置一个高级约定,使其与WPF TabControl类似:

代码语言:javascript复制
ConventionManager.AddElementConvention<Pivot>(Pivot.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =
    (viewModelType, path, property, element, convention) => {
        ConventionManager
            .GetElementConvention(typeof(ItemsControl))
            .ApplyBinding(viewModelType, path, property, element, convention);
        ConventionManager
            .ConfigureSelectedItem(element, Pivot.SelectedItemProperty, viewModelType, path);
        ConventionManager
            .ApplyHeaderTemplate(element, Pivot.HeaderTemplateProperty, viewModelType);
    };

很酷吧?

框架使用

BindProperties仅由ViewModelBinder使用。

会议经理

如果您已经阅读了本文,您就会知道ConventionManager在很大程度上受到操作和属性绑定机制的影响。它是微调框架中大多数约定行为的网关。以下是可用于自定义框架约定的可替换函数和属性的列表:

性质

BooleantVisibilityConverter–用于将布尔值转换为可见性并返回的默认IValueConverter。由ApplyValueConverter使用。

IncludeStaticProperties-指示在约定名称匹配期间是否应包括静态属性。默认情况下为False。

DefaultItemTemplate–当ItemsControl或ContentControl需要DataTemplate时使用。

DefaultHeaderTemplate–当TabControl需要标题模板时,由ApplyHeaderTemplate使用。

芬克斯

单数化–将单词从复数形式转换为单数形式。默认的实现是非常基本的,只是去掉了后面的's'。

DerivePotentialSelectionNames–给定基本集合名称,返回表示所选内容的可能属性名称列表。使用Singularize。

SetBinding–ElementConventions使用的ApplyBinding的默认实现(更多信息见下文)。更改此选项将更改所有常规绑定的应用方式。在内部使用以下函数:

HasBinding—确定特定依赖项属性是否已在提供的元素上具有绑定。如果绑定已存在,则SetBinding将中止。

ApplyBindingMode-将适当的绑定模式应用于绑定。

ApplyValidation—确定是否以及在绑定上启用何种类型的验证。

ApplyValueConverter-确定是否需要值转换器,并将其应用于绑定。默认情况下,它仅检查BooleanToVisibility转换。

ApplyStringFormat-确定是否需要自定义字符串格式并将其应用于绑定。默认情况下,如果绑定到日期时间,则使用格式“{0:MM/dd/yyyy}”。

ApplyUpdateSourceTrigger-确定是否应将自定义更新源触发器应用于绑定。对于WPF,始终设置为UpdateSourceTrigger=PropertyChanged。对于Silverlight,调用ApplySlverLightTriggers。

例如,让ChangeConventionManager.Singularize使用令人敬畏的库人性化工具。

代码语言:javascript复制
ConventionManager.Singularize = original => original.Singularize(inputIsKnownToBePlural: false);

方法

AddElementConvention–添加或替换ElementConvention。

GetElementConvention–获取特定元素类型的约定。如果未找到,则在类型层次结构中搜索匹配项。

ApplyHeaderTemplate–将标头模板约定应用于元素。

ApplySlverLightTriggers–对于TextBox和PasswordBox,将适当的事件连接到绑定更新,以模拟WPF的UpdateSourceTrigger=PropertyChanged。

ElementConvention

元素约定

可以通过ConventionManager.AddElementConvention添加或替换元素约定。但是,了解这些约定是什么以及在整个框架中如何使用它们是很重要的。在本文的最底部是一个代码列表,它显示了如何开箱即用地配置所有元素。以下是ElementConvention类的属性和函数以及简要说明:

Properties

ElementType–约定适用的元素类型。

ParameterProperty–使用Message.Attach声明操作时,如果指定了引用元素的参数,但未指定该元素的属性,则将查找ElementConvention并使用ParameterProperty。例如,如果我们有此标记:

代码语言:javascript复制
<TextBox x:Name="something" />
<Button cal:Message.Attach="MyMethod(something)" />

当按钮的ActionMessage被创建时,我们会查找“某物”,这是一个文本框。我们得到TextBox的ElementConvention,它的ParameterProperty设置为“Text”。因此,我们从something.Text创建MyMethod的参数。

芬克斯

GetBindableProperty–获取应在约定绑定中使用的元素的属性。

CreateTrigger–当Message.Attach用于声明操作,且未指定特定事件时,将查找ElementConvention并调用CreateTrigger Func来创建Interaction.Trigger。例如,在上面的Xaml中,当为按钮创建ActionMessage时,将查找按钮的ElementConvention并调用其CreateTrigger函数。在这种情况下,ElementConvention返回一个配置为使用Click事件的EventTrigger。

ApplyBinding–如上所述,当发生常规数据绑定时,我们正在绑定的元素将查找其ElementConvention,并调用其ApplyBinding func。默认情况下,这只传递给ConventionManager.SetBinding。但某些元素(见上文…或下文)对此进行了定制,以实现更强大的合成场景。

ConventionManager上有一个名为AddElementConvention的助手方法,可以这样使用:

代码语言:javascript复制
ConventionManager.AddElementConvention<Rating>(Rating.ValueProperty, "Value", "ValueChanged");

在上述情况下,Rating.ValueProperty的第一个参数值告诉约定系统元素的默认可绑定属性是什么。因此,如果我们在评级控件上有一个约定匹配,我们将针对ValueProperty设置绑定。第二个参数表示要在操作绑定中使用的默认属性。因此,如果您使用指向分级控件的ElementName创建了一个操作绑定,但没有指定属性,那么我们将返回到“Value”属性。最后,第三个参数表示控件的默认事件。因此,如果我们将操作附加到评级控件,但没有指定触发该操作的事件,则系统将退回到“ValueChanged”事件。这些元素约定允许开发人员在各种情况下提供尽可能多或尽可能少的信息,允许框架适当地填充缺少的细节。

02

最后

原文标题:Caliburn.Micro Xaml made easy

原文链接:https://caliburnmicro.com/documentation/conventions

翻译:dotnet编程大全

0 人点赞