(24)WPF 数据绑定
一、绑定自定义对象
1.绑定
<StackPanel Name="StudentPanel" > <TextBox Text="{Binding Path=Id}" Height="30" Width="100"></TextBox> <TextBox Text="{Binding Path=Age}" Height="30" Width="100"></TextBox> <TextBox Text="{Binding Path=Name}" Height="30" Width="100"></TextBox> <Button Name="btn1" Click="btn1_Click" Height="30" Width="100"></Button> </StackPanel>
public partial class MainWindow : Window { Student student; public MainWindow() { InitializeComponent(); student = new Student(1,15,"Tom"); } private void btn1_Click(object sender, RoutedEventArgs e) { StudentPanel.DataContext = student; } } class Student { private int id; private int age; private string name; public Student(int id, int age, string name) { this.id = id; this.age = age; this.name = name; } public int Id { get => id; set => id = value; } public int Age { get => age; set => age = value; } public string Name { get => name; set => name = value; } }
2.输入控件自动修改绑定类
当给TextBox输入数据并失去焦点后,Student会自动赋值
注意如果按钮可以用回车来执行,这就使得在未更新的情况下进行了提交
最好按钮前强制转移焦点
<Button Name="btn2" Click="btn2_Click" IsDefault="True" Height="30" Width="100"></Button>
private void btn2_Click(object sender, RoutedEventArgs e) { FocusManager.SetFocusedElement(this, (Button)sender); MessageBox.Show(student.Name); }
3.更改通知
如果有按钮改变student类的name,从而想达到自动更新界面name对应的textbox的效果,有三种方法
(1)把Product中的属性改未依赖项属性
(2)引发 porpertyNameChange事件
(3)student类实现InotifyPropertyChanged接口
private void btn2_Click(object sender, RoutedEventArgs e) { student.Name = "Lick"; MessageBox.Show(student.Name); }
class Student :INotifyPropertyChanged { private int id; private int age; private string name; public Student(int id, int age, string name) { this.id = id; this.age = age; this.name = name; } public int Id { get => id; set => id = value; } public int Age { get => age; set => age = value; } //新增 public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) PropertyChanged(this, e); } public string Name { get => name; set { name = value; OnPropertyChanged(new PropertyChangedEventArgs("Name")); } } }
二、绑定对象集合
所有派生自ItemsControl的类,都支持集合数据绑定。(ListBox,Combobox,ListView,DataGrid,Menu,TreeView)
ItemsControl类属性
- ItemsSource
- DisplayMemberPath
- ItemTemplate
1.绑定
<StackPanel Name="StudentPanel" DataContext="{Binding ElementName=listBox,Path=SelectedItem}" > <ListBox Name="listBox" Height="100" Width="200"></ListBox> <TextBox Text="{Binding Path=Id}" Height="30" Width="100"></TextBox> <TextBox Text="{Binding Path=Age}" Height="30" Width="100"></TextBox> <TextBox Text="{Binding Path=Name}" Height="30" Width="100"></TextBox> </StackPanel>
Student student1; Student student2; List<Student> list = new List<Student>(); public MainWindow() { InitializeComponent(); student1 = new Student(1,15,"Tom"); student2 = new Student(2, 17, "Maiko"); list.Add(student1); list.Add(student2); listBox.ItemsSource = list; }
2.添加删除
使用ObservableCollection<Student> 代替List<Student>,可以实现增删效果
Student student1; Student student2; ObservableCollection<Student> list = new ObservableCollection<Student>(); public MainWindow() { InitializeComponent(); student1 = new Student(1,15,"Tom"); student2 = new Student(2, 17, "Maiko"); list.Add(student1); list.Add(student2); listBox.ItemsSource = list; } private void btn1_Click(object sender, RoutedEventArgs e) { list.Remove((Student)listBox.SelectedItem); }
3.绑定Ado.net
绑定和增删
DataTable dt = new DataTable(); public MainWindow() { InitializeComponent(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("Age", typeof(int)); dt.Columns.Add("Name"); DataRow dr1 = dt.NewRow(); dr1["Id"] = 1; dr1["Age"] = 15; dr1["Name"] = "Tom"; dt.Rows.Add(dr1); DataRow dr2 = dt.NewRow(); dr2["Id"] = 2; dr2["Age"] = 19; dr2["Name"] = "Luck"; dt.Rows.Add(dr2); listBox.ItemsSource = dt.DefaultView; } private void btn1_Click(object sender, RoutedEventArgs e) { ((DataRowView)listBox.SelectedItem).Row.Delete(); }
4.绑定到Linq表达式
三、提高大列表性能 ??
1.虚拟化
ListBox ListView DataGrid 自动使用VirtualizingStackPanel面板布局它们的子元素。
ComboBox需要明确通过ItemPanelTemplate来支持虚拟化
<ComboBox> <ComboBox.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel></VirtualizingStackPanel> </ItemsPanelTemplate> </ComboBox.ItemsPanel> </ComboBox>
TreeView默认支持虚拟化是关闭着的,开启
<TreeView VirtualizingStackPanel.IsVirtualizing="True"></TreeView>
有可能会破坏虚拟化的条件:
- ScrollViewer中放置列表控件
- 改变列表控件的模板并且没有使用ItemsPresenter
- 不使用数据绑定
2.项容器再循环
<ListBox VirtualizingStackPanel.VirtualizationMode="Recycling"></ListBox>
3.缓存长度
<ListBox VirtualizingStackPanel.CacheLength="100" VirtualizingStackPanel.CacheLengthUnit="Item"></ListBox>
4.延迟滚动
<ListBox ScrollViewer.IsDeferredScrollingEnabled="True"></ListBox>
<ListBox VirtualizingStackPanel.ScrollUnit="Pixel"></ListBox>
四、验证 ???
1.在数据对象中进行验证
public partial class MainWindow : Window { Student student; public MainWindow() { InitializeComponent(); student = new Student(); //绑定 StudentPanel.DataContext = student; } private void btn1_Click(object sender, RoutedEventArgs e) { try { student.Age =Convert.ToInt32(tb1.Text); } catch (Exception ex) { MessageBox.Show(ex.Message); return; } MessageBox.Show(student.Age.ToString()); } } class Student { int age=10; public int Age { get => age; set { if (value <= 0) { throw new Exception("请输入正数"); } } } }
2.在绑定级别的验证
ExceptionValidationRule 是预先构建的验证规则,它向WPF报告所有异常