Autor Beitrag
3Huete
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Di 08.04.08 11:14 
Hallo,
habe mir zwei DataGridViews zur Master->Detail-anzeige zusammengebaut und das funktioniert auch so weit ganz ordentlich.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
          dapKunden.Fill(tblKunden);
          dapAufträge.Fill(tblAufträge);
          dsKunden        = new DataSet();
          dsKunden.Tables.Add(tblKundenstamm);
          dsKunden.Tables.Add(tblAufträge);
          MasterCol      = dsKunden.Tables["Kundenstamm"].Columns[0];
          DetailCol      = dsKunden.Tables["Aufträge"].Columns[0];
          drKundenAuftrag  = new DataRelation("KundenAufträge", MasterCol, DetailCol);
          dsKunden.Relations.Add(drKundenAuftrag);
          dsKunden.Tables["Aufträge"].Columns["Kundennummer"].ColumnMapping = MappingType.Hidden;
          DGrVKunden.DataSource    = dsKunden.Tables["Kundenstamm"];
          DGrVAufträge.DataSource    = dsKunden;
          DGrVAufträge.DataMember    = "Kundenstamm.KundenAufträge";
          // textBox mit Kundennummer synchronisieren
          tbKundennummer.DataBindings.Add("Text",dsKunden.Tables[0],"Kundennummer");

In der letzten Zeile habe ich eine TextBox an die Kundennummer der Kundentabelle gebunden.
Scrolle ich jetzt durch diese, so wird das Textfeld auch synchronisiert. (Wenn ich vorher die Synchronisierung zwischen den DGV aufhebe.) Allerdings wollte ich es umgekehrt haben, d.h. ich wollte mit dem Textfeld durch den Kundenstamm scrollen und mir die dazu gehörenden Detaildatensätze anzeigen lassen. Funktioniert aber so nicht. Kann mir da mal jemand sagen wie das gehen tut ;-)
Danke und Gruß 3Huete
maro158
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35



BeitragVerfasst: Mi 09.04.08 08:06 
Verwende eine BindingSource statt direkt an die Tables zu binden. In der TextBox kannst Du dann die Tasten-Events abfangen und im entspr. Event-Handler die Methoden bindingSource.MoveNext() bzw. bindingSource.MovePrevious() aufrufen um das "Scrollen" zu implementieren.
3Huete Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 09.04.08 12:06 
user profile iconmaro158 hat folgendes geschrieben:
Verwende eine BindingSource statt direkt an die Tables zu binden. In der TextBox kannst Du dann die Tasten-Events abfangen und im entspr. Event-Handler die Methoden bindingSource.MoveNext() bzw. bindingSource.MovePrevious() aufrufen um das "Scrollen" zu implementieren.


Danke für die schnelle Antwort. Habe es so hinbekommen. Hat allerdings noch etwas gedauert, bis ich den Bogen raus hatte, wie ich beide BindingSource miteinander verknüpfen musste, um die Details mit dem Master zu synchronisieren. Jetzt geht's aber und ich hab's übungshalber gleich noch 1:n:m ausprobiert. Klappt :-)
Nochmals danke und Gruß
maro158
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35



BeitragVerfasst: Mi 09.04.08 13:06 
user profile icon3Huete hat folgendes geschrieben:
...bis ich den Bogen raus hatte, wie ich beide BindingSource miteinander verknüpfen musste, um die Details mit dem Master zu synchronisieren.


Wow, freut mich, dass es so schnell ging! Aber jetzt hätte ich einige Fragen:

1. Ich hatte eigentlich mit EINER BindingSource, nicht mit ZWEIEN gerechnet. Setzt Du die DataSource-Eigenschaft des BindingSource-Objekts auf die DataTables oder auf das DataSet?
2. Wie gehst Du mit der Currency (BindingSource.Current) multipler BindingSource-n um?
3. Wie hast Du denn die Relationen zwischen den zwei BindingSource-en erstellt?
3Huete Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 09.04.08 14:45 
user profile iconmaro158 hat folgendes geschrieben:

Wow, freut mich, dass es so schnell ging! Aber jetzt hätte ich einige Fragen:

1. Ich hatte eigentlich mit EINER BindingSource, nicht mit ZWEIEN gerechnet. Setzt Du die DataSource-Eigenschaft des BindingSource-Objekts auf die DataTables oder auf das DataSet?
2. Wie gehst Du mit der Currency (BindingSource.Current) multipler BindingSource-n um?
3. Wie hast Du denn die Relationen zwischen den zwei BindingSource-en erstellt?


Die Relation kommt aus dem DataSet, welches die DataSource der ersten BindingSource wird.
Die zweite BindingSource erhält ihren DataSource aus der ersten BindingSource.
Aber sieh selbst :
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
// Tabellen füllen
dapKunden.Fill(tblKunden);
dapAufträge.Fill(tblAufträge);
// DataSet erstellen und Tabellen hinzufügen
dsKunden      = new DataSet();
dsKunden.Tables.Add(tblKunden);
dsKunden.Tables.Add(tblAufträge);
// Datenrelation erstellen
parentCol    = dsKunden.Tables["Kundenstamm"].Columns[0];
childCol      = dsKunden.Tables["Aufträge"].Columns[0];
drKndAufträge  = new DataRelation("KundenAufträge", parentCol, childCol);
// Relation dem DataSet hinzufügen
dsKunden.Relations.Add(drKndAufträge);
// Primärschlüsselfeld der Master-Tabelle in der Detail-Tabelle ausblenden
dsKunden.Tables["Aufträge"].Columns["Kundennummer"].ColumnMapping = MappingType.Hidden;
// Bindungsource für Kundentabelle erstellen
// DataSource ist das DataSet mit seinen Tabellen und der Relation
bsKunden          = new BindingSource();
bsKunden.DataSource  = dsKunden;
bsKunden.DataMember  = "Kundenstamm";
// Bindingsource für die Aufträge erstellen
// DataSource ist die BindigSource der Master-Tabelle (bsKunden)
// DataMember ist die Relation aus dem DataSet
bsAufträge            = new BindingSource();
bsAufträge.DataSource    = bsKunden;
bsAufträge.DataMember    = "KundenAufträge";
DGrVKunden.DataSource    = bsKunden; // entfällt später
DGrVAufträge.DataSource  = bsAufträge;
// Datenbindung an die TextBoxen
tbKundennummer.DataBindings.Add("Text", bsKunden, "Kundennummer");
tbKundenname.DataBindings.Add("Text", bsKunden, "Kurzbezeichnung");
// bsKunden.movenext() wird dann a.a.O. ausgeführt
// das war's erst mal bis hier hin

Deine zweite Frage kann ich derzeit noch nicht beantworten. (Siehe mein erstes Posting in diesem Forum)
Sachdienliche Hinweise und Anregungen, wie man das Ganze noch besser und/oder kürzer hinbekommt nehme ich gerne entgegen.
Gruß
maro158
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35



BeitragVerfasst: Mi 09.04.08 19:45 
Ja, meine Implementation sieht sehr ähnlich aus (ich verwende hier als Beispiel die Northwind Datenbank):

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlServerCe;


namespace ComboMasterDetail
{
    public partial class Form1 : Form
    {
        DataSet northwindDataSet = new DataSet();
        BindingSource bindingSource = new BindingSource(); // EINE BindingSource für alles
        SqlCeDataAdapter adapterCustomers;
        SqlCeDataAdapter adapterOrders;
        SqlCeCommandBuilder commandBuilderCustomers;       // Quick and Dirty-Lösung für das Speichern
        SqlCeCommandBuilder commandBuilderOrders;          // der Daten

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            System.Data.SqlServerCe.SqlCeConnection connection = new System.Data.SqlServerCe.SqlCeConnection(Properties.Settings.Default.NorthwindConnectionString);
            adapterCustomers = new SqlCeDataAdapter("SELECT * FROM Customers", connection);
            adapterOrders = new SqlCeDataAdapter("SELECT * FROM Orders", connection);

            commandBuilderCustomers = new SqlCeCommandBuilder(adapterCustomers);
            commandBuilderOrders = new SqlCeCommandBuilder(adapterOrders);

            adapterCustomers.Fill(northwindDataSet, "Customers");
            adapterOrders.Fill(northwindDataSet, "Orders");

            DataColumn columnMaster = northwindDataSet.Tables["Customers"].Columns[" columnDetail.ColumnMapping = MappingType.Hidden;

            bindingSource.DataSource = northwindDataSet;
            bindingSource.DataMember = "
Customers";

            dataGridViewCustomers.DataSource = bindingSource;
            dataGridViewOrders.DataSource = bindingSource;
            dataGridViewOrders.DataMember = "
CustomersOrders";

            comboBoxCustomerID.DataSource = bindingSource;
            comboBoxCustomerID.DisplayMember = "
Customer ID";
            comboBoxCustomerID.ValueMember = "
Customer ID";
        }

        private void toolStripButtonSave_Click(object sender, EventArgs e)
        {
            bindingSource.EndEdit();
            adapterCustomers.Update(northwindDataSet.Tables["
Customers"]);
            adapterOrders.Update(northwindDataSet.Tables["
Orders"]);
        }
    }
}


Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt
3Huete Threadstarter
Hält's aus hier
Beiträge: 8



BeitragVerfasst: Mi 09.04.08 21:11 
user profile iconmaro158 hat folgendes geschrieben:
Ja, meine Implementation sieht sehr ähnlich aus (ich verwende hier als Beispiel die Northwind Datenbank):

Interessant, habe mir Dein Beispiel ausgedruckt :-) und werde es morgen kurz nachbauen. Da kann man ja nur dazu lernen.
Was mich interessiert: Funktioniert es auch so, wenn man Kunden->Aufträge->Positionen braucht? Und wie synchronisiere ich einen BindingNavigator mit den Master- resp. Detaildatensätzen? In meiner Version kann ich mittels BindingNavigator.DataSource = bsKunden oder bsAufträge verwenden. Bei Verwendung von nur einer BindingSource muss man das wohl anders lösen? Gruß
maro158
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35



BeitragVerfasst: Do 10.04.08 01:37 
user profile icon3Huete hat folgendes geschrieben:
Funktioniert es auch so, wenn man Kunden->Aufträge->Positionen braucht?


Ja, es gilt allerdings eine winzig kleine Besonderheit in der Bezeichnung von verketteten Relationen zu beachten:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlServerCe;

[assembly:CLSCompliant(true)]

namespace ComboMasterDetail
{
    public partial class Form1 : Form
    {
        DataSet northwindDataSet;
        BindingSource bindingSource;
        SqlCeDataAdapter adapterCustomers;
        SqlCeDataAdapter adapterOrders;
        SqlCeDataAdapter adapterOrderDetails;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            northwindDataSet = new DataSet();
            northwindDataSet.Locale = System.Globalization.CultureInfo.InvariantCulture;

            bindingSource = new BindingSource();

            System.Data.SqlServerCe.SqlCeConnection connection = new System.Data.SqlServerCe.SqlCeConnection(Properties.Settings.Default.NorthwindConnectionString);
            adapterCustomers = new SqlCeDataAdapter("SELECT * FROM Customers", connection);
            adapterOrders = new SqlCeDataAdapter("SELECT * FROM Orders", connection);
            adapterOrderDetails = new SqlCeDataAdapter("SELECT * FROM [Order Details]", connection);

            SqlCeCommandBuilder commandBuilderCustomers = new SqlCeCommandBuilder();
            commandBuilderCustomers.DataAdapter = adapterCustomers;
            SqlCeCommandBuilder commandBuilderOrders = new SqlCeCommandBuilder();
            commandBuilderOrders.DataAdapter = adapterOrders;
            SqlCeCommandBuilder commandBuilderOrderDetails = new SqlCeCommandBuilder();
            commandBuilderOrderDetails.DataAdapter = adapterOrderDetails;

            adapterCustomers.Fill(northwindDataSet, "Customers");
            adapterOrders.Fill(northwindDataSet, "Orders");
            adapterOrderDetails.Fill(northwindDataSet, "Order_Details");

            DataColumn columnMaster = northwindDataSet.Tables["Customers"].Columns["Customer ID"];
            DataColumn columnDetail = northwindDataSet.Tables["Orders"].Columns["Customer ID"];
            DataRelation relationCustomersOrders = new DataRelation("CustomersOrders", columnMaster, columnDetail, true);
            northwindDataSet.Relations.Add(relationCustomersOrders);

            DataColumn columnMasterOrders = northwindDataSet.Tables["Orders"].Columns["Order ID"];
            DataColumn columnDetailOrders = northwindDataSet.Tables["Order_Details"].Columns["Order ID"];
            DataRelation relationOrderOrderDetails = new DataRelation("OrdersOrderDetails", columnMasterOrders, columnDetailOrders, true);
            northwindDataSet.Relations.Add(relationOrderOrderDetails);

            columnMaster.ColumnMapping = MappingType.Hidden;
            columnDetail.ColumnMapping = MappingType.Hidden;
            columnMasterOrders.ColumnMapping = MappingType.Hidden;
            columnDetailOrders.ColumnMapping = MappingType.Hidden;

            bindingSource.DataSource = northwindDataSet;
            bindingSource.DataMember = "Customers";

            comboBoxCustomerID.DataSource = bindingSource;
            comboBoxCustomerID.DisplayMember = "Customer ID";
            comboBoxCustomerID.ValueMember = "Customer ID";

            dataGridViewCustomers.DataSource = bindingSource;
            dataGridViewOrders.DataSource = bindingSource;
            dataGridViewOrders.DataMember = "CustomersOrders";
            dataGridViewOrderDetails.DataSource = bindingSource;
            dataGridViewOrderDetails.DataMember = "CustomersOrders.OrdersOrderDetails";  //  <-- Besonderheit
        }

        private void toolStripButtonSave_Click(object sender, EventArgs e)
        {
            bindingSource.EndEdit();
            adapterCustomers.Update(northwindDataSet.Tables["Customers"]);
            adapterOrders.Update(northwindDataSet.Tables["Orders"]);
            adapterOrderDetails.Update(northwindDataSet.Tables["Order_Details"]);
        }
    }
}


Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt