Silverlight数据绑定/IValueConverter学习笔记
先回忆一下aspx中的处理:
在aspx中,可以直接在后台定义一个变量,然后前台就可以用<%=xxx%>来将其"绑定"html控件上,比如下面这样,实在是很方便:
using System;
namespace WebApplication1
{
public partial class _Default : System.Web.UI.Page
{
protected string _Test = DateTime.Now.ToString();
protected void Page_Load(object sender, EventArgs e)
{
}
}
}
代码
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<input id="Text1" type="text" value="<%=_Test %>"/>
</form>
</body>
</html>
但到了Silverlight中,要想直接将后台的变量绑定到某个控件上却是行不通的,通常我们得先定义一个类,然后在类里定义属性,才能把类实例的属性绑定到控件:
简单绑定:
代码
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Shapes;
namespace BindVariable
{
public partial class MainPage : UserControl
{
public class MyClass { public string Test { set; get; } }
public MyClass TestClass;
public MainPage()
{
InitializeComponent();
TestClass = new MyClass();
TestClass.Test = "123";
this.textBox1.DataContext = TestClass;
}
}
}
<StackPanel>
<TextBox x:Name="textBox1" Text="{Binding Test}"/>
</StackPanel>
这样就完成了功能最简单的绑定,还想玩得更深入一点,比如实现OneWay,TwoWay方式的绑定(不清楚绑定模式的朋友,建议先参看https://cloud.tencent.com/developer/article/1027125),这样仍然不行,比如我们稍微把刚才的代码改一下:
"自动更新"的绑定:
代码
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="BindVariable.MainPage"
>
<StackPanel Orientation="Vertical">
<TextBox x:Name="textBox1" Text="{Binding Test}"/>
<Button x:Name="btnChange" Content="Change Test" Click="btnChange_Click"></Button>
</StackPanel>
</UserControl>
代码
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Shapes;
namespace BindVariable
{
public partial class MainPage : UserControl
{
public class MyClass { public string Test { set; get; } }
public MyClass TestClass;
public MainPage()
{
InitializeComponent();
TestClass = new MyClass();
TestClass.Test = "123";
this.textBox1.DataContext = TestClass;
}
private void btnChange_Click(object sender, RoutedEventArgs e)
{
this.TestClass.Test = "456";
}
}
}
运行后,点击按钮,发现textbox1中的内容并无变化,原因是:要想实现源与目标的数据自动关联更新,MyClass得实现INotifyPropertyChanged接口,我们把MyClass的定义改成下面这样:
代码
public class MyClass:INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private string _test;
public string Test
{
set{
_test = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Test"));
}
}
get { return _test; }
}
}
再次运行,发现点击按钮后,textbox1的内容变成了456,达到预期的效果了. 绑定集合(数据集):
很多应用场合中,数据来源不仅只有一个实例(或一条记录)--比如从数据库中检索的记录,这时如果想绑定数据并实现自动更新,应使用集合绑定(类似于aspx中的DataSet或DataTable)。要注意的是,使用集合绑定并实现自动更新,除了要实现 INotifyPropertyChanged 外,还要实现 INotifyCollectionChanged。幸好.net框架已经有一个ObservableCollection<T> 类,该类具有 INotifyCollectionChanged 和 INotifyPropertyChanged 的内置实现。可以直接拿来用:
代码
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="BindVariable.MainPage"
xmlns:local="clr-namespace:BindVariable"
>
<StackPanel Orientation="Vertical">
<ListBox x:Name="lst" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Test}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="btnChange" Content="Change Test" Click="btnChange_Click"></Button>
</StackPanel>
</UserControl>
代码
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace BindVariable
{
public partial class MainPage : UserControl
{
public class MyClass { public string Test { set; get; } }
ObservableCollection<MyClass> oc = new ObservableCollection<MyClass>(){
new MyClass() { Test = "1" },
new MyClass() { Test = "2" },
new MyClass() { Test = "3" }
};
public MainPage()
{
InitializeComponent();
this.lst.ItemsSource = oc;
}
private void btnChange_Click(object sender, RoutedEventArgs e)
{
oc.Add(new MyClass() { Test = "4" });
}
}
}
IValueConverter:
上述的绑定,都是将数据原封不动的绑定并显示,如果我们希望在绑定时,能对数据的输出做一些变化,比如:代表性别的"1,0"输出时希望变成"男,女",该怎么办呢?(silverlight中可不允许象aspx那样用<%# Eval("Sex").ToString()=="1"?"男":"女"%>来搞定) 答案:IValueConverter
代码
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace BindVariable
{
public partial class MainPage : UserControl
{
public class MyClass
{
public string Test { set; get; }
public bool Sex { set; get; }
}
ObservableCollection<MyClass> oc = new ObservableCollection<MyClass>(){
new MyClass() { Test = "1",Sex=true },
new MyClass() { Test = "2",Sex=false },
new MyClass() { Test = "3",Sex=true }
};
public MainPage()
{
InitializeComponent();
this.lst.ItemsSource = oc;
}
private void btnChange_Click(object sender, RoutedEventArgs e)
{
oc.Add(new MyClass() { Test = "4", Sex = false });
}
}
/// <summary>
/// bool转化为性别字符串
/// </summary>
public class BoolToSexConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return ((bool)value) ? "男" : "女";
}
catch
{
return "?";
}
}
//只有TwoWay模式下,才需要实现该方法,否则可以不用理
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="BindVariable.MainPage"
xmlns:local="clr-namespace:BindVariable"
>
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<local:BoolToSexConverter x:Key="Bool2Sex"></local:BoolToSexConverter>
</StackPanel.Resources>
<ListBox x:Name="lst" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Test}"></TextBlock>
<TextBlock Text=","></TextBlock>
<TextBlock Text="{Binding Path=Sex, Converter={StaticResource Bool2Sex}}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="btnChange" Content="Change Test" Click="btnChange_Click"></Button>
</StackPanel>
</UserControl>
也许您注意到了IValueConverter的Convert方法中,还能传入参数!我们可以利用这个玩点小花样,比如界面上有三个矩形,其中"矩形2的宽度"等于"矩形1的宽度"+"一个任意指定的固定值",矩形3的宽度矩形1与矩形2的宽度总和,不允用 rect2.width = rect1.width,rect3.width = rect2.width + rect1.width 来处理:) 您会怎么做呢?
代码
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace BindVariable
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
}
public class DoubleAddConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return double.Parse(value.ToString()) + double.Parse(parameter.ToString());
}
catch
{
return 50.0;
}
}
//只有TwoWay模式下,才需要实现该方法,否则可以不用理
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class FrameworkElementAddConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return double.Parse(value.ToString()) + ((App.Current.RootVisual as FrameworkElement).FindName(parameter.ToString()) as FrameworkElement).Width;
}
catch
{
return 50.0;
}
}
//只有TwoWay模式下,才需要实现该方法,否则可以不用理
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Class="BindVariable.MainPage"
xmlns:local="clr-namespace:BindVariable"
>
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" >
<StackPanel.Resources>
<local:DoubleAddConverter x:Key="DoubleAdd"></local:DoubleAddConverter>
<local:FrameworkElementAddConverter x:Key="FEAdd"></local:FrameworkElementAddConverter>
</StackPanel.Resources>
<Rectangle x:Name="rect1" Width="100" Height="50" Fill="Gray" HorizontalAlignment="Left"></Rectangle>
<Rectangle x:Name="rect2" Height="50" Width="{Binding Width, Converter={StaticResource DoubleAdd}, ConverterParameter=100, ElementName=rect1, Mode=OneWay}" Fill="Red" HorizontalAlignment="Left"></Rectangle>
<Rectangle x:Name="rect3" Height="50" Fill="Blue" Width="{Binding Width, Converter={StaticResource FEAdd}, ConverterParameter=rect2, ElementName=rect1, Mode=OneWay}"></Rectangle>
</StackPanel>
</UserControl>
这样就搞定了,也许有人会问:为啥不用 rect2.width = rect1.width,rect3.width = rect2.width + rect1.width 呢?不是更简单吗?
存在即合理,这样的好处是不必用硬编码把逻辑写死,我们可以把常用的转换处理抽象出来,比如封装成一个单纯的dll程序集,以后需要用到的地方,直接引用就可以了,能有效的重用代码。
转载请注明来自菩提树下的杨过
- hdu------(3549)Flow Problem(最大流(水体))
- go语言实现http服务端与客户端
- hdu-----(1532)Drainage Ditches(最大流问题)
- LNMP无法删除.user.ini文件的解决方法
- HDU-----(4858)项目管理(模拟)
- hdu-----(4857)逃生(拓扑排序)
- HDU-----(1083)Courses(最大匹配)
- HDU----(3294)Girls' research(manacher)
- map
- hdu----(3068)最长回文(manacher)
- hdu---(1280)前m大的数(计数排序)
- 程序员你为什么这么累【续】:编码习惯之Controller规范
- go-nsq使用简述
- hdu---(4515)小Q系列故事——世界上最遥远的距离(模拟题)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ThingJS数据对接方法介绍——Ajax
- python-剑指offer41-62
- 【python-opencv】读取、显示、写入图像
- WSL——windows上的linux子系统
- 【python-opencv】读取、显示、保存视频
- 超级账本——Hyperledger Fabric
- 【python-opencv】绘图(目标检测框及其置信度等)
- 哈希表:哈希值太大了,还是得用set
- 哈希表:今天你快乐了么?
- 简单二分法查找(binary search)
- 【python-opencv】鼠标作为画笔
- npm 依赖管理中被忽略的那些细节
- 哈希表:map等候多时了
- 简单了解异步通信
- 哈希表:其实需要哈希的地方都能找到map的身影