Postupy: Zajištění, aby vybraný řádek v podřízené tabulce zůstal na správné pozici
Při práci s datovou vazbou ve Windows Forms se často zobrazují data v zobrazení nadřazenosti, podřízenosti nebo předlohy nebo podrobností. To se týká scénáře datové vazby, ve kterém se data ze stejného zdroje zobrazují ve dvou ovládacích prvcích. Změna výběru v jednom ovládacím prvku způsobí, že se změní data zobrazená ve druhém ovládacím prvku. První ovládací prvek může například obsahovat seznam zákazníků a druhý seznam objednávek souvisejících s vybraným zákazníkem v prvním ovládacím prvku.
Počínaje rozhraním .NET Framework verze 2.0 je možné, že při zobrazení dat v zobrazení nadřazeného nebo podřízeného objektu budete muset provést další kroky, abyste se ujistili, že aktuálně vybraný řádek v podřízené tabulce není resetována na první řádek tabulky. Aby to bylo možné, budete muset uložit pozici podřízené tabulky do mezipaměti a obnovit ji po změně nadřazené tabulky. K resetování dítěte obvykle dochází poprvé, když se změní pole v řádku nadřazené tabulky.
Uložit aktuální pozici podřízeného do mezipaměti
Deklarujte celočíselnou proměnnou pro uložení pozice podřízeného seznamu a logické proměnné pro uložení, zda se má podřízená pozice ukládat do mezipaměti.
private int cachedPosition = -1; private bool cacheChildPosition = true;
Private cachedPosition As Integer = - 1 Private cacheChildPosition As Boolean = True
Zpracujte událost ListChanged pro CurrencyManager vazby a zkontrolujte ListChangedTypeReset.
Zkontrolujte aktuální pozici CurrencyManager. Pokud je větší než první položka v seznamu (obvykle 0), uložte ji do proměnné.
void relatedCM_ListChanged(object sender, ListChangedEventArgs e) { // Check to see if this is a caching situation. if (cacheChildPosition && cachePositionCheckBox.Checked) { // If so, check to see if it is a reset situation, and the current // position is greater than zero. CurrencyManager relatedCM = sender as CurrencyManager; if (e.ListChangedType == ListChangedType.Reset && relatedCM.Position > 0) // If so, cache the position of the child table. cachedPosition = relatedCM.Position; } }
Private Sub relatedCM_ListChanged(ByVal sender As Object, _ ByVal e As ListChangedEventArgs) ' Check to see if this is a caching situation. If cacheChildPosition AndAlso cachePositionCheckBox.Checked Then ' If so, check to see if it is a reset situation, and the current ' position is greater than zero. Dim relatedCM As CurrencyManager = sender If e.ListChangedType = ListChangedType.Reset _ AndAlso relatedCM.Position > 0 Then ' If so, cache the position of the child table. cachedPosition = relatedCM.Position End If End If End Sub
Zpracujte událost CurrentChanged nadřazeného seznamu správce nadřazené měny. V obslužné rutině nastavte logickou hodnotu tak, aby bylo zřejmé, že nejde o cacheovací scénář. Pokud dojde k CurrentChanged, změna nadřazeného objektu je změna pozice seznamu, nikoli změna hodnoty položky.
void bindingSource1_CurrentChanged(object sender, EventArgs e) { // If the CurrentChanged event occurs, this is not a caching // situation. cacheChildPosition = false; }
' Handle the current changed event. This event occurs when ' the current item is changed, but not when a field of the current ' item is changed. Private Sub bindingSource1_CurrentChanged(ByVal sender As Object, _ ByVal e As EventArgs) Handles bindingSource1.CurrentChanged ' If the CurrentChanged event occurs, this is not a caching ' situation. cacheChildPosition = False End Sub
Obnovit pozici dítěte
Zpracujte událost PositionChanged pro vazbu CurrencyManager.
Obnovte pozici podřízené tabulky na mezipaměťovanou pozici uloženou v předchozím postupu.
void relatedCM_PositionChanged(object sender, EventArgs e) { // Check to see if this is a caching situation. if (cacheChildPosition && cachePositionCheckBox.Checked) { CurrencyManager relatedCM = sender as CurrencyManager; // If so, check to see if the current position is // not equal to the cached position and the cached // position is not out of bounds. if (relatedCM.Position != cachedPosition && cachedPosition > 0 && cachedPosition < relatedCM.Count) { relatedCM.Position = cachedPosition; cachedPosition = -1; } } }
Private Sub relatedCM_PositionChanged(ByVal sender As Object, ByVal e As EventArgs) ' Check to see if this is a caching situation. If cacheChildPosition AndAlso cachePositionCheckBox.Checked Then Dim relatedCM As CurrencyManager = sender ' If so, check to see if the current position is ' not equal to the cached position and the cached ' position is not out of bounds. If relatedCM.Position <> cachedPosition AndAlso _ cachedPosition > 0 AndAlso cachedPosition < _ relatedCM.Count Then relatedCM.Position = cachedPosition cachedPosition = -1 End If End If End Sub
Příklad
Následující příklad ukazuje, jak uložit aktuální pozici na CurrencyManagerpro podřízenou tabulku a obnovit pozici po dokončení úpravy v nadřazené tabulce. Tento příklad obsahuje dva ovládací prvky DataGridView vázané na dvě tabulky v DataSet pomocí komponenty BindingSource. Relace je vytvořena mezi dvěma tabulkami a je přidána do DataSet. Pro ukázkové účely je pozice v podřízené tabulce zpočátku nastavena na třetí řádek.
using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace BT2
{
public class Form1 : Form
{
public Form1()
{
InitializeControlsAndDataSource();
}
// Declare the controls to be used.
private BindingSource bindingSource1;
private DataGridView dataGridView1;
private Button button1;
private DataGridView dataGridView2;
private CheckBox cachePositionCheckBox;
public DataSet set1;
private void InitializeControlsAndDataSource()
{
// Initialize the controls and set location, size and
// other basic properties.
this.dataGridView1 = new DataGridView();
this.bindingSource1 = new BindingSource();
this.button1 = new Button();
this.dataGridView2 = new DataGridView();
this.cachePositionCheckBox = new System.Windows.Forms.CheckBox();
this.dataGridView1.ColumnHeadersHeightSizeMode =
DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Dock = DockStyle.Top;
this.dataGridView1.Location = new Point(0, 20);
this.dataGridView1.Size = new Size(292, 170);
this.button1.Location = new System.Drawing.Point(18, 175);
this.button1.Size = new System.Drawing.Size(125, 23);
button1.Text = "Clear Parent Field";
this.button1.Click += new System.EventHandler(this.button1_Click);
this.dataGridView2.ColumnHeadersHeightSizeMode =
System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView2.Location = new System.Drawing.Point(0, 225);
this.dataGridView2.Size = new System.Drawing.Size(309, 130);
this.cachePositionCheckBox.AutoSize = true;
this.cachePositionCheckBox.Checked = true;
this.cachePositionCheckBox.Location = new System.Drawing.Point(150, 175);
this.cachePositionCheckBox.Name = "radioButton1";
this.cachePositionCheckBox.Size = new System.Drawing.Size(151, 17);
this.cachePositionCheckBox.Text = "Cache and restore position";
this.ClientSize = new System.Drawing.Size(325, 420);
this.Controls.Add(this.dataGridView1);
this.Controls.Add(this.cachePositionCheckBox);
this.Controls.Add(this.dataGridView2);
this.Controls.Add(this.button1);
// Initialize the data.
set1 = InitializeDataSet();
// Set the data source to the DataSet.
bindingSource1.DataSource = set1;
//Set the DataMember to the Menu table.
bindingSource1.DataMember = "Customers";
// Add the control data bindings.
dataGridView1.DataSource = bindingSource1;
// Set the data source and member for the second DataGridView.
dataGridView2.DataSource = bindingSource1;
dataGridView2.DataMember = "custOrders";
// Get the currency manager for the customer orders binding.
CurrencyManager relatedCM =
bindingSource1.GetRelatedCurrencyManager("custOrders");
// Set the position in the child table for demonstration purposes.
relatedCM.Position = 3;
// Handle the current changed event. This event occurs when
// the current item is changed, but not when a field of the current
// item is changed.
bindingSource1.CurrentChanged +=
new EventHandler(bindingSource1_CurrentChanged);
// Handle the two events for caching and resetting the position.
relatedCM.ListChanged += new ListChangedEventHandler(relatedCM_ListChanged);
relatedCM.PositionChanged
+= new EventHandler(relatedCM_PositionChanged);
// Set cacheing to true in case current changed event
// occurred on set up.
cacheChildPosition = true;
}
// Establish the data set with two tables and a relationship
// between them.
private DataSet InitializeDataSet()
{
set1 = new DataSet();
// Declare the DataSet and add a table and column.
set1.Tables.Add("Customers");
set1.Tables[0].Columns.Add("CustomerID");
set1.Tables[0].Columns.Add("Customer Name");
set1.Tables[0].Columns.Add("Contact Name");
// Add some rows to the table.
set1.Tables["Customers"].Rows.Add("c1", "Fabrikam, Inc.", "Ellen Adams");
set1.Tables[0].Rows.Add("c2", "Lucerne Publishing", "Don Hall");
set1.Tables[0].Rows.Add("c3", "Northwind Traders", "Lori Penor");
set1.Tables[0].Rows.Add("c4", "Tailspin Toys", "Michael Patten");
set1.Tables[0].Rows.Add("c5", "Woodgrove Bank", "Jyothi Pai");
// Declare the DataSet and add a table and column.
set1.Tables.Add("Orders");
set1.Tables[1].Columns.Add("CustomerID");
set1.Tables[1].Columns.Add("OrderNo");
set1.Tables[1].Columns.Add("OrderDate");
// Add some rows to the table.
set1.Tables[1].Rows.Add("c1", "119", "10/04/2006");
set1.Tables[1].Rows.Add("c1", "149", "10/10/2006");
set1.Tables[1].Rows.Add("c1", "159", "10/12/2006");
set1.Tables[1].Rows.Add("c2", "169", "10/10/2006");
set1.Tables[1].Rows.Add("c2", "179", "10/10/2006");
set1.Tables[1].Rows.Add("c2", "189", "10/12/2006");
set1.Tables[1].Rows.Add("c3", "122", "10/04/2006");
set1.Tables[1].Rows.Add("c4", "130", "10/10/2006");
set1.Tables[1].Rows.Add("c5", "1.29", "10/14/2006");
DataRelation dr = new DataRelation("custOrders",
set1.Tables["Customers"].Columns["CustomerID"],
set1.Tables["Orders"].Columns["CustomerID"]);
set1.Relations.Add(dr);
return set1;
}
private int cachedPosition = -1;
private bool cacheChildPosition = true;
void relatedCM_ListChanged(object sender, ListChangedEventArgs e)
{
// Check to see if this is a caching situation.
if (cacheChildPosition && cachePositionCheckBox.Checked)
{
// If so, check to see if it is a reset situation, and the current
// position is greater than zero.
CurrencyManager relatedCM = sender as CurrencyManager;
if (e.ListChangedType == ListChangedType.Reset && relatedCM.Position > 0)
// If so, cache the position of the child table.
cachedPosition = relatedCM.Position;
}
}
void bindingSource1_CurrentChanged(object sender, EventArgs e)
{
// If the CurrentChanged event occurs, this is not a caching
// situation.
cacheChildPosition = false;
}
void relatedCM_PositionChanged(object sender, EventArgs e)
{
// Check to see if this is a caching situation.
if (cacheChildPosition && cachePositionCheckBox.Checked)
{
CurrencyManager relatedCM = sender as CurrencyManager;
// If so, check to see if the current position is
// not equal to the cached position and the cached
// position is not out of bounds.
if (relatedCM.Position != cachedPosition && cachedPosition
> 0 && cachedPosition < relatedCM.Count)
{
relatedCM.Position = cachedPosition;
cachedPosition = -1;
}
}
}
int count = 0;
private void button1_Click(object sender, EventArgs e)
{
// For demo purposes--modifies a value in the first row of the
// parent table.
DataRow row1 = set1.Tables[0].Rows[0];
row1[1] = DBNull.Value;
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Public Class Form1
Inherits Form
Public Sub New()
InitializeControlsAndDataSource()
End Sub
' Declare the controls to be used.
Private WithEvents bindingSource1 As BindingSource
Private dataGridView1 As DataGridView
Private WithEvents button1 As Button
Private dataGridView2 As DataGridView
Private cachePositionCheckBox As CheckBox
Public set1 As DataSet
Private Sub InitializeControlsAndDataSource()
' Initialize the controls and set location, size and
' other basic properties.
Me.dataGridView1 = New DataGridView()
Me.bindingSource1 = New BindingSource()
Me.button1 = New Button()
Me.dataGridView2 = New DataGridView()
Me.cachePositionCheckBox = New System.Windows.Forms.CheckBox()
Me.dataGridView1.ColumnHeadersHeightSizeMode = _
DataGridViewColumnHeadersHeightSizeMode.AutoSize
Me.dataGridView1.Dock = DockStyle.Top
Me.dataGridView1.Location = New Point(0, 20)
Me.dataGridView1.Size = New Size(292, 170)
Me.button1.Location = New System.Drawing.Point(18, 175)
Me.button1.Size = New System.Drawing.Size(125, 23)
button1.Text = "Clear Parent Field"
Me.dataGridView2.ColumnHeadersHeightSizeMode = _
System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize
Me.dataGridView2.Location = New System.Drawing.Point(0, 225)
Me.dataGridView2.Size = New System.Drawing.Size(309, 130)
Me.cachePositionCheckBox.AutoSize = True
Me.cachePositionCheckBox.Checked = True
Me.cachePositionCheckBox.Location = New System.Drawing.Point(150, 175)
Me.cachePositionCheckBox.Name = "radioButton1"
Me.cachePositionCheckBox.Size = New System.Drawing.Size(151, 17)
Me.cachePositionCheckBox.Text = "Cache and restore position"
Me.ClientSize = New System.Drawing.Size(325, 420)
Me.Controls.Add(Me.dataGridView1)
Me.Controls.Add(Me.cachePositionCheckBox)
Me.Controls.Add(Me.dataGridView2)
Me.Controls.Add(Me.button1)
' Initialize the data.
set1 = InitializeDataSet()
' Set the data source to the DataSet.
bindingSource1.DataSource = set1
'Set the DataMember to the Menu table.
bindingSource1.DataMember = "Customers"
' Add the control data bindings.
dataGridView1.DataSource = bindingSource1
' Set the data source and member for the second DataGridView.
dataGridView2.DataSource = bindingSource1
dataGridView2.DataMember = "custOrders"
' Get the currency manager for the customer orders binding.
Dim relatedCM As CurrencyManager = _
bindingSource1.GetRelatedCurrencyManager("custOrders")
' Handle the two events for caching and resetting the position.
AddHandler relatedCM.ListChanged, AddressOf relatedCM_ListChanged
AddHandler relatedCM.PositionChanged, AddressOf relatedCM_PositionChanged
' Set the position in the child table for demonstration purposes.
relatedCM.Position = 3
' Set cacheing to true in case current changed event
' occurred on set up.
cacheChildPosition = True
End Sub
' Establish the data set with two tables and a relationship
' between them.
Private Function InitializeDataSet() As DataSet
set1 = New DataSet()
' Declare the DataSet and add a table and column.
set1.Tables.Add("Customers")
set1.Tables(0).Columns.Add("CustomerID")
set1.Tables(0).Columns.Add("Customer Name")
set1.Tables(0).Columns.Add("Contact Name")
' Add some rows to the table.
set1.Tables("Customers").Rows.Add("c1", "Fabrikam, Inc.", _
"Ellen Adams")
set1.Tables(0).Rows.Add("c2", "Lucerne Publishing", "Don Hall")
set1.Tables(0).Rows.Add("c3", "Northwind Traders", "Lori Penor")
set1.Tables(0).Rows.Add("c4", "Tailspin Toys", "Michael Patten")
set1.Tables(0).Rows.Add("c5", "Woodgrove Bank", "Jyothi Pai")
' Declare the DataSet and add a table and column.
set1.Tables.Add("Orders")
set1.Tables(1).Columns.Add("CustomerID")
set1.Tables(1).Columns.Add("OrderNo")
set1.Tables(1).Columns.Add("OrderDate")
' Add some rows to the table.
set1.Tables(1).Rows.Add("c1", "119", "10/04/2006")
set1.Tables(1).Rows.Add("c1", "149", "10/10/2006")
set1.Tables(1).Rows.Add("c1", "159", "10/12/2006")
set1.Tables(1).Rows.Add("c2", "169", "10/10/2006")
set1.Tables(1).Rows.Add("c2", "179", "10/10/2006")
set1.Tables(1).Rows.Add("c2", "189", "10/12/2006")
set1.Tables(1).Rows.Add("c3", "122", "10/04/2006")
set1.Tables(1).Rows.Add("c4", "130", "10/10/2006")
set1.Tables(1).Rows.Add("c5", "1.29", "10/14/2006")
Dim dr As New DataRelation("custOrders", _
set1.Tables("Customers").Columns("CustomerID"), _
set1.Tables("Orders").Columns("CustomerID"))
set1.Relations.Add(dr)
Return set1
End Function '
Private cachedPosition As Integer = - 1
Private cacheChildPosition As Boolean = True
Private Sub relatedCM_ListChanged(ByVal sender As Object, _
ByVal e As ListChangedEventArgs)
' Check to see if this is a caching situation.
If cacheChildPosition AndAlso cachePositionCheckBox.Checked Then
' If so, check to see if it is a reset situation, and the current
' position is greater than zero.
Dim relatedCM As CurrencyManager = sender
If e.ListChangedType = ListChangedType.Reset _
AndAlso relatedCM.Position > 0 Then
' If so, cache the position of the child table.
cachedPosition = relatedCM.Position
End If
End If
End Sub
' Handle the current changed event. This event occurs when
' the current item is changed, but not when a field of the current
' item is changed.
Private Sub bindingSource1_CurrentChanged(ByVal sender As Object, _
ByVal e As EventArgs) Handles bindingSource1.CurrentChanged
' If the CurrentChanged event occurs, this is not a caching
' situation.
cacheChildPosition = False
End Sub
Private Sub relatedCM_PositionChanged(ByVal sender As Object, ByVal e As EventArgs)
' Check to see if this is a caching situation.
If cacheChildPosition AndAlso cachePositionCheckBox.Checked Then
Dim relatedCM As CurrencyManager = sender
' If so, check to see if the current position is
' not equal to the cached position and the cached
' position is not out of bounds.
If relatedCM.Position <> cachedPosition AndAlso _
cachedPosition > 0 AndAlso cachedPosition < _
relatedCM.Count Then
relatedCM.Position = cachedPosition
cachedPosition = -1
End If
End If
End Sub
Private count As Integer = 0
Private Sub button1_Click(ByVal sender As Object, _
ByVal e As EventArgs) Handles button1.Click
' For demo purposes--modifies a value in the first row of the
' parent table.
Dim row1 As DataRow = set1.Tables(0).Rows(0)
row1(1) = DBNull.Value
End Sub
<STAThread()> _
Shared Sub Main()
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
Application.Run(New Form1())
End Sub
End Class
Pokud chcete otestovat příklad kódu, proveďte následující kroky:
Spusťte příklad.
Ujistěte se, že je zaškrtnuté políčko mezipaměti a resetování pozice.
Kliknutím na tlačítko Vymazat pole rodičovské tabulky dojde ke změně v poli rodičovské tabulky. Všimněte si, že vybraný řádek v podřízené tabulce se nemění.
Zavřete a znovu spusťte příklad. Musíte to udělat, protože k resetování dojde pouze při první změně v nadřazeném řádku.
Zrušte zaškrtnutí políčka Cache a resetovat umístění.
Klikněte na tlačítko Vymazat nadřazené pole. Všimněte si, že vybraný řádek v podřízené tabulce se změní na první řádek.
Kompilace kódu
Tento příklad vyžaduje:
- Odkazy na sestavení System, System.Data, System.Drawing, System.Windows.Forms a System.XML.
Viz také
.NET Desktop feedback