[转]深入浅出WPF(7)——数据的绿色通道,Binding
本文转自:http://liutiemeng.blog.51cto.com/120361/95273

- 响应slider1的ValueChanged事件,在事件处理函数中让textBox1显示slider1的Value
- 响应textBox1的LostFocus事件,把textBox1的Text转换成数值,并赋值给slider1
- <Window x:Class="BindingSample.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="http://blog.csdn.net/FantasiaX" Height="300" Width="300">
- <Window.Background>
- <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
- <GradientStop Color="Blue" Offset="0.3"/>
- <GradientStop Color="LightBlue" Offset="1"/>
- </LinearGradientBrush>
- </Window.Background>
- <Grid>
- <TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" />
- <TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
- <Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
- </Grid>
- </Window>
<Window x:Class="BindingSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="http://blog.csdn.net/FantasiaX" Height="300" Width="300">
<Window.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Blue" Offset="0.3"/>
<GradientStop Color="LightBlue" Offset="1"/>
</LinearGradientBrush>
</Window.Background>
<Grid>
<TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" />
<TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
<Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
</Grid>
</Window>
- <Grid>
- <TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" />
- <TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
- <Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
- </Grid>
<Grid>
<TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" />
<TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
<Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
</Grid>
- <Grid>
- <TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding ElementName=slider1, Path=Value}"/>
- <TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
- <Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
- </Grid>
<Grid>
<TextBox Height="23" Margin="10,10,9,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding ElementName=slider1, Path=Value}"/>
<TextBox Height="23" Margin="10,41,9,0" Name="textBox2" VerticalAlignment="Top" />
<Slider Height="21" Margin="10,73,9,0" Name="slider1" VerticalAlignment="Top" Maximum="100" />
</Grid>


- 数据源(Data Source,简称Source):顾名思义,它是保有数据的实体、是数据的来源、源头。把谁当作数据源完全由程序员来决定——只要你想把它当做数据核心来使用。它可以是一个UI元素、某个类的实例,也可以是一个集合(关于对集合的绑定,非常重要,专门用一篇文章来讨论之)。
- 路径(Path):数据源作为一个实体可能保有着很多数据,你具体关注它的哪个数值呢?这个数值就是Path。就上面的例子而言,slider1是Source,它拥有很多数据——除了Value之外,还有Width、Height等,但都不是我们所关心的——所以,我们把Path设为Value。
- 目标(Target):数据将传送到哪里去?这就是数据的目标了。上面这个例子中,textBox1是数据的Target。有一点需要格外注意:Target一定是数据的接收者、被驱动者,但它不一定是数据的显示者——也许它只是数据联动中的一环——后面我们给出了例子。
- 关联(Binding):数据源与目标之间的通道。正是这个通道,使Source与Target之间关联了起来、使数据能够(直接或间接地)驱动界面!
- 设定关联(Set Binding):为Target指定Binding,并将Binding指向Target的一个属性,完成数据的“端对端”传输。
- 如果你想把“绿色通道”限制为“单行道”,那就设置Binding实例的Mode属性,它是一个BindingMode类型的枚举值,其中包含了TwoWay、OneWay和OneWayToSource几个值。上面这个例子中,默认地是TwoWay,所以才会有双向的数据传递。
- 如果用户提出只要textBox1的文本改变slider1的滑块立刻响应,那就设置Binding的UpdateSourceTrigger属性。它是一个UpdateSourceTrigger类型枚举值,默认值是UpdateSourceTrigger.LostFocus,所以才会在移走鼠标焦点的时候更新数据。如果把它设置为UpdateSourceTrigger.PropertyChanged,那么Target被关联的属性只要一改变,就立刻传回给Source——我们要做的仅仅是改了一个单词,而WinForm程序员这时候正头疼呢,因为他需要去把代码搬到另一个事件响应函数中去。
- 如果Binding两端的数据类型不一致怎么办?没关系,你可以设置Binding的Converter属性,具体内容在下篇文章中讨论。
- 如果数据中有“易燃易爆”的不安全因素怎么办?OK,可以设置Binding的ValidationRules,为它加上一组“安检设施”(同样也在下篇文中讨论)。

- Source:确定哪个对象作为数据源
- Target:确定哪个对象作为目标
- Binding:声明一个Binding实例
- 把一根管子接到Source上并把管芯插在Source的Path上
- 把另一根管子接到Target上并把管芯插在Target的联动属性上

- public Window1()
- {
- InitializeComponent();
- // 1. 我打算用slider1作为Source
- // 2. 我打算用textBox1作为Target
- Binding binding = new Binding();
- binding.Source = this.slider1;
- binding.Path = new PropertyPath("Value");
- this.textBox1.SetBinding(TextBox.TextProperty, binding);
- }
public Window1()
{
InitializeComponent();
// 1. 我打算用slider1作为Source
// 2. 我打算用textBox1作为Target
Binding binding = new Binding();
binding.Source = this.slider1;
binding.Path = new PropertyPath("Value");
this.textBox1.SetBinding(TextBox.TextProperty, binding);
}
- public Window1()
- {
- InitializeComponent();
- // 1. 我打算用slider1作为Source
- // 2. 我打算用textBox1作为Target
- Binding binding = new Binding("Value");
- binding.Source = this.slider1;
- this.textBox1.SetBinding(TextBox.TextProperty, binding);
- }
public Window1()
{
InitializeComponent(); // 1. 我打算用slider1作为Source
// 2. 我打算用textBox1作为Target
Binding binding = new Binding("Value");
binding.Source = this.slider1;
this.textBox1.SetBinding(TextBox.TextProperty, binding);
}
- public Window1()
- {
- InitializeComponent();
- // 1. 我打算用slider1作为Source
- // 2. 我打算用textBox1作为Target
- Binding binding = new Binding("Value");
- binding.Source = this.slider1;
- binding.Mode = BindingMode.TwoWay;
- binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
- this.textBox1.SetBinding(TextBox.TextProperty, binding);
- }
public Window1()
{
InitializeComponent();
// 1. 我打算用slider1作为Source
// 2. 我打算用textBox1作为Target
Binding binding = new Binding("Value");
binding.Source = this.slider1;
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
this.textBox1.SetBinding(TextBox.TextProperty, binding);
}
- 为这个类定义一些Property,相当于为Binding提供Path
- 让这个类实现INotifyPropertyChanged接口。实现这个接口的目的是当Source的属性值改变后通知Binding(不然人家怎么知道源头的数据变了并进行联动协同呢?),好让Binding把数据传输给Target——本质上还是使用事件机制来做,只是掩盖在底层、不用程序员去写event handler了。
- <PRE class=csharp name="code">// 第一步:声明一个类,准备必要的属性
- public class Student
- {
- private int id;
- public int Id
- {
- get { return id; }
- set { id = value; }
- }
- private string name;
- public string Name
- {
- get { return name; }
- set { name = value; }
- }
- private int age;
- public int Age
- {
- get { return age; }
- set { age = value; }
- }
- }</PRE>
- // 第一步:声明一个类,准备必要的属性
- public class Student
- {
- private int id;
- public int Id
- {
- get { return id; }
- set { id = value; }
- }
- private string name;
- public string Name
- {
- get { return name; }
- set { name = value; }
- }
- private int age;
- public int Age
- {
- get { return age; }
- set { age = value; }
- }
- }
// 第一步:声明一个类,准备必要的属性
public class Student
{
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
}
- // 第二步:实现INotifyPropertyChanged接口
- public class Student : INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged; // 这个接口仅包含一个事件而已
- private int id;
- public int Id
- {
- get { return id; }
- set
- {
- id = value;
- if (this.PropertyChanged != null)
- {
- this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Id")); // 通知Binding是“Id”这个属性的值改变了
- }
- }
- }
- private string name;
- public string Name
- {
- get { return name; }
- set
- {
- name = value;
- if (this.PropertyChanged != null)
- {
- this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); // 通知Binding是“Name”这个属性的值改变了
- }
- }
- }
- private int age;
- public int Age
- {
- get { return age; }
- set { age = value; } // Age的值改变时不进行通知
- }
// 第二步:实现INotifyPropertyChanged接口
public class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; // 这个接口仅包含一个事件而已
private int id;
public int Id
{
get { return id; }
set
{
id = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Id")); // 通知Binding是“Id”这个属性的值改变了
}
}
}
private string name;
public string Name
{
get { return name; }
set
{
name = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name")); // 通知Binding是“Name”这个属性的值改变了
}
}
}
private int age;
public int Age
{
get { return age; }
set { age = value; } // Age的值改变时不进行通知
}
- OK,此时,你可以尝试使用Student类的实例作为数据源了!
OK,此时,你可以尝试使用Student类的实例作为数据源了!
http://liutiemeng.blog.51cto.com/120361/95275
- 让数据“为我所用”的Converter
- 让数据“干干净净”的Validation
- 集合控件与集合数据的Binding
- 偷懒专用的数据中转站——DataContext
- 如果数据源里的值是Y和N,如果是Y,那么UI上的CheckBox就被勾选,否则就不勾选,这就需要我们把string(也许是char)类型的数据转换成bool?类型再使用。如果Binding是TwoWay的,CheckBox的勾选操作还会把值传回数据源。
- 如果“评论内容”TextBox里没有内容,则“提交”Button不可以点击。这是个典型的OneWay数据Binding,因为只有TextBox去影响Button的份儿。具体如何实现,大家可以先猜猜;)
- Convert方法:按照你的要求,把从数据源传来的数据转成你想要的数据——至于是加减乘除还是煎炒炸炖,那就要看你怎么实现函数体了
- ConvertBack方法:如果Binding是TwoWay的,那么数据目标会回传经用户改动后的数据,这时候你就不得不把数据转换回数据源里的格式——大多数情况下,它是Convert方法的逆运算,具体情况还要具体分析。(不过,熟饭估计怎么着也变不成生米了,呵呵~~)
- class ConverterYN2TF
- {
- }
class ConverterYN2TF
{
}
- class ConverterYN2TF : IValueConverter
- {
- #region IValueConverter Members
- public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- #endregion
- }
class ConverterYN2TF : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
- [ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标类型是bool?
- class ConverterYN2TF : IValueConverter
- {
- #region IValueConverter Members
- public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- throw new NotImplementedException();
- }
- #endregion
- }
[ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标类型是bool?
class ConverterYN2TF : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
- [ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标类型是bool?
- class ConverterYN2TF : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- string str = System.Convert.ToString(value);
- switch (str)
- {
- case "Y":
- return true;
- case "N":
- return false;
- default:
- return null;
- }
- }
- public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- bool? b = System.Convert.ToBoolean(value);
- switch (b)
- {
- case true:
- return "Y";
- case false:
- return "N";
- default:
- return "Null";
- }
- }
- }
[ValueConversion(typeof(string), typeof(bool?))] //数据的源类型是string,目标类型是bool?
class ConverterYN2TF : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string str = System.Convert.ToString(value);
switch (str)
{
case "Y":
return true;
case "N":
return false;
default:
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool? b = System.Convert.ToBoolean(value);
switch (b)
{
case true:
return "Y";
case false:
return "N";
default:
return "Null";
}
}
}
- checkBox1.IsThreeState = true;
- Binding binding = new Binding("Text");
- binding.Source = textBox1;
- binding.Converter = new ConverterYN2TF(); // 设定Converter
- this.checkBox1.SetBinding(CheckBox.IsCheckedProperty, binding);
checkBox1.IsThreeState = true;
Binding binding = new Binding("Text");
binding.Source = textBox1;
binding.Converter = new ConverterYN2TF(); // 设定Converter
this.checkBox1.SetBinding(CheckBox.IsCheckedProperty, binding);
- bool类型的IsValid属性告诉Binding回传的数据是否合法
- object类型(一般是存储一个string)的ErrorContent属性告诉Binding一些信息,比如当前是进行什么操作而出现的校验错误等等,一般我会把这些信息写进Log文件里
- public class MyValidationRule : ValidationRule
- {
- public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
- {
- double d = 0.0;
- if (double.TryParse((string)value, out d) && d >= 20 && d <= 35)
- {
- return new ValidationResult(true, "OK");
- }
- else
- {
- return new ValidationResult(false, "Error");
- }
- }
- }
public class MyValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
double d = 0.0;
if (double.TryParse((string)value, out d) && d >= 20 && d <= 35)
{
return new ValidationResult(true, "OK");
}
else
{
return new ValidationResult(false, "Error");
}
}
}
- Binding binding = new Binding("Value");
- binding.Source = slider1;
- binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
- binding.ValidationRules.Add(new MyValidationRule()); // 加载校验条件
- textBox1.SetBinding(TextBox.TextProperty, binding);
Binding binding = new Binding("Value");
binding.Source = slider1;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
binding.ValidationRules.Add(new MyValidationRule()); // 加载校验条件
textBox1.SetBinding(TextBox.TextProperty, binding);

