一聚教程网:一个值得你收藏的教程网站

热门教程

解决DataTemplate绑定附加属性

时间:2022-06-25 04:05:27 编辑:袖梨 来源:一聚教程网

文 Silverlight 版本:4.0。

    首先定义数据类型,此文始终使用此定义类型。
view sourceprint?
1 public class SimpleData : ViewModelBase
2 {
3     private string _text;
4     private int _column, _row;
5  
6     public string Text { get { return _text; } set { _text = value; OnPropertyChanged("Text"); } }
7     public int Column { get { return _column; } set { _column = value; OnPropertyChanged("Column"); } }
8     public int Row { get { return _row; } set { _row = value; OnPropertyChanged("Row"); } }
9 }
 
    前台代码:
view sourceprint?
01 <Grid x:Name="LayoutRoot" Background="White">
02     <ItemsControl ItemsSource="{Binding}">
03         <ItemsControl.ItemTemplate>
04             <DataTemplate>
05                 <TextBox Text="{Binding Text}"
06                          Foreground="Green"
07                          Grid.Row="{Binding Row}"
08                          Grid.Column="{Binding Column}"
09                          Height="30" Width="150"
10                          />
11             DataTemplate>
12         ItemsControl.ItemTemplate>
13         <ItemsControl.ItemsPanel>
14             <ItemsPanelTemplate>
15                 <Grid ShowGridLines="True">
16                     <Grid.RowDefinitions>
17                         <RowDefinition/>
18                         <RowDefinition/>
19                         <RowDefinition/>
20                     Grid.RowDefinitions>
21                     <Grid.ColumnDefinitions>
22                         <ColumnDefinition/>
23                         <ColumnDefinition/>
24                     Grid.ColumnDefinitions>
25                 Grid>
26             ItemsPanelTemplate>
27         ItemsControl.ItemsPanel>
28     ItemsControl>
29 Grid>
    后台代码:
view sourceprint?
01 public partial class MainPage : UserControl
02 {
03     public MainPage()
04     {
05         InitializeComponent();
06         this.DataContext = new SimpleData[]
07         {
08             new SimpleData{ Text = "111111", Column = 0, Row = 0 },
09             new SimpleData{ Text = "222222", Column = 1, Row = 1 }, 
10             new SimpleData{ Text = "333333", Column = 0, Row = 2 }, 
11         };
12     }
13 }
 
    可以看出这段代码的本意是通过绑定的方式设置,在 ItemsControl 里面显示 3 个 TextBox,同时指定了相应在 Grid 的行和列。
    但是,你懂的!
    这样的代码肯定是不能正确运行。特别是在Silverlight。
    如果这是在 WPF 环境,很庆幸你还可以用 ItemContainerStyle 搞定:
view sourceprint?
1 <ItemsControl.ItemContainerStyle>
2     <Style>
3         <Setter Property="Grid.Row" Value="{Binding Row, Mode=OneWay}"/>
4         <Setter Property="Grid.Column" Value="{Binding Column, Mode=OneWay}"/>
5     Style>
6 ItemsControl.ItemContainerStyle>
 
    只可惜这是在 Silverlight 环境。我们只能够想别的办法了。
 
    为什么不可以?拿出 Silverlight Spy 或者 Snoop 查看相应的 VisualTree。可以看到在 TextBox 外面还套了一个 ContextPresenter
    于是我们可以想到,能不能设置 ContextPresenter 的 Grid.Row 和 Grid.Colume 达到控制行列的目的?
    于是我们得到下面的思路,使用附加属性把相应的绑定关系提升。
view sourceprint?
001 using System;
002 using System.Collections.Generic;
003 using System.Globalization;
004 using System.Linq;
005 using System.Reflection;
006 using System.Windows;
007 using System.Windows.Controls;
008 using System.Windows.Data;
009 using System.Windows.Media;
010   
011 namespace Delay
012 {
013     public class UpUp : DependencyObject
014     {
015         // Using a DependencyProperty as the backing store for Up.  This enables animation, styling, binding, etc...
016         public static readonly DependencyProperty UpProperty =
017             DependencyProperty.RegisterAttached("Up", typeof(string), typeof(UpUp), new PropertyMetadata(string.Empty));
018   
019         public static void SetUp(FrameworkElement element, string value)
020         {
021             HanderClosure hander = element.GetValue(UpProperty) as HanderClosure;
022             if (hander == null)
023             {
024                 hander = new HanderClosure(element, value);
025                 element.SetValue(UpProperty, value);
026                 element.LayoutUpdated += new EventHandler(hander.element_LayoutUpdated);
027             }
028         }
029         public static string GetUp(FrameworkElement element)
030         {
031             HanderClosure hander = element.GetValue(UpProperty) as HanderClosure;
032             if (hander == null)
033                 return null;
034             else
035                 return hander.OrgParamenter;
036         }
037   
038         private class HanderClosure
039         {
040             private FrameworkElement _elem = null;
041             private string[] propertys = null;
042             private int _level;
043             private UpMode _mode;
044             private string _orgParamenter;
045   
046             public string OrgParamenter { get { return _orgParamenter; } }
047   
048             public HanderClosure(FrameworkElement element, string parameter)
049             {
050                 if (element == null)
051                     throw new ArgumentNullException("element");
052                 if (parameter == null)
053                     throw new ArgumentNullException("parameter");
054                 _elem = element;
055                 _level = 1;
056                 _mode = UpMode.Copy;
057                 _orgParamenter = parameter;
058   
059                 string[] array = parameter.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
060                 if (array.Length == 0)
061                     throw new ArgumentException("parameter");
062                 propertys = array[0].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
063                 if (array.Length > 1)
064                 {
065                     int num;
066                     if (int.TryParse(array[1].Trim(), out num))
067                     {
068                         _level = num;
069                     }
070                 }
071                 if (array.Length > 2)
072                 {
073                     UpMode mode;
074                     if (Enum.TryParse(array[2].Trim(), true, out mode))
075                     {
076                         _mode = mode;
077                     }
078                 }
079             }
080   
081             public void element_LayoutUpdated(object sender, EventArgs e)
082             {
083                 FrameworkElement parent = _elem;
084                 for (int i = 0; i < _level && parent != null; i++)
085                 {
086                     parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
087                 }
088                 if (parent == null)
089                     return;
090   
091                 foreach (string property in propertys)
092                 {
093                     Apply(_elem, parent, property.Trim());
094                 }
095             }
096   
097             // Copyright (C) Microsoft Corporation. All Rights Reserved.
098             // This code released under the terms of the Microsoft Public License
099             // (Ms-PL, http://opensource.org/licenses/ms-pl.html).
100             private void Apply(FrameworkElement element1, FrameworkElement element2, string property)
101             {
102                 var array = property.Split('.');
103                 if (array.Length != 2)
104                     throw new ArgumentException("property");
105                 string typeName = array[0].Trim();
106                 string propertyName = array[1].Trim();
107   
108                 Type type = null;
109                 foreach (var assembly in AssembliesToSearch)
110                 {
111                     // Match on short or full name
112                     type = assembly.GetTypes()
113                        .Where(t => (t.FullName == typeName) || (t.Name == typeName))
114                        .FirstOrDefault();
115                     if (type != null)
116                         break;
117                 }
118                 if (null == type)
119                 {
120                     // Unable to find the requested type anywhere
121                     throw new ArgumentException(
122                         string.Format(
123                             CultureInfo.CurrentCulture,
124                             "Unable to access type "{0}". Try using an assembly qualified type name.",
125                             typeName));
126    &n