艾伟_转载:WPF/Silverlight陷阱:XAML自定义控件的嵌套内容无法通过名称访问

简介: 为了说明这个问题,假定我们需要实现一个具有特殊功能的按钮控件。编写Xaml文件如下:Button>对 Code Behind类,唯一的改动是把向导生成的基类从UserControl改成Button:public partial class XamlButton : Button{    ...

为了说明这个问题,假定我们需要实现一个具有特殊功能的按钮控件。编写Xaml文件如下:

< Button  x:Class ="TestWpf.XamlButton"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" >
Button >

对 Code Behind类,唯一的改动是把向导生成的基类从UserControl改成Button:

public   partial   class  XamlButton : Button
{
    
public  XamlButton()
    {
        InitializeComponent();
    }
}

 然后在主窗体中放上这个新创建的控件:

< Window  x:Class ="TestWpf.Window1"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local
="clr-namespace:TestWpf"
    Title
="Window1"  Height ="300"  Width ="300" >
    
< StackPanel >
        
< local:XamlButton  x:Name ="xamlBtn"  Click ="xamlBtn_Click" >
            
< TextBlock  x:Name ="xamlText"  Text ="Xaml Button"   />
        
local:XamlButton >
    
StackPanel >
Window >

看起来很平常的代码,但是很遗憾,编译无法通过。Visual Studio会告诉我们这样的信息:

无法在元素“TextBlock”上设置 Name 属性值“xamlText”。“TextBlock”位于元素“XamlButton”的范围之内,该元素已经具有在其他范围中定义时注册的名称。

或许是翻译的问题,这段错误提示可以说是文不对题,因为我们可以肯定的说:这个程序里面再没有别的地方用到xamlBtn或者xamlText这样的名称。

如果我们换个方式,不再用XAML声明控件,而是用C#代码定义:

public   class  CsButton : Button
{
}

然后再试试用同样的方式把这个控件加到主界面上:

< local:CsButton  x:Name ="csBtn"  Click ="csBtn_Click" >
    
< TextBlock  x:Name ="csText"  Text ="Cs Button"   />
local:CsButton >

 

 完全没有问题!csText通过代码也是可以访问的,Click处理方法可以证明这一点:

private   void  csBtn_Click( object  sender, RoutedEventArgs e)
{
    MessageBox.Show(csText.Text);
}

如果用Silverlight来实验同样的代码,结果会稍有不同。在Silverlight XAML中添加x:Name并不会报错 ,但是运行时就会出现问题——xamlText总是等于null,并且FindName("xamlText")同样返回null,因此文本内容用自动生成的代码是无法访问的。但是以Button作为根对象来查找文本框,却能够找到:

xamlText  =  (TextBlock)xamlBtn.Content;
HtmlPage.Window.Alert(xamlText.Text);

此实验可以说明:用XAML来声明自定义控件是存在严重问题的,控件内容中的对象无论是通过自动生成的成员变量还是用根容器的FindName都无法访问。要绕开这个限制,有以下几种可能的途径:

1. 使用C#手工构造自定义控件,不用XAML声明;

2. 使用自定义控件的FindName找到内容对象,然后手工绑定到成员变量;

3. 使用RegisterName手工管理命名空间。此方法我没有实验,并且它仅对WPF有效,Silverlight是没有这个方法的。

上述方法2是我们最初曾经使用的方法,但是目前已经放弃了,因为手工绑定需要程序员自己编写大量无聊的代码,并且非常容易出错。方法1是目前采用的方法,为此我们删除了许多原先已经写好的XAML,全部改用C#代码手工创建,其实这个工作并不算困难,因为大多数时候XAML到C#的映射还是比较直观的,但由于Silverlight的自身设计的限制,存在一个明显的限制:

不像WPF,Silverlight里面没有简单的办法可以从代码创建一个Template。在WPF中,可以指定Template.VisualTree,但是Silverlight没有提供这个属性,所以要从代码里是生成Template是很困难的。网上曾有人提供过一个思路,即用字符串拼出模板的XAML字符串,再用XamlReader.Load读出模板对象。这个方法虽然可行,但比较丑陋,拼字符串总是下下策,维护也很困难。我们现在使用的是一个折中的办法,Template还是用XAML来保存,但是需要编写一些自定义代码,以便把C#控件和XAML中的模板关联起来。不幸的是,这个办法导致本来是同一个控件的内容不得不在两个地方分别维护,还要时时注意两边的代码保持同步,因此也不能说是一个完满的解决办法。

后记: 我现在主要的工作,是基于Silverlight开发一个应用程序平台,在此过程中已经感觉到Silverlight的一些不足,包括实现上不够完整(比如说缺少Decorator,没有OnRender),部分API在版本之间的大幅度变动(针对Silverlight 3 Beta的一些例子现在都已经失效了),也有设计上的复杂性导致的一些微妙的问题,本文所提到的就是这些问题的其中之一,给框架层面的实现带来了不少麻烦。此外值得一提的是,我们现在编译的xap包大小已经长到了800k以上,可以说和Adobe Flex编译出来的文件大小不相上下。对于文件大小“贡献”最多的是System.Windows.Controls、System.Windows.Controls.Data、System.Windows.Controls.Toolkit和System.Xml.Serialization这四个程序集,其中除了最后一个或许可以考虑以后不再用XML序列化,前面3个是不可能不使用的。所以Flex文件编译以后6、7百K的体积真的算不上大,Silverlight同样是这个水平,那些总是叫唤文件太大的同学也应该了解,RIA程序的尺寸基本上也就这样了,除了用RSL之类技术切割一下以外,已经没有多大优化的余地了。如果这个大小您也不能接受的话,那还是用回Ajax吧。

目录
相关文章
|
4月前
|
XML 开发框架 .NET
WPF自定义控件05:ToggleButton
本文重点介绍WPF中如何实现自定义ToggleButton控件,它是一个开关控件,通过单击来进行状态的快速切换。
4284 0
WPF自定义控件05:ToggleButton
|
6月前
|
IDE C# 开发工具
2000条你应知的WPF小姿势 基础篇<40-44 启动关闭,Xaml,逻辑树>
2000条你应知的WPF小姿势 基础篇<40-44 启动关闭,Xaml,逻辑树>
31 0
|
6月前
|
人工智能 C#
WPF自定义控件库之Window窗口
本文以自定义窗口为例,简述WPF开发中如何通过自定义控件来扩展功能和样式,仅供学习分享使用,如有不足之处,还请指正。
154 5
|
8月前
|
C#
WPF技术之Xaml Window
WPF Window 是一个 WPF 窗口类,它具有许多属性枚举可以控制窗口的外观和行为。
77 0
WPF技术之Xaml Window
|
8月前
|
XML 数据格式 C++
WPF-疑难问题-xaml编码导致中文字符编译无效
WPF-疑难问题-xaml编码导致中文字符编译无效
110 0
|
9月前
|
C# 容器
WPF框架下,窗体的嵌套显示
WPF框架下,窗体的嵌套显示
172 0
|
11月前
|
C#
4.使用代码和未经编译的XAML创建WPF应用程序
4.使用代码和未经编译的XAML创建WPF应用程序
58 0
|
数据采集 人工智能 监控
【WPF】CAD工程图纸转WPF可直接使用的xaml代码技巧
随着工业化的进一步发展,制造业、工业自动化等多领域,都可能用到上位监控系统。而WPF在上位监控系统方面,应该算是当下最流行的前端框架之一了。而随着监控体系的不断完善与更新迭代,监控画面会变得越来越复杂、多样化和全面化。
242 0
【WPF】CAD工程图纸转WPF可直接使用的xaml代码技巧
|
XML C# 数据格式
WPF中用户控件和自定义控件
无论是在WPF中还是WinForm中,都有用户控件(UserControl)和自定义控件(CustomControl),这两种控件都是对已有控件的封装,实现功能重用。但是两者还是有一些区别,本文对这两种控件进行讲解。