- class Student
- {
- public int StuNum { get; set; }
- public string Name { get; set; }
- public int Age { get; set; }
- }
class Student
{
public int StuNum { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
- <WINDOW title=Window1 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Width="300" Height="300" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="CollectionBinding.Window1">
- <GRID>
- <LISTBOX Background="LightBlue" Margin="5" Name="listBox1" />
- </GRID>
- </WINDOW><PRE></PRE>

- //水之真谛出品
- // [url]http://blog.csdn.net/FantasiaX[/url]
- public Window1()
- {
- InitializeComponent();
- List<Student> stuList = new List<Student>()
- {
- new Student{StuNum=1, Name="Tim", Age=28},
- new Student{StuNum=2, Name="Ma Guo", Age=25},
- new Student{StuNum=3, Name="Yan", Age=25},
- new Student{StuNum=4, Name="Xaiochen", Age=28},
- new Student{StuNum=5, Name="Miao miao", Age=24},
- new Student{StuNum=6, Name="Ma Zhen", Age=24}
- };
- this.listBox1.ItemsSource = stuList;
- this.listBox1.DisplayMemberPath = "Name";
- }

- <Window x:Class="CollectionBinding.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="水之真谛" Height="300" Width="300">
- <StackPanel>
- <ListBox Name="listBox1" Margin="5" Height="150" Background="LightBlue"/>
- <TextBox Name="stuNumTextBox" Margin="5" Background="LightGreen"/>
- <TextBox Name="nameTextBox" Margin="5" Background="LightGreen"/>
- <TextBox Name="ageTextBox" Margin="5" Background="LightGreen"/>
- </StackPanel>
- </Window>

- public Window1()
- {
- InitializeComponent();
- List<Student> stuList = new List<Student>()
- {
- new Student{StuNum=1, Name="Tim", Age=28},
- new Student{StuNum=2, Name="Ma Guo", Age=25},
- new Student{StuNum=3, Name="Yan", Age=25},
- new Student{StuNum=4, Name="Xaiochen", Age=28},
- new Student{StuNum=5, Name="Miao miao", Age=24},
- new Student{StuNum=6, Name="Ma Zhen", Age=24}
- };
- this.listBox1.ItemsSource = stuList;
- this.listBox1.DisplayMemberPath = "Name";
- this.listBox1.SelectedValuePath = "StuNum";
- this.stuNumTextBox.SetBinding(TextBox.TextProperty, new Binding("SelectedValue") { Source = this.listBox1 });
- }

- public Window1()
- {
- InitializeComponent();
- List<Student> stuList = new List<Student>()
- {
- new Student{StuNum=1, Name="Tim", Age=28},
- new Student{StuNum=2, Name="Ma Guo", Age=25},
- new Student{StuNum=3, Name="Yan", Age=25},
- new Student{StuNum=4, Name="Xaiochen", Age=28},
- new Student{StuNum=5, Name="Miao miao", Age=24},
- new Student{StuNum=6, Name="Ma Zhen", Age=24}
- };
- this.listBox1.ItemsSource = stuList;
- this.listBox1.DisplayMemberPath = "Name";
- //this.listBox1.SelectedValuePath = "StuNum";
- this.stuNumTextBox.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.StuNum") { Source = this.listBox1 });
- this.nameTextBox.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Name") { Source = this.listBox1 });
- this.ageTextBox.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Age") { Source = this.listBox1 });
- }
- <Window x:Class="CollectionBinding.Window1"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="水之真谛" Height="300" Width="300">
- <StackPanel>
- <ListBox Name="stuListBox" Margin="5" Height="70" Background="LightBlue"/>
- <ListBox Name="tchrListBox" Margin="5" Height="70" Background="LightPink"/>
- <TextBox Name="idTextBox" Margin="5" Background="LightGreen"/>
- <TextBox Name="nameTextBox" Margin="5" Background="LightGreen"/>
- <TextBox Name="ageTextBox" Margin="5" Background="LightGreen"/>
- </StackPanel>
- </Window>

- interface ISchoolMember
- {
- int ID { get; set; }
- string Name { get; set; }
- int Age { get; set; }
- }
- class Student : ISchoolMember
- {
- public int ID { get; set; }
- public string Name { get; set; }
- public int Age { get; set; }
- }
- class Teacher : ISchoolMember
- {
- public int ID { get; set; }
- public string Name { get; set; }
- public int Age { get; set; }
- }
- public Window1()
- {
- InitializeComponent();
- List<Student> stuList = new List<Student>()
- {
- new Student{ID=1, Name="Tim", Age=28},
- new Student{ID=2, Name="Ma Guo", Age=25},
- new Student{ID=3, Name="Yan", Age=25},
- };
- List<Teacher> tchrList = new List<Teacher>()
- {
- new Teacher{ID=1, Name="Ma Zhen", Age=24},
- new Teacher{ID=2, Name="Miao miao", Age=24},
- new Teacher{ID=3, Name="Allen", Age=26}
- };
- stuListBox.ItemsSource = stuList;
- tchrListBox.ItemsSource = tchrList;
- stuListBox.DisplayMemberPath = "Name";
- tchrListBox.DisplayMemberPath = "Name";
- stuListBox.SelectionChanged += (sender, e) => { this.DataContext = this.stuListBox.SelectedItem; };
- tchrListBox.SelectionChanged += (sender, e) => { this.DataContext = this.tchrListBox.SelectedItem; };
- this.idTextBox.SetBinding(TextBox.TextProperty, new Binding("ID"));
- this.nameTextBox.SetBinding(TextBox.TextProperty, new Binding("Name"));
- this.ageTextBox.SetBinding(TextBox.TextProperty, new Binding("Age"));
- }

- Binding与Routed Event结合(常见的是在有数据流动时,Binding抛出一些Routed Event,由外界捕捉处理)
- Binding与Command结合
- Binding与ItemsControl的ItemTemplate/CellTemplate等DataTemplate的结合——这个非常重要,甚至是每天工作的主要内容,我会用专门的文章去介绍
- 如果你想自己创建一个集合类,让它可以与Binding配合使用,别忘了它的元素一定要实现INotifyPropertyChanged接口,而这个集合自身要是(或者派生自)ObservableCollection<T>……实际上太多东西需要在实际工作中去摸索和掌握了,一两篇文章只是杯水车薪——我也不想像琼瑶姐姐那样上、中、下、继、再继、再再继……
[转]深入浅出WPF(7)——数据的绿色通道,Binding的更多相关文章
- 《深入浅出WPF》学习总结之Binding
一.前言 友好的图形用户界面(Graphics User Interface ,GUI)的流行也就是近十来年的事情,之前应用程序与用户的交互是通过控制台界面(Console User Interfac ...
- 《深入浅出WPF》重点摘要(—)Binding自动通知机制
最近因为公司的项目需要用WPF开发,就学习了一下WPF.刚开始只是用到什么就百度什么,虽然功能是实现了,但还是没有弄清楚原理(如果不弄清原理,会感觉很心虚,整个人会没底气),所以决定找个教程系统地学一 ...
- 深入浅出WPF(1)—转(http://liutiemeng.blog.51cto.com/120361/91631/)
深入浅出WPF(1)——什么是WPF 2008-05-15 19:06:00 小序: Hi,大家好!几乎两个月没有写技术文章了.这两个月,我在学习WPF.回顾一下两个月的学习历程,有两个感觉— ...
- 《深入浅出WPF》 学习笔记
<深入浅出WPF> 序言 1. 什么是WPF 2. 为什么要学习WPF 第一章 XAML概览 1. XAML是什么? 2. XAML有哪些优点 第二章 从零起步认识XAML 1. 新 ...
- 《深入浅出WPF》笔记——模板篇
原文:<深入浅出WPF>笔记--模板篇 我们通常说的模板是用来参照的,同样在WPF中,模板是用来作为制作控件的参照. 一.认识模板 1.1WPF菜鸟看模板 前面的记录有提过,控件主要是算法 ...
- [WPF系列]-数据邦定之DataTemplate 根据对象属性切换模板
引言 书接上回[WPF系列-数据邦定之DataTemplate],本篇介绍如何根据属性切换模板(DataTemplate) 切换模板的两种方式: 使用DataTemplateSelecto ...
- 深入浅出WPF开发下载
为什么要学习WPF? 许多朋友也许会问:既然表示层技术那么多,为什么还要推出WPF作为表示层技术呢?我们话精力学习WPF有什么收益和好处呢,这个问题我们从两个方面进行回答. 首先,只要开发表示层程序 ...
- 【【分享】深入浅出WPF全系列教程及源码
】
因为原书作者的一再要求,在此声明,本书中的部分内容引用了原书名为<深入浅出WPF>的部分内容,假设博文不能满足你现有的学习须要,能够购买正版图书! 本人10月份提出离职,可是交接非常慢,预 ...
- 《深入浅出WPF》笔记——绘画与动画
<深入浅出WPF>笔记——绘画与动画 本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一 ...
随机推荐
- 如何去除Office Excel的密码保护?
企图更改Excel文件内容,然而却弹出如下提示: 根据提示,我尝试解除保护表,却要求输入密码: 这就尴尬了=_=密码不是我设定的 问了度娘,找到了解决方案 将Excel文件扩展名更改为rar, 使用压 ...
- 创建Material Design风格的Android应用--应用主题
本人全部文章首先公布于个人博客,欢迎关注,地址:http://blog.isming.me 昨天正式公布了android 5,同一时候android developer站点也更新了,添加了创建Mate ...
- java.lang.ClassNotFoundException: org.springframework.boot.context.embedded.FilterRegistrationBean
java.lang.ClassNotFoundException: org.springframework.boot.context.embedded.FilterRegistrationBean 把 ...
- linux驱动开发之九鼎板载蜂鸣器驱动测试【转】
本文转载自:http://whylinux.blog.51cto.com/10900429/1932491 字符设备驱动用的fileopretion结构体. 1.板载蜂鸣器的驱动测试 我手里有一个BS ...
- 字符串查找函数(BF)
//模拟字符串定位函数 // s: abcbbghi // t: ghi // 返回6 #include <iostream> #include <string> #inclu ...
- dedecms获取顶级栏目名称、二级栏目名称实现方法
织梦DEDECMS文章.栏目页获取当前页面顶级栏目名称的方法 在用织梦做一些项目时,时常会碰到需要在当前页面调用顶级栏目名称的时候,织梦默认{dede:field name='typename' /} ...
- Vue安装及插件Vue Devtools
vue安装: # 最新稳定版 $ npm install vue # 全局安装 vue-cli $ npm install --global vue-cli # 创建一个基于 webpack 模板的新 ...
- codeforces 673D D. Bear and Two Paths(构造)
题目链接: D. Bear and Two Paths time limit per test 2 seconds memory limit per test 256 megabytes input ...
- python中的编码和解码
计算机中常见的编码方式有多种,英文一般是ascii编码,其他有unicode,utf-8,gbk,utf-16等编码. 常见编码方式: ASCII编码:ASCII是早期的编码,包含英文字母.数字和 ...
- HDU5890:Eighty seven(Bitset优化背包)
Mr. Fib is a mathematics teacher of a primary school. In the next lesson, he is planning to teach ch ...