65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 中的 DataView 分页

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (10投票s)

2007年9月12日

CPOL

2分钟阅读

viewsIcon

164823

downloadIcon

4053

WPF 中 DataView 的自定义分页。

引言

在 WPF (Windows Presentation Foundation) 中,与 Visual Studio 2005 不同的是,GridView 控件没有内置的分页支持 (我认为。可能我遗漏了什么)。 当我使用 GridView 在 WPF 中进行一些测试编码并想要分页支持时,我像往常一样在 Google 上搜索,但没有用。 经过大量搜索后,我决定为此目的实现自定义分页。 完成后,我决定与他人分享,因为关于 WPF 的文章并不多。

在本文中,我将解释如何创建 DataView,如何将其绑定到动态数据源,并且我还将解释关于实现分页。 分页逻辑非常简单,可以在任何其他类似情况下使用。

在这里,我将使用 Northwind 作为数据库和两个表 Products 作为数据。

首先,创建一个 GridView 来显示数据。 要创建 gridview,请使用此语法

<ListView Name="lstProducts">
   <ListView.View>
    <GridView></GridView>
   </ListView.View>
</ListView>

要创建列,请使用此语法

<GridViewColumn Header="ProductID"></GridViewColumn>

要将数据源绑定到 gridview,请将 ItemsSource 属性设置为 "{Binding}" ,并将数据库字段绑定到 gridviewcolumn,将 DisplayMemberBinding 属性设置为 "{Binding Path=[FieldName]}"

因此,这是可绑定 gridview 的 XAML

<ListView Margin="15,115,15,48" Name="lstProducts" ItemsSource="{Binding}">
   <ListView.View>
      <GridView>
        <GridViewColumn Header="ProductID"
             DisplayMemberBinding="{Binding Path=ProductID}"></GridViewColumn>
          <GridViewColumn Header="Product Name"
               DisplayMemberBinding="{Binding Path=ProductName}"></GridViewColumn>
          <GridViewColumn Header="SupplierID"
               DisplayMemberBinding="{Binding Path=SupplierID}"></GridViewColumn>
          <GridViewColumn Header="CategoryID"
               DisplayMemberBinding="{Binding Path=CategoryID}"></GridViewColumn>
          <GridViewColumn Header="Qty. Per Unit"
               DisplayMemberBinding="{Binding Path=QuantityPerUnit}"></GridViewColumn>
          <GridViewColumn Header="Unit Price"
               DisplayMemberBinding="{Binding Path=UnitPrice}"></GridViewColumn>
          <GridViewColumn Header="In Stock"
               DisplayMemberBinding="{Binding Path=UnitInStock}"></GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

在代码隐藏中,编写代码将数据绑定到 gridview。 这是绑定数据的函数

private void ListProducts()
{
     sqlCon = new SqlConnection();
     sqlCon.ConnectionString = \\ConnectionString.

     cmd = new SqlCommand();
     cmd.Connection = sqlCon;
     cmd.CommandType = CommandType.Text;
     cmd.CommandText = "SELECT * FROM Products";

     sqlDa = new SqlDataAdapter();
     sqlDa.SelectCommand = cmd;

     ds = new DataSet();
     try
     {
         sqlDa.Fill(ds,"Products");

         if (ds.Tables["Products"].Rows.Count > 0)
         {
             lstProducts.DataContext = ds.Tables["Products"].DefaultView;
         }
         else
         {
              MessageBox.Show("Message");
         }
      }
      catch (Exception ex)
      {
          MessageBox.Show("Error Message");
      }
      finally
      {
          sqlDa.Dispose();
          cmd.Dispose();
          sqlCon.Dispose();
      }
 }

要在窗口的 Loaded 事件(Visual Studio 2005 中的 Load 事件)中调用此函数,请像这样更新 XAML

<Window
.......
Loaded="OnLoad"
>

*.cs 文件中编写 OnLoad 处理程序的代码。

private void OnLoad(object sender, System.EventArgs e)
{
    ListProducts();
}

现在我们有了列出所有产品的网格。 让我们开始实现 分页。 首先,我们需要为 分页 创建 buttonButton 使用 <Button></Button> 标签创建。 对于单击事件,请使用 Click="EventName"

因此,这是带有事件的 button 的 XAML

<Button Height="23" HorizontalAlignment="Left" Margin="18,0,0,22"
    Name="btnFirst" VerticalAlignment="Bottom" Width="40"
    Content="&lt;&lt;" Click="btnFirst_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,474,22"
    Name="btnNext" VerticalAlignment="Bottom" Width="40"
    Content="&gt;" Click="btnNext_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,429,22"
    VerticalAlignment="Bottom" Width="40" Name="btnLast"
    Click="btnLast_Click" Opacity="0.75" Content="&gt;&gt;">
</Button>
<Button Height="23" Margin="62,0,551,22" VerticalAlignment="Bottom"
    Name="btnPrev" Click="btnPrev_Click" Opacity="0.75" Content="&lt;">
</Button>

在代码隐藏中,编写代码进行 分页。 对于 分页,我创建了四个 private 成员

//For holding the data globally.
DataTable dt_Products = new DataTable("Products");

//For storing the current page number.
private int paging_PageIndex = 1;

//For storing the Paging Size. Here it is static but you can use a property
//to expose and update value.
private int paging_NoOfRecPerPage = 20;

//To check the paging direction according to use selection.
private enum PagingMode {First = 1,Next = 2,Previous = 3,Last = 4};

我们使用 dt_Products 来存储从数据库检索的数据。 为此,稍微更新一下 ListProducts() 函数。 检索数据后,我们必须根据 paging_NoOfRecPerPage 的值 (这里是 20) 显示第一组记录。 为此,我使用 clone 方法创建了一个与 dt_Products 具有相同架构的临时表。

private void ListProducts()
{
...........

paging_PageIndex = 1;\\For default
sqlDa.Fill(dt_Products);

if (dt_Products.Rows.Count > 0)
{
    DataTable tmpTable = new DataTable();

    //Copying the schema to the temporary table.
    tmpTable = dt_Products.Clone();

    //If total record count is greater than page size then import records
    //from 0 to pagesize (here 20)
    //Else import reports from 0 to total record count.
    if (dt_Products.Rows.Count >= paging_NoOfRecPerPage)
    {
       for (int i = 0; i < paging_NoOfRecPerPage; i++)
       {
            tmpTable.ImportRow(dt_Products.Rows[i]);
       }
    }
    else
    {
       for (int i = 0; i < dt_Products.Rows.Count; i++)
       {
           tmpTable.ImportRow(dt_Products.Rows[i]);
       }
    }

    //Bind the table to the gridview.
    lstProducts.DataContext = tmpTable.DefaultView;

    //Dispose the temporary table.
    tmpTable.Dispose();
 }

现在,仅显示前 20 条(页面大小)记录。 现在我们必须编写导航代码。 让我们为此创建一个函数

private void CustomPaging(int mode)
{
    //There is no need for these variables but i created them just for readability
    int totalRecords = dt_Products.Rows.Count;
    int pageSize = paging_NoOfRecPerPage;

    //If total record count is less than  the page size then return.
    if (totalRecords  <= pageSize)
    {
       return;
    }

    switch (mode)
    {
        case (int)PagingMode.Next:
           if (totalRecords  > (paging_PageIndex  * pageSize))
           {
               DataTable tmpTable = new DataTable();
               tmpTable = dt_Products.Clone();

               if (totalRecords  >= ((paging_PageIndex  * pageSize) + pageSize))
               {
                   for (int i = paging_PageIndex * pageSize; i <
                       ((paging_PageIndex   * pageSize) + pageSize); i++)
                   {
                       tmpTable.ImportRow(dt_Products.Rows[i]);
                   }
               }
               else
               {
                   for (int i = paging_PageIndex * pageSize; i < totalRecords; i++)
                   {
                       tmpTable.ImportRow(dt_Products.Rows[i]);
                   }
               }

               paging_PageIndex += 1;

               lstProducts.DataContext = tmpTable.DefaultView;
               tmpTable.Dispose();
           }
           break;
       case (int)PagingMode.Previous:
           if (paging_PageIndex > 1)
           {
               DataTable tmpTable = new DataTable();
               tmpTable = dt_Products.Clone();

               paging_PageIndex -= 1;

               for (int i = ((paging_PageIndex * pageSize) - pageSize);
                   i < (paging_PageIndex * pageSize); i++)
               {
                  tmpTable.ImportRow(dt_Products.Rows[i]);
               }

               lstProducts.DataContext = tmpTable.DefaultView;
               tmpTable.Dispose();
           }
           break;
       case (int)PagingMode.First:
             paging_PageIndex = 2;
             CustomPaging((int)PagingMode.Previous);
             break;
       case (int)PagingMode.Last:
             paging_PageIndex = (totalRecords/pageSize);
             CustomPaging((int)PagingMode.Next);
             break;
     }
 }

分页 功能已完成。 我们只需要在按钮单击时调用并传递正确的模式。

private void btnFirst_Click(object sender, System.EventArgs e)
{
    CustomPaging((int)PagingMode.First);
}

private void btnNext_Click(object sender, System.EventArgs e)
{
   CustomPaging((int)PagingMode.Next);
}

private void btnPrev_Click(object sender, System.EventArgs e)
{
   CustomPaging((int)PagingMode.Previous);
}

private void btnLast_Click(object sender, System.EventArgs e)
{
   CustomPaging((int)PagingMode.Last);
}

这就是 分页 的全部内容。

如果您想同时显示 分页 信息和页码,请创建两个 label

<Label Height="23.277" HorizontalAlignment="Left" Margin="14.37,89.723,0,0"
    Name="lblPagingInfo" VerticalAlignment="Top" Width="282.63"/>
<Label Height="23.277" HorizontalAlignment="Left" Margin="108.37,0,0,23"
    Name="lblPageNumber" VerticalAlignment="Bottom" Width="26.63" Content="1"/>

为了显示 分页 信息,让我们编写一个简单的函数。 将此函数调用添加到 CustomPaging() 函数中的 switch 块之外。 完成。 编译并运行。

这是完整的代码

XAML

<Window
.......
Loaded="OnLoad"
>

<Grid>

<ListView Margin="15,115,15,48" Name="lstProducts" ItemsSource="{Binding}">
   <ListView.View>
      <GridView>
        <GridViewColumn Header="ProductID"
            DisplayMemberBinding="{Binding Path=ProductID}"></GridViewColumn>
          <GridViewColumn Header="Product Name"
            DisplayMemberBinding="{Binding Path=ProductName}"></GridViewColumn>
          <GridViewColumn Header="SupplierID"
            DisplayMemberBinding="{Binding Path=SupplierID}"></GridViewColumn>
          <GridViewColumn Header="CategoryID"
            DisplayMemberBinding="{Binding Path=CategoryID}"></GridViewColumn>
          <GridViewColumn Header="Qty. Per Unit"
            DisplayMemberBinding="{Binding Path=QuantityPerUnit}"></GridViewColumn>
          <GridViewColumn Header="Unit Price"
            DisplayMemberBinding="{Binding Path=UnitPrice}"></GridViewColumn>
          <GridViewColumn Header="In Stock"
            DisplayMemberBinding="{Binding Path=UnitInStock}"></GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

<Button Height="23" HorizontalAlignment="Left" Margin="18,0,0,22"
    Name="btnFirst" VerticalAlignment="Bottom" Width="40" Content="&lt;&lt;"
    Click="btnFirst_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,474,22"
    Name="btnNext" VerticalAlignment="Bottom" Width="40" Content="&gt;"
    Click="btnNext_Click" Opacity="0.75">
</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,429,22"
    VerticalAlignment="Bottom" Width="40" Name="btnLast"
    Click="btnLast_Click" Opacity="0.75" Content="&gt;&gt;">
</Button>
<Button Height="23" Margin="62,0,551,22" VerticalAlignment="Bottom"
    Name="btnPrev" Click="btnPrev_Click" Opacity="0.75" Content="&lt;">
</Button>

<Label Height="23.277" HorizontalAlignment="Left" Margin="14.37,89.723,0,0"
    Name="lblPagingInfo" VerticalAlignment="Top" Width="282.63"/>
<Label Height="23.277" HorizontalAlignment="Left" Margin="108.37,0,0,23"
    Name="lblPageNumber" VerticalAlignment="Bottom" Width="26.63" Content="1"/>

</Grid>
</Window>

C#

//For holding the data globally.
DataTable dt_Products = new DataTable("Products");

//For storing the current page number.
private int paging_PageIndex = 1;

//For storing the Paging Size. Here it is static but you can use a property
//to expose and update value.
private int paging_NoOfRecPerPage = 20;

//To check the paging direction according to use selection.
private enum PagingMode {First = 1,Next = 2,Previous = 3,Last = 4};

private void OnLoad(object sender, System.EventArgs e)
{
    ListProducts();
}

private void btnFirst_Click(object sender, System.EventArgs e)
{
    CustomPaging((int)PagingMode.First);
}

private void btnNext_Click(object sender, System.EventArgs e)
{
   CustomPaging((int)PagingMode.Next);
}

private void btnPrev_Click(object sender, System.EventArgs e)
{
   CustomPaging((int)PagingMode.Previous);
}

private void btnLast_Click(object sender, System.EventArgs e)
{
   CustomPaging((int)PagingMode.Last);
}

private void ListProducts()
{
     sqlCon = new SqlConnection();
     sqlCon.ConnectionString = \\ConnectionString.

     cmd = new SqlCommand();
     cmd.Connection = sqlCon;
     cmd.CommandType = CommandType.Text;
     cmd.CommandText = "SELECT * FROM Products";

     sqlDa = new SqlDataAdapter();
     sqlDa.SelectCommand = cmd;

     try
     {

         paging_PageIndex = 1;\\For default
     sqlDa.Fill(dt_Products);

    if (dt_Products.Rows.Count > 0)
    {
             DataTable tmpTable = new DataTable();

            //Copying the schema to the temporary table.
            tmpTable = dt_Products.Clone();

           //If total record count is greater than page size then
           //import records from 0 to pagesize (here 20)
           //Else import reports from 0 to total record count.
           if (dt_Products.Rows.Count >= paging_NoOfRecPerPage)
           {
               for (int i = 0; i < paging_NoOfRecPerPage; i++)
               {
                    tmpTable.ImportRow(dt_Products.Rows[i]);
               }
           }
           else
           {
               for (int i = 0; i < dt_Products.Rows.Count; i++)
               {
                   tmpTable.ImportRow(dt_Products.Rows[i]);
               }
           }

          //Bind the table to the gridview.
          lstProducts.DataContext = tmpTable.DefaultView;

          //Dispose the temporary table.
          tmpTable.Dispose();
       }
       else
       {
          MessageBox.Show("Message");
       }
    }
    catch (Exception ex)
    {
       MessageBox.Show("Error Message");
    }
    finally
    {
       sqlDa.Dispose();
       cmd.Dispose();
       sqlCon.Dispose();
    }
 }

private void CustomPaging(int mode)
{
    //There is no need for these variables but i created them just for readability
    int totalRecords = dt_Products.Rows.Count;
    int pageSize = paging_NoOfRecPerPage;

    //If total record count is less than  the page size then return.
    if (totalRecords  <= pageSize)
    {
       return;
    }

    switch (mode)
    {
        case (int)PagingMode.Next:
           if (totalRecords  > (paging_PageIndex  * pageSize))
           {
               DataTable tmpTable = new DataTable();
               tmpTable = dt_Products.Clone();

               if (totalRecords  >= ((paging_PageIndex  * pageSize) + pageSize))
               {
                   for (int i = paging_PageIndex * pageSize;
                        i < ((paging_PageIndex   * pageSize) + pageSize); i++)
                   {
                       tmpTable.ImportRow(dt_Products.Rows[i]);
                   }
               }
               else
               {
                   for (int i = paging_PageIndex * pageSize; i < totalRecords; i++)
                   {
                       tmpTable.ImportRow(dt_Products.Rows[i]);
                   }
               }

               paging_PageIndex += 1;

               lstProducts.DataContext = tmpTable.DefaultView;
               tmpTable.Dispose();
           }
           break;
       case (int)PagingMode.Previous:
           if (paging_PageIndex > 1)
           {
               DataTable tmpTable = new DataTable();
               tmpTable = dt_Products.Clone();

               paging_PageIndex -= 1;

               for (int i = ((paging_PageIndex * pageSize) - pageSize);
                   i < (paging_PageIndex * pageSize); i++)
               {
                  tmpTable.ImportRow(dt_Products.Rows[i]);
               }

               lstProducts.DataContext = tmpTable.DefaultView;
               tmpTable.Dispose();
           }
           break;
       case (int)PagingMode.First:
             paging_PageIndex = 2;
             CustomPaging((int)PagingMode.Previous);
             break;
       case (int)PagingMode.Last:
             paging_PageIndex = (totalRecords/pageSize);
             CustomPaging((int)PagingMode.Next);
             break;
     }

     DisplayPagingInfo();
 }

private void DisplayPagingInfo()
{
    //There is no need for these variables but i created them just for readability
    int totalRecords = dt_Products.Rows.Count;
    int pageSize = paging_NoOfRecPerPage;

    string pagingInfo = "Displaying " + (((paging_PageIndex-1)*pageSize)+1) +
        to " + paging_PageIndex*pageSize ;

    if (dt_Products.Rows.Count < (paging_PageIndex * pageSize))
    {
        pagingInfo = "Displaying " + (((paging_PageIndex - 1) * pageSize) + 1) +
        to " + totalRecords;
    }
    lblPagingInfo.Content = pagingInfo;
    lblPageNumber.Content = paging_PageIndex;
} 
© . All rights reserved.