WPF数据绑定学习

时间:2022-05-08 19:23:17


WPF技术的最显著的特点是实现了UI和逻辑业务的分离,并用数据绑定来关联两者。本文通过一个简单的实例来总结一下WPF中数据绑定的方法,本例还用到了数据库操作和泛型集合的使用方法。

1.      UI和功能

左上方Border区域内有三个Label控件、三个TextBox控件和三个Button控件,TextBox控件用于接收用户输入和显示选择的内容,Button控件分别实现数据库的添加、删除、修改操作。右上Border区域内有两个Label控件、一个Combo控件、一个TextBox控件和一个Button控件,左下为DataGrid控件,右下为ListView控件。程序启动时DataGrid控件显示数据库tb_User表中所有的元素,ListView控件显示按条件查询的结果,鼠标可以从DataGrid控件、ListView控件中选择条目,显示在左上的TextBox控件中,从而进行修改和删除操作。

WPF数据绑定学习

代码如下,其中数据绑定部分关键代码加粗标出,后面再解释。

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF" x:Class="WPF.MainWindow"
Title="用户设置" Height="720"Width="1024"Background="{DynamicResource{x:StaticSystemColors.ControlBrushKey}}" ResizeMode="NoResize"FontSize="14">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="265*"/>
<ColumnDefinition Width="243*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="330*"/>
<RowDefinition Height="359*"/>
</Grid.RowDefinitions>
<TextBox x:Name="tbx_User"HorizontalAlignment="Left" Height="35"Margin="160,80,0,0"TextWrapping="Wrap"VerticalAlignment="Top" Width="150"FontSize="16" BorderBrush="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"/>
<TextBox x:Name="tbx_KeyWord"HorizontalAlignment="Left" Height="35"Margin="160,160,0,0"TextWrapping="Wrap"VerticalAlignment="Top" Width="150"FontSize="16" BorderBrush="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"/>
<TextBox x:Name="tbx_Auth"HorizontalAlignment="Left" Height="35"Margin="160,240,0,0"TextWrapping="Wrap" VerticalAlignment="Top"Width="150" FontSize="16"BorderBrush="{DynamicResource{x:StaticSystemColors.ControlDarkDarkBrushKey}}"/>
<Button x:Name="btn_Add" Content="添加用户"HorizontalAlignment="Left" Height="40"Margin="360,80,0,0"VerticalAlignment="Top" Width="120"FontSize="16" Click="btn_Add_Click"/>
<Button x:Name="btn_Remove"Content="删除用户"HorizontalAlignment="Left" Height="40"Margin="360,160,0,0"VerticalAlignment="Top" Width="120"FontSize="16" Click="btn_Remove_Click"/>
<Button x:Name="btn_Upate"Content="编辑用户"HorizontalAlignment="Left" Height="40"Margin="360,240,0,0"VerticalAlignment="Top" Width="120"FontSize="16" Click="btn_Upate_Click"/>
<Label Content="用户名"HorizontalAlignment="Left" Height="40"Margin="60,75,0,0"VerticalAlignment="Top" Width="80"FontSize="16"/>
<Label Content="密码"HorizontalAlignment="Left" Height="40"Margin="60,155,0,0"VerticalAlignment="Top" Width="80"FontSize="16"/>
<Label Content="权限"HorizontalAlignment="Left" Height="40"Margin="60,235,0,0"VerticalAlignment="Top" Width="80"FontSize="16"/>
<Border BorderBrush="Black"BorderThickness="1" HorizontalAlignment="Left"Height="305" Margin="20,20,0,0"VerticalAlignment="Top" Width="490"/>
<ComboBox x:Name="cbx_condition"Grid.Column="1" HorizontalAlignment="Left"Height="35" Margin="200,80,0,0"VerticalAlignment="Top" Width="165"FontSize="16">
<ComboBoxItem Content="按用户名"/>
<ComboBoxItem Content="按用户权限"/>
</ComboBox>
<Label Content="查询条件"Grid.Column="1" HorizontalAlignment="Left"Height="40" Margin="60,80,0,0"VerticalAlignment="Top" Width="100"FontSize="16"/>
<Button x:Name="btn_Select"Content="查询"Grid.Column="1" HorizontalAlignment="Left"Height="40" Margin="200,235,0,0"VerticalAlignment="Top" Width="160"FontSize="16" Click="btn_Select_Click"/>
<TextBox x:Name="tbx_forselect"Grid.Column="1" HorizontalAlignment="Left"Height="40" Margin="200,160,0,0"TextWrapping="Wrap"VerticalAlignment="Top" Width="160"FontSize="16"/>
<Label Content="关键字"Grid.Column="1" HorizontalAlignment="Left"Height="40" Margin="60,160,0,0"VerticalAlignment="Top" Width="100"FontSize="16"/>
<Border BorderBrush="Black"BorderThickness="1" Grid.Column="1"HorizontalAlignment="Left" Height="305"Margin="5,20,0,0"VerticalAlignment="Top" Width="460"/>
<DataGrid x:Name="GridView1"HorizontalAlignment="Left" Margin="20,50,0,0"Grid.Row="1" VerticalAlignment="Top"Height="290" Width="490"BorderBrush="{DynamicResource{x:StaticSystemColors.ActiveCaptionTextBrushKey}}"IsReadOnly="True"SelectionChanged="GridView1_SelectionChanged" <strong><span style="color:#ff0000;">ItemsSource="{Binding LT,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MainWindow}}}" ></span></strong>
<DataGrid.ItemBindingGroup>
<BindingGroup/>
</DataGrid.ItemBindingGroup>
</DataGrid>
<Label Content="用户列表"HorizontalAlignment="Left" Height="40"Margin="25,10,0,0" Grid.Row="1"VerticalAlignment="Top" Width="135"FontSize="16"/>
<Label Content="查询结果"HorizontalAlignment="Left" Height="40"Margin="20,15,0,0" Grid.Row="1"VerticalAlignment="Top" Width="135"FontSize="16" Grid.Column="1"/>
<ListView x:Name="ListView1"Grid.Column="1" HorizontalAlignment="Left"Height="290" Margin="5,50,0,0"Grid.Row="1" VerticalAlignment="Top"Width="460" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveCaptionTextBrushKey}}"<span style="color:#ff0000;"><strong>ItemsSource="{Binding DataList,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:MainWindow}}}"</strong></span>SelectionChanged="ListView1_SelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn Header="UserID"Width="230"<span style="color:#ff0000;"><strong>DisplayMemberBinding="{BindingUserID}"</strong></span>/>
<GridViewColumnHeader="Auth" Width="230"<strong><span style="color:#ff0000;">DisplayMemberBinding="{Binding Auth}"</span></strong>/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>


2.      数据库定义

数据库用Microsoft SQL Server 2008创建,名为db_Nord,其中有一个表tb_User,字段和初始内容如下图,后面程序只对本表操作。

WPF数据绑定学习

3.      类设计

3.1    首先将数据库操作相关的方法封装为类DatabaseClass,其代码如下:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Windows;

namespace WPF.ClassLib
{
public class DatabaseClass
{
private string ConnectionString=Properties.Settings.Default.ConnectionString;
#region 连接数据库
private SqlConnection GetConnection()
{
try
{
SqlConnection sqlcon = new SqlConnection("Data Source=WIN-01410121400\\SQLEXPRESS;Initial Catalog=db_Nord;User ID=sa;Password=admin2016");
return sqlcon;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "数据库连接失败");
return null;
}
}
#endregion

#region 从SqlDataReader对象生成类成员列表
private List<UserClass> GetList(SqlDataReader sdr)
{
List<UserClass> lt =new List<UserClass>();
while (sdr.Read())
{
lt.Add(new UserClass(sdr[0].ToString(),sdr[1].ToString(),sdr[2].ToString()));
}
return lt;
}
#endregion

#region 增加记录
public void Add(UserClass user)
{
SqlConnection sc = GetConnection();
try
{
sc.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = sc;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO tb_User(UserID,KeyWord,Auth)VALUES(@UserID,@KeyWord,@Auth)";
cmd.Parameters.Add("@UserID",SqlDbType.VarChar).Value=user.UserID;
cmd.Parameters.Add("@KeyWord", SqlDbType.VarChar).Value = user.KeyWord;
cmd.Parameters.Add("@Auth", SqlDbType.VarChar).Value = user.Auth;
cmd.ExecuteNonQuery();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "添加记录失败");
}
finally
{
if (sc.State==ConnectionState.Open)
{
sc.Close();
}
}
}
#endregion

#region 删除记录
public void Remove(string UserID)
{
SqlConnection sc = GetConnection();
try
{
sc.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = sc;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "DELETE FROM tb_user WHERE UserID=@UserID";
cmd.Parameters.Add("@UserID",SqlDbType.VarChar).Value=UserID;
cmd.ExecuteNonQuery();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "删除记录失败");
}
finally
{
if (sc.State==ConnectionState.Open)
{
sc.Close();
}
}
}
#endregion

#region 更新记录
public void Update(UserClass User)
{
SqlConnection sc = GetConnection();
try
{
sc.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = sc;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "UPDATE tb_user SET UserID=@UserID,KeyWord=@KeyWord,Auth=@Auth WHERE UserID=@UserID";
cmd.Parameters.Add("@UserID", SqlDbType.VarChar).Value = User.UserID;
cmd.Parameters.Add("@KeyWord", SqlDbType.VarChar).Value = User.KeyWord;
cmd.Parameters.Add("@Auth", SqlDbType.VarChar).Value = User.Auth;
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "更改记录失败");
}
finally
{
if (sc.State == ConnectionState.Open)
{
sc.Close();
}
}
}
#endregion

# region 查询全部记录
public List<UserClass> Select()
{
SqlConnection sc = GetConnection();
try
{
sc.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = sc;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT * FROM tb_user";
return GetList(cmd.ExecuteReader());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "查找记录失败");
return null;
}
finally
{
if (sc.State == ConnectionState.Open)
{
sc.Close();
}
}
}
#endregion

# region 按SQL语句查询记录
public List<UserClass> ConditionSelect(SqlCommand SQLstr)
{
SqlConnection sc = GetConnection();
try
{
sc.Open();
SqlCommand cmd =SQLstr;
cmd.Connection = sc;
return GetList(cmd.ExecuteReader());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "查找记录失败");
return null;
}
finally
{
if (sc.State == ConnectionState.Open)
{
sc.Close();
}
}
}
#endregion
}
}


3.2    将数据实体对象封装为UserClass类,提供给WPF绑定数据源,代码如下:

namespace WPF.ClassLib
{
    public  class UserClass
    {
        private string userid;
        private string keyword;
        private string auth;
        public  string UserID
        {
            get { return userid; }
            set { userid = value; }
        }
        public string KeyWord
        {
            get { return keyword; }
            set { keyword = value; }
        }
        public  string Auth
        {
            get { return auth; }
            set { auth = value; }
        }
        public UserClass(string userid, string keyword, string auth)
        {
            this.UserID = userid;
            this.KeyWord = keyword;
            this.Auth = auth;
        }
    }
}

4.      主程序代码

主程序代码启动时读取数据库tb_User表中所有的内容并显示在DataGrid控件中,还要实现文本框的一些操作。另外数据绑定必须定义依赖属性,因此定义了ObservableCollection<T>泛型集合和List <T>泛型列表公共属性,ListView、DataGrid控件分别绑定到其公共属性上。代码如下:

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using WPF.ClassLib;
using System.Data;
using System.Data.SqlClient;
using System.Collections.ObjectModel;


namespace WPF
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
DatabaseClass dt = new DatabaseClass();
private ObservableCollection<UserClass> datalist = new ObservableCollection<UserClass>();
public ObservableCollection<UserClass> DataList
{
get { return this.datalist; }
}
private List<UserClass> lt = new List<UserClass>();
public List<UserClass> LT
{
get { return this.lt; }
}
public MainWindow()
{
InitializeComponent();
lt = dt.Select();
cbx_condition.SelectedIndex=0;
}
private void btn_Add_Click(object sender, RoutedEventArgs e)
{
if (tbx_User.Text != "" && tbx_KeyWord.Text != "" && tbx_Auth.Text != "")
{
UserClass uc = new UserClass(tbx_User.Text, tbx_KeyWord.Text, tbx_Auth.Text);
dt.Add(uc);
}
else
{
MessageBox.Show("请输入完整","添加失败");
}
GridView1.ItemsSource = dt.Select();
}


private void btn_Remove_Click(object sender, RoutedEventArgs e)
{
string userid=tbx_User.Text;
UserClass uc = new UserClass(tbx_User.Text, tbx_KeyWord.Text, tbx_Auth.Text);
if (userid!="")
{
dt.Remove(uc.UserID);
}
else
{
MessageBox.Show("请选择要删除的用户", "操作失败");
}
GridView1.ItemsSource = dt.Select();
}


