很早以前就接触了WPF,可是一直没怎么仔细研究过。最近做Windows Phone时又开始接触相关内容。在一个功能中,需要显示一些保存的城市列表,决定用自定义控件做。因为以前没仔细学习WPF,现在就趁着用到看了点。
=================以下段落转自网络并做出了修改====================
我们为控件(或者任何一个WPF 类)添加的依赖属性都是"公开的","静态的","只读的",其命名方式是"属性名+Property",这是依赖属性一成不变的
书写方式.对于依赖属性的注册可以在声明该属性时就调用DependencyProperty.Register()方法注册,也可以在其静态构造方法中注册.上面的
DependencyProperty.Register 方法的几个参数分别是:属性名(该属性名与声明的依赖属性名称"XXXProperty"相比仅仅是少了"Property"
后缀,其它完全一样,否则在运行时会报异常),属性的数据类型,属性的拥有者的类型,元数据.
关于参数中传递的元数据: 如果是普通的类则应该传递PropertyMetadata, 如果是FrameworkElement 则可以传递
FrameworkPropertyMetadata, 其中FrameworkPropertyMetadata 中可以制定一些标记表明该属性发生变化时控件应该做出什么反应,比如某
属性的变化会影响到该控件的绘制, 那么就应该像这样书写该属性的元数据: new FrameworkPropertyMetadata(defauleValue,
FrameworkPropertyMetadataOptions.AffectsRender);这样当该属性发生变化时系统会考虑重绘该控件.另外元数据中还保护很多内容,比
如默认值,数据验证,数据变化时的回调函数,是否参与属性"继承"等.
然后,我们将该依赖属性包装成普通属性:
1 [Description("获取或设置当前城市")] 2 [Category("Common Properties")] 3 public string City 4 { 5 get 6 { 7 return (string)this.GetValue(CityProperty); 8 } set 9 { 10 this.SetValue(CityProperty, value); 11 } 12 }
GetValue 和SetValue 方法来自于DependencyObject 类,其用于获取或设置类的某属性值.
注意:在将依赖属性包装成普通属性时,在get 和set 块中除了按部就班的调用GetValue 和SetValue 方法外,不要进行任何其它的操作.下面的代码
是不恰当的:
1 [Description("获取或设置当前气温")] 2 [Category("Common Properties")] 3 public string Temperature 4 { 5 get 6 { 7 return (string)this.GetValue(TemperatureProperty); 8 } 9 set 10 { 11 this.SetValue(TemperatureProperty, value); 12 this.OnTimeUpdated(value);//Error 13 } 14 }
在以前这或许是很多人的惯用写法,但在WPF 中,这样的写法存在潜在的错误,原因如下:我们知道继承于DependencyObject 的类拥有GetValue 和
SetValue 方法来获取或设置属性值,那为什么我们不直接使用该方法来获取或设置属性值,而要将其包装成普通的.NET 属性呢,事实上在这里两种方
式都是可以的,只不过包装成普通的.NET 属性更符合.NET 开发人员的习惯,使用GetValue 和SetValue 更像JAVA 开发人员的习惯,但XAML 在执
行时似乎于JAVA 开发人员一样,其不会调用.NET 属性而是直接使用GetValue 或SetValue 方法,这样一来,我们写在get 块和set 块中的其它代
码根本不会被XAML 执行到.所以说,就上面的Time 属性而言,C#(或其它)对该属性的调用不会出现任何问题,但该属性被用在XAML 中时(比如在XAML
对该属性进行数据绑定等),其set 块中的this.OnTimeUpdated(value);语句不会被执行到.
那么,当Time 属性发生变化时的确需要调用this.OnTimeUpdated(value); 语句(因为该语句会引发时间被更新了的事件),还是在传递的依赖属性
元数据做文章:
new FrameworkPropertyMetadata(DateTime.Now,new PropertyChangedCallback(TimePropertyChangedCallback)), 我们为属性
的变化指定了一个回调函数,当该属性变化时该回调函数就会被执行
==================页面设计======================
1 <Grid Name="gd" Height="200" Width="200"> 2 <Grid.RowDefinitions> 3 <RowDefinition Height="*"/> 4 <RowDefinition Height="*"/> 5 </Grid.RowDefinitions> 6 <Grid.ColumnDefinitions> 7 <ColumnDefinition Width="*"/> 8 <ColumnDefinition Width="*"/> 9 </Grid.ColumnDefinitions> 10 11 <TextBlock Name="txtCity" Grid.Row="0" Grid.Column="0" FontSize="40" FontFamily="Microsoft YaHei"> 12 <TextBlock.BitmapEffect > 13 <OuterGlowBitmapEffect Opacity="0.6"></OuterGlowBitmapEffect> 14 </TextBlock.BitmapEffect> 15 </TextBlock> 16 <TextBlock Name="txtTemp" Grid.Row="1" Grid.Column="0" FontSize="40" FontFamily="Microsoft YaHei"> 17 <TextBlock.BitmapEffect > 18 <OuterGlowBitmapEffect Opacity="0.6"></OuterGlowBitmapEffect> 19 </TextBlock.BitmapEffect> 20 </TextBlock> 21 <Image Grid.Row="0" Grid.Column="1" Name="img" ></Image> 22 </Grid>
==================后台代码======================
namespace userC { /// <summary> /// Interaction logic for UserControl1.xaml /// </summary> public partial class UserControl1 : UserControl { #region DP public string City { get { return (string)this.GetValue(CityProperty); } set { SetValue(CityProperty, value); } } public static DependencyProperty CityProperty = DependencyProperty.Register("City", typeof(string), typeof(UserControl1), new PropertyMetadata("长春")); public string Temperature { get { return (string)this.GetValue(TemperatureProperty); } set { SetValue(TemperatureProperty, value); } } public static DependencyProperty TemperatureProperty = DependencyProperty.Register("Temperature", typeof(string), typeof(UserControl1), new PropertyMetadata("20")); public string ImagePath { get { return (string)this.GetValue(ImagePathProperty); } set { SetValue(ImagePathProperty, value); } } public static DependencyProperty ImagePathProperty = DependencyProperty.Register("ImagePath", typeof(string), typeof(UserControl1), new PropertyMetadata("null")); public Brush Background { get { return (Brush)this.GetValue(BackgroundProperty); } set { SetValue(BackgroundProperty, value); } } public static DependencyProperty BackgroundProperty = DependencyProperty.Register("Background", typeof(Brush), typeof(UserControl1), new PropertyMetadata(Brushes.Cyan)); #endregion public UserControl1() { InitializeComponent(); } protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); Binding cityBinding = new Binding(); cityBinding.Source = this; cityBinding.Path = new PropertyPath(UserControl1.CityProperty); this.txtCity.SetBinding(TextBlock.TextProperty, cityBinding); Binding temBinding = new Binding(); temBinding.Source = this; temBinding.Path = new PropertyPath(UserControl1.TemperatureProperty); this.txtTemp.SetBinding(TextBlock.TextProperty, temBinding); Binding imgBinding = new Binding(); imgBinding.Source = this; imgBinding.Path = new PropertyPath(UserControl1.ImagePathProperty); this.img.SetBinding(Image.SourceProperty, imgBinding); Binding bgBinding = new Binding(); bgBinding.Source = this; bgBinding.Path = new PropertyPath(UserControl1.BackgroundProperty); this.gd.SetBinding(Grid.BackgroundProperty, bgBinding); } } }
==================前台调用======================
先引用User Control工程
using userC;
然后在WrapPanel里面添加自定义控件
1 public MainWindow() 2 { 3 InitializeComponent(); 4 5 wp.Children.Add(new UserControl1 { City = "宿迁", Temperature = "25", ImagePath = "/usercontrol;component/晴D.png", Background = Brushes.Pink }); 6 wp.Children.Add(new UserControl1 { City = "长春", Temperature = "10", ImagePath = "/usercontrol;component/多云D.png", Background = Brushes.RosyBrown }); 7 wp.Children.Add(new UserControl1 { City = "北京", Temperature = "15", ImagePath = "/usercontrol;component/冻雨N.png" }); 8 }