(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报告所有异常

五、数据提供者 ??