[Silverlight]如何获取模板中定义各个对象

  过去一直有个Silverlight的技术疑难没有得到解决,那就是如果在Code Behind中获取模板中定义的各个对象的引用。参考一下Xaml代码:

代码
     < ListBox x:Name ="lbx_listBox"
<ListBox.ItemPanel
>

     
< ItemsPanelTemplate x:Key ="fileListItemsPanelTemplate" >
   
< controlsToolkit:WrapPanel x:Name ="wrp_listWrapper"

                   Width
="450"

                   Orientation
="Horizontal" />
   
</ ItemsPanelTemplate >
</ ListBox.ItemPanel >
</ ListBox >

  这段代码定义了一个列表,列表中我选用WrapPanel作为列表项的容器,很明显是为了实现水平列表项自动换行的功能。但现在我是硬编码了450这个宽度给WrapPanel,因此当列表控件变大或缩小时,WrapPanel不会自动跟随变化。由此,我必须实现一个自动更新的机制。可以使用数据绑定,或者使用ListBox的SizeChanged事件。但无论使用哪种方式,我都必须获取这个WrapPanel对象的引用。

  我故意给这个WrapPanel一个Name属性(值为wrp_listWrapper),这样并不会引起编译错误或者运行时异常。但尽管拥有一个Name属性,我仍然无法从Code Behind中获取该WrapPanel的引用,因为它是定义在模板中的对象。

  实现获取引用的方式就是Loaded事件。参考以下改进代码:

代码
     < ListBox x:Name ="lbx_listBox"
<ListBox.ItemPanel
>

     
< ItemsPanelTemplate x:Key ="fileListItemsPanelTemplate" >
   
< controlsToolkit:WrapPanel x:Name ="wrp_listWrapper"

                   Width
="450"

                   Orientation
="Horizontal"

                   Loaded
="wrp_listWrapper_Loaded" />
   
</ ItemsPanelTemplate >
</ ListBox.ItemPanel >
</ ListBox >

  高亮的代码就是对WrapPanel的Loaded事件注册处理程序。该事件只会在列表加载完成时触发一次,仅一次。于是在Code Behind中,采用以下代码保存该WrapPanel的引用:

private WrapPanel m_listWrapper;

  
private void wrp_listWrapper_Loaded( object sender, RoutedEventArgs e)
{
m_listWrapper
= sender as WrapPanel;

  }

  就是这样简单的方式,就可以把这个定义在模板中的WrapPanel对象的引用保存下来了。对于其他类似的,定义在模板中的控件对象也能使用这种方式。但要注意,假如面对的是

DataTemplate这一类模板,一般会被多个数据项使用,例如一个ListBox中的DataTemplate会被该ListBox的所有列表项使用。这种情况下,模板中定义的控件的Loaded事件会发生多次,每次是由不一样的列表项触发。但事件处理程序就只有一个,因此必须要在该程序代码中想办法区分各个实例。

  例如:

代码
     < ListBox x:Name ="lbx_listBox"
<ListBox.ItemTemplate
>

    
< DataTemplate >

      
< Image src ={Binding} Loaded ="Image_Loaded" />

    
</ DataTemplate >
</ ListBox.ItemTemplate >
</ ListBox >

  该ListBox中的每个列表项都是一张图片。假如我们用同样的方法在Code Behide中获取该图片的引用:

  private IList < Image > m_imgs = new List < Image > ();

  
private void Image_Loaded( object sender, RoutedEventArgs e)
{
m_imgs.Add(sender
as Image);  

  }

  这里要使用一个Image的List集合来保存模板中的Image,因为多个列表项会运行多次该处理程序。假如要选择指定的某一个Image,则必须添加筛选代码。

你可能感兴趣的:(silverlight)