《Programming WPF》翻译 第9章 4.模板

简介: 原文:《Programming WPF》翻译 第9章 4.模板对一个自定义元素最后的设计考虑是,它是如何连接其可视化的。如果一个元素直接从FrameworkElement中派生,这将会适当的生成它自己的可视化。
原文: 《Programming WPF》翻译 第9章 4.模板

对一个自定义元素最后的设计考虑是,它是如何连接其可视化的。如果一个元素直接从FrameworkElement中派生,这将会适当的生成它自己的可视化。(第7章描述了如何创建一个图形外观。)尤其是,如果你创建了一个元素,是为了提供一个特定的可视化表现,该元素应该完全控制这个可视化是如何管理的,一旦你编写了一个控件,通常你不会将一个图形硬编码到里面。

记住,一个控件的工作是提供行为。可视化是由控件模板提供的。这种可视化是由控件模板提供的。一个控件可能提供一组默认的可视化,而应允许这些可视化被替换,为了提供像内迁控件一样的弹性。(第五章描述了如何使用模板替换一个控件的可视化)符合这种方法的控件,这里可视化从控件中分离出来,通常引用到一个没有外观的控件。所有内迁到WPF的控件都是没有外观的。

当然,控件完全独立于其可视化是不可能的。任何控件将对模板必须满足的需求施加影响,如果控件操作正确。这些需求的程度随控件不同而不同。例如,Button有一个相当简单的需求——仅仅需要一个占位符放置标题或内容。Slider控件需要更广泛的需求:可视化必须提供两个按钮(增加和减少),“Thumb”,以及运行时Thumb上的一个跟踪。此外,它还需要能够响应点击和拖动在这些元素的任意一个,以及能够定位这个Thumb

在任意控件类型和样式或模板之间有一个隐式的约定。这个控件允许它的外观通过替换可视化树的方式进行自定义,但是这棵树必须轮流提供代表这棵树的某些特征。这个约定的本性依赖于这个控件,内嵌控件使用一些不同的样式,紧紧依赖于它们的可视化结构。下面的部分描述了很多将控件与其模板联系在一起的方式

 

9.4.1属性别名

控件和模板间最松散的约定形式是控件简单的定义了公有属性,以及允许模板来决定哪一个属性在别名中可见。(参见第5章获取更多属性别名的信息。)这个控件并不关心

在控件中是什么。

这里有一个单行的约定:控件提供属性和命令,不需要返回值。尽管如此,如果必要的话,这样的控件仍能响应用户输入。事件路由允许事件从可视化向上冒泡到控件。控件能够处理这些事件而不需要知道任何关于可视化本性的信息。

为了支持这个模型,你所要做的是,使用本章先前描述的依赖属性机制,来实现这些属性。示例9-11显示了一个自定义控件,并且定义了一个单独的名为Foo的依赖属性,Brush类型。

依赖属性支持这个控件的用户在模板中提及,正如示例9-12所示。

示例9-12

< ControlTemplate  TargetType =" {x:Type local:MyCustomControl} " >
    
< Grid >
        
< Rectangle  Fill =" {TemplateBinding Foo} "   />
    
</ Grid >
</ ControlTemplate >


所有的依赖属性自动支持属性别名。这种情形下的“约定”是由一组你的控件提供的依赖属性暗示的。

9.4.2占位符

一些控件希望在模板中找到一个特定的占位符元素。这将要么采取该元素指定类型的形式,或者可以是一个元素标记了一个特定的属性。

控件通过派生于ContentControl支持内容模板,使用元素类型的方法。它们希望在模板中找到一个ContentPresenter元素。这是一个特殊意图的元素,它的工作是在其他内容中担当一个占位符。

实际上,这是一个松散的强迫性的约定。如果模板中没有ContentPresenterContentControl通常不会申诉。控件并不绝对依赖于表现的内容,为了放在那里起作用。或者你能到达另一个极端,以及放一些ContentPresenter在你的模板中,可以使子内容多次出现。

你不需要做任何特殊的事情来支持ContentPresenter的使用,只要你派生于ContentControl,它可以很好的工作。控件的用户能够编写一个模板,正如示例9-13所示。

示例9-13

 

< ControlTemplate  TargetType =" {x:Type local:MyContentControl} " >
    
< Grid >
        
< Rectangle  Fill ="White"   />
        
< ContentPresenter  />
    
</ Grid >
</ ControlTemplate >

9.4.3通过属性指定占位符

一些控件寻找用一个特定属性标记的元素。例如,派生于ItemsControl的控件,如ListBoxMenuItem,希望模板包括一个带有Panel.IsItemsHost属性设为true的元素。这标志了Panel将要扮演控件数据项目的宿主。ItemCOntrol使用附属属性取代占位符的原因是,允许你决定使用什么类型的Panel,作为数据项的宿主。(ItemControl还支持ItemsPresenter占位符元素的使用。这将使用于当样式不希望利用特定的panel类型的时候以及想要使用无论控件的默认panel是什么的时候)

为了实现使用此技术的控件,你需要定义一个自定义附属依赖属性,将其应用到占位符。这是一个Boolean属性。示例9-14注册了这样一个附属属性,并定义了通常的访问器功能。

示例9-14

public   class  ControlWithPlaceholder : Control  {
    
public static DependencyProperty IsMyPlaceholderProperty;

    
static ControlWithPlaceholder( ) {

        PropertyMetadata 
 isMyPlaceholderMetadata 
= new PropertyMetadata(false,
            
new PropertyInvalidatedCallback 
(OnIsMyPlaceholderChanged));

        IsMyPlaceholderProperty 
= DependencyProperty.RegisterAttached(
            
"IsMyPlaceholder"typeof(bool),
            
typeof(ControlWithPlaceholder), isMyPlaceholderMetadata);
    }


    
public static bool GetIsMyPlaceholder(DependencyObject target) {
        
return (bool) target.GetValue(IsMyPlaceholderProperty);
    }

    
public static void SetIsMyPlaceholder(DependencyObject target, bool value) {
        target.SetValue(IsMyPlaceholderProperty, value);
    }


注意到示例

9-14 PropertyMetaData 提供了一个PropertyInvalidatedCallBack 。这指示了一个可以在任意时间调用的方法,这个附属属性可以在任意元素上被设置或修改。在这种方法中,我们的控件将发现哪个元素被设置为占位符,示例9-15 显示了这个方法。

示例9-15


    
private   static   void  OnIsMyPlaceholderChanged(DependencyObject target)  {

        FrameworkElement targetElement 
= target as FrameworkElement;
        
if (targetElement != null && GetIsMyPlaceholder(targetElement)) {
            ControlWithPlaceholder containingControl 
=
                targetElement.TemplatedParent 
as ControlWithPlaceholder;
            
if (containingControl != null{
                containingControl.placeholder 
= targetElement;
            }

        }

    }

    
private  FrameworkElement placeholder;

    
}


这个示例开始于检测属性被应用到派生于

FrameworkElement 的对象。记住我们希望这个属性会被应用到一个特定的控件模板内的UI 元素,因此如果被应用到别的元素而不是FrameworkElement ,我们这么做就得不到什么有用的东西。

其次,我们通过GetIsMyPlaceholder访问器方法检测了属性值,该方法是我们在示例9-14为附属属性定义的。这将是些微单独的,如果有人显示的设置这个属性为false,但是如果确实是这样,我们干脆不应该把元素作为占位符。

如果这个属性设置为true,我们继续获取目标元素的TemplatedParent属性。因为元素作为控件的模板一部分,这将返回可视化所属于的控件。(如果这个元素不是控件的成员,那么返回null。既然这个属性仅仅对模板中的元素有意义,如果没有模板化的父一级,我们就做不了任何事情。)我们还检查了父一级是一个控件类型的一个实例,而且忽略了属性,如果被应用到一个模板中的元素,在某种其它类型的控件模板中。

示例9-16显示了如何在一个控件模板中使用属性,来表明是哪一个元素在占位符中。

示例9-16

< ControlTemplate  TargetType =" {x:Type local:ControlWithPlaceholder} " >
    
< Grid  local:ControlWithPlaceholder.IsMyPlaceholder ="true"   />
</ ControlTemplate >

一些控件希望有一种模板,提供一组详细明确的元素,来履行特定的角色在控件的标签中。例如,

HorizontalSlider 控件希望模板包含表示可拖动thumb 的元素,这个可点击的跟踪,在thumb 的任意一边,等等。模板需要指出哪一个元素是哪一个。这可以通过使用上述显示的技术,定义多个附属属性来实现。

当你写一个使用了占位符的控件时,你可能选择不执行这个约定。例如,如果模板的任意部分不见了,slider控件不会抱怨。一旦你只提供了要寻找的一些元素,这可以工作而不用抱怨。

目录
相关文章
|
1月前
|
文字识别 C# 开发者
WPF开源的一款免费、开箱即用的翻译、OCR工具
WPF开源的一款免费、开箱即用的翻译、OCR工具
|
7月前
|
算法 C# UED
浅谈WPF之控件模板和数据模板
WPF不仅支持传统的Windows Forms编程的用户界面和用户体验设计,同时还推出了以模板为核心的新一代设计理念。在WPF中,通过引入模板,将数据和算法的“内容”和“形式”进行解耦。模板主要分为两大类:数据模板【Data Template】和控件模板【Control Template】。
124 8
WPF ComboBox 数据模板
WPF中的控件,有不少都是需要绑定数据的,例如ComboBox控件可以绑定数据,从下拉列表中进行选择。默认情况下,ComboBox控件绑定的数据从显示上比较单一,只能显示固定的文本信息。而为了更好的突出数据展现效果,这里需要使用到WPF中的另一种强大的功能,即数据模板(DataTemplate )
1144 0
WPF ComboBox 数据模板
|
C#
WPF XAML 资源样式模板属性存放位置
原文:WPF XAML 资源样式模板属性存放位置 WPF的XAML 资源申明 类似HTML。 整体来说分3种1.行类资源样式属性 1.1 行内属性 1.2 行内样式 模板(没多大意义) ...
1117 0
|
C#
WPF - 模板查看工具:Show Me The Template及如何查看第三方主题
原文:WPF - 模板查看工具:Show Me The Template及如何查看第三方主题   在学习WPF的模板(DataTemplate、ItemsPanelTemplate、ControlTemplate)时,经常会想看看WPF内建的控件模板。
1588 0
|
C#
【msdn wpf forum翻译】如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点?
原文:【msdn wpf forum翻译】如何在wpf程序(程序激活时)中捕获所有的键盘输入,而不管哪个元素获得焦点?原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/cf884a91-c135-447d-b16b-214d2d9e9972 有时有些特殊的程序需要这样处理。
960 0
|
C#
【msdn wpf forum翻译】获取当前窗口焦点所在的元素
原文:【msdn wpf forum翻译】获取当前窗口焦点所在的元素原文地址: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6bd7a03a-f0b4-42df-a7f2-5182cf003cb0 Bialgous回答:IInputElement focusedElement = FocusManager.
945 0
|
C#
【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?
原文:【msdn wpf forum翻译】TextBlock等类型的默认样式(implicit style)为何有时不起作用?原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/148e95c6-6fb5-4399-8a56-4...
952 0
|
C#
【msdn wpf forum翻译】TextBox中文本 中对齐 的方法
原文:【msdn wpf forum翻译】TextBox中文本 中对齐 的方法原文链接:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/49864e35-1dbf-4292-a361-93f1a8400558 问题:TextBox中文本中对齐,使用 TextBox.HorizontalContentAlignment="Center"行不通(TextBox.VerticalContentAlignment="Center"则会起到预期的作用。
1212 0
|
C#
WPF关于控件 父级控件,子级控件,控件模板中的控件,等之间的相互访问
原文:WPF关于控件 父级控件,子级控件,控件模板中的控件,等之间的相互访问 1,在菜单中访问 弹出菜单的控件 var mi = sender as MenuItem;//菜单条目 MenuItem var cm = mi.
948 0