private void btn_Upate_Click(object sender, RoutedEventArgs e)
{
if (tbx_User.Text != "" && tbx_KeyWord.Text != "" && tbx_Auth.Text != "")
{
UserClass uc1 = new UserClass(tbx_User.Text, tbx_KeyWord.Text, tbx_Auth.Text);
dt.Update(uc1);
}
else
{
MessageBox.Show("请输入完整", "更新失败");
}
GridView1.ItemsSource = dt.Select();
}
        private void btn_Select_Click(object sender, RoutedEventArgs e)        {                        List<UserClass> ltt = new List<UserClass>();            int cbx = cbx_condition.SelectedIndex;            SqlCommand cmd = new SqlCommand();            cmd.CommandType = CommandType.Text;            datalist.Clear();            if (cbx==0)            {                //按用户名查询                cmd.CommandText = "SELECT * FROM tb_User WHERE UserID = @UserID";                cmd.Parameters.Add("@UserID", SqlDbType.VarChar).Value = tbx_forselect.Text;            }            else            {                //按权限查询                cmd.CommandText = "SELECT * FROM tb_User WHERE Auth = @Auth";                cmd.Parameters.Add("@Auth", SqlDbType.VarChar).Value = tbx_forselect.Text;            }            ltt = dt.ConditionSelect(cmd);            if (lt.Count != 0)            {                for (int i = 0; i <= ltt.Count-1; i++)                {                    datalist.Add(new UserClass(ltt[i].UserID,ltt[i].KeyWord,ltt[i].Auth ));                }            }                     // ListView1.ItemsSource = this.DataList;   //xaml中已经绑定        }        private void GridView1_SelectionChanged(object sender, SelectionChangedEventArgs e)        {            UserClass ul = this.GridView1.SelectedItem as UserClass;            if (ul!=null)            {                tbx_User.Text = ul.UserID;                tbx_KeyWord.Text = ul.KeyWord;                tbx_Auth.Text = ul.Auth;            }        }        private void ListView1_SelectionChanged(object sender, SelectionChangedEventArgs e)        {             UserClass ul = this.ListView1.SelectedItem as UserClass;             if (ul != null)             {                 tbx_User.Text = ul.UserID;                 tbx_KeyWord.Text = ul.KeyWord;                 tbx_Auth.Text = ul.Auth;             }        }    }}

5.      数据绑定

从上面MainWindow.cs代码中可以看到,DataGrid控件和ListView控件只添加了一个SelectionChanged事件处理方法,用于将选择的条目显示在左上的文本框中,除此没有任何事件处理方法,其内容通过数据绑定来呈现。

绑定前先要指定数据源命名空间,前面在WPF命名空间中定义了ObservableCollection<T>泛型集合和List <T>泛型列表,本例可以在UI代码中看到Visual Studio自动添加了它们所在的命名空间和类的位置:

         xmlns:local="clr-namespace:WPF"x:Class="WPF.MainWindow"

如果数据源定义不在内容控件所在的命名空间,就需要指定其所在的命名空间。如下:

         xmlns:my="namespace:myNameSpace "

其中my为自定义标识,myNameSpace为数据源所在命名空间名称。接着需要在MainWindow类中定义资源:

<MainWindow.Resoures>
<my:myClass x:Key="myData"/>
</MainWindow.Resoures>

myClass为数据源所在命名空间中的类名,这样内容控件就可以绑定到myData上,如后面的LT用myData.LT替换即可。

先来看DataGrid控件数据的绑定,DataGrid控件派生自List类,因此需要为其指定ItemsSource,这里将其绑定到LT上,LT是在MainWindow类中定义的泛型列表List<UserClass>数据集合,RelativeSource用来指定绑定源相对于绑定目标的位置,获取或设置绑定源。这里的绑定实际上是用“数据绑定”向导实现的,不需要手工添加代码。

ItemsSource="{Binding LT, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"

WPF数据绑定学习

再来看ListView控件,ListView控件派生自ListBox类,它可以显示多列数据。经尝试不能将其绑定到List<UserClass>数据源,但可以绑定到ObservableCollection<UserClass>数据源上。首先指定ItemsResource数据源,方法如前使用向导实现。代码如下:

ItemsSource="{Binding DataList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"

接着添加要显示的数据列,表中数据共有3列,这里只显示2列,列名为UserIDAuth,并为列指定数据源路径DisplayMemberBindingUserIDAuthItemsSource数据源DataList下的数据路径。

   <GridViewColumn Header="UserID" Width="230" DisplayMemberBinding="{Binding UserID}"/>
<GridViewColumn Header="Auth" Width="230" DisplayMemberBinding="{Binding Auth}"/>

至此,DataGrid控件和ListView控件的数据绑定已经完成。通常文本框也可以通过数据绑定来显示数据,但左上文本框的数据源可能是DataGrid控件或ListView控件,WPF不能实现一对多的绑定。

 

LeiZhanfang

2016-02-14