[Binding] Wiązanie kontrolek z obiektami

0

Przykładowo posiadam obiekt DataTable, który w 2giej kolumnie przechowuje obiekty typu Container:


            myTab = new DataTable();
            myTab.Columns.Add("col1",typeof(string));
            myTab.Columns.Add("col2",typeof(Container));


public class Container
    {
        string napis;
        public string Napis
        {
            get { return napis; }
        }
        int liczba;
        public int Liczba
        {
            get { return liczba; }
        }
        public Container(string nap, int licz)
        {
            napis = nap;
            liczba = licz;
        }
        public override string ToString()
        {
            return napis + " " + liczba.ToString();
        }
    }

Mogę np utworzyć wiązanie z kolumną 1:

textBox1.DataBindings.Add("Text", myTab, "col1");

W jaki sposób mogę się odwołać do np. do pola napis dla obiektór Container z kolumny 2, abym mógł zbindować tą wartość podobnie jak to zrobiłem w przypadku kolumny, która zawierała typy proste.

0

Zaznaczam, ze -niepamietam- poniewaz kaszania mi sie databindingi DevX, Infragis, bazowy .net, i pare innych..

Sprobuj zamiast sourcemember="col1", podac po porstu sourcemember="col2.Napis".
To ma szanse po prostu zadzialac, nie pamietam czy DataBindingEngine byl tutaj walniety, czy tez w kolumnach DGV.

Jezeli to nie zadziala, to masz duzy brzydki problem, bo to oznacza ze w tym konkretnym miejscu databindingengine jest rownie po prostu NIEDOROBIONY i nie umie przechodzi po subpolach.
W zasadzie, jesli gdzies na takie cos trafisz, zostaja Ci dwie opcje:

  • przebudowac formatke, tak, aby szeroko korzystala z komponentow BindignSource ktore standardowo dostarczaja list obiektow lub wlasnosci jednego obiektu, owo BS maja .DataSource/.Member/.Current, ktore moze formowac zrodlo danych dla innego BindingSource, wiec w teorii mozesz dowolne po=kropkowe "obiekt.pole.pole.pole" rozpakowac do kilku kaskadowo polaczonych BS'ow i bindowac nie do obiektu, tylko do odpowiednego BS'a

  • uzyc sprytnie FORMATTERA (o ile w ogole to miejsce Ci to umozliwia:) tutaj na szczescie na pewno jest taka opcja), tzn. nie robic prostego wiazania w stylu textBox1.DataBindings.Add("Text", myTab, "col1");, tylko textBox1.DataBindings.Add(new DataBinding(.....)); i w parametrach poza danymi kluczowymi podac formatter, ktory bedzie "formatowal" wartosc poprzez wyciaganie z niej subpola wg Twego widzimisie, al'a:

//pseudokod!
textBox1.DataBindings.Add(new DataBinding("Text", myTab, new MyFormatter())); // nie pamietam czy taki konstruktor istnieje. moze to jest EVENT DataBinding.OnParse? albo .FormatNeeded?

private class new MyFormatter : IWhateverNeeded
{
     public string formateme(object datasourcevalue)
     {
           return ((Container)datasourcevalue).Napis;
     }
}
0

Niestety

Binding bind = new Binding("Text",myTab,"col2.napis");
textBox1.DataBindings.Add(bind);

nie działa. Nie znam się dobrze na zaawansowanym wiązaniu, więc rozwiążę problem inaczej.

Posiadam tabelę klasy DataTable, gdzie jako kolumny są np:
imie, nazwisko, id, wiek oraz ostatnia przechowująca obikekt pewnej klasy "KlasaA"

KlasaA, którą faktycznie wykorzystuję, posiada 2 pola będące wartościami typu wyliczeniowego, oraz około 10 wartości string.

W mojej formatce chciałem dane z tej tabeli pokazywać w formatce DataGridView, gdzie jeden z typów wyliczeniowych byłby pokazywany w osattniej kolumnie. Natomiast reszat danych string pokazywana by była w zbindowanych textboxach. Niestety nie mogę/nie potrafię tak zrobić, muszę znaleźć jakiś workaround. Myślałem o podrzędnej DataTable, która przechowywała by wartości zamiast mniemanego obiektu klasyA. Tylko jak zbindować przykładowe textboxy z drugą tabelą i updateować je, kiedy zaznaczony wiersz na datagridview ulegnie zmianie.

Można by było pokusić się o powiekszenie tabeli1 i pokazać w dgv tylko wybrane kolumny (o ile się da tak) ale nie każdy wiersz z tabeli1 będzie miał swój odpowiednik w tabeli2. Będzie to uzależnione od wartości typu wyliczeniowego, który miałby wejsć w skład klasyA.

Jeśli macie pomysły na fachowe załatwienie problemu, lub info jak można powiązać zmiany pierwszej tabeli z wyświetlaniem danych w 2 tabeli na textboxach to prosił bym o info. Dzięki

0

Dlaczego używasz DataTable, a nie własnych obiektów?

0
somekind napisał(a)

Dlaczego używasz DataTable, a nie własnych obiektów?

DGV oferuje prosty sposób wiązania z DataTable i z tego co czytałem w różnych materiałach zazwyczaj jest taka praktyka.

0

Statystyka wśród materiałów kłamie, ponieważ ktoś kiedyś napisał parę kursów na temat X, a potem 300 innych ludzi ten kurs skopiowało, przetłumaczyło, dopisało trzy zdania i powstały setki "nowych" materiałów.. Niestety to sie tyczy każdego dowolnego tematu jakiego szukasz na google.

DataTable zamiast obeiktow stosuje się w 3 przypadkach:

  • jestes hardcorem, wiec używasz tego "bo tak"
  • jestes zielony, nie znacz zadnego ORM'a i uczysz sie dopiero co to jest SQL i baza danych
  • wiesz co robisz i naprawde potrzebujesz tych kilku ulamkow % szybkosci wiecej
    w innych przypadkach, kazda zdrowa na umyśle osoba natychmiast ucieka do dowolnego ORM chocby Linq2Sql albo EntityFramework ktore - uwaga - przychodza z .Net za free. ok, albo do "typed datasets" ale to jest hm.. hybryda.

Ale, skoro mowa o DataTable, http://www.akadia.com/services/dotnet_databinding.html

0

Dzięki.
Przeanalizowałem kod i dostrzegłem, że posiadając relację pomiędzy tabelami można 2 tabele zbindować w łątwy sposób z kontrolkami, aby jeden datagridview pokazywał ogólną zawartość 1. tabeli a drugi detale zaznaczonego wiersza (poprzez relację).
Niestety działa tylko na starcie a przy zmianie zaznaczenia dla 1. dgv, zmiany na drugim nie są odnotowane. Czego tu brakuje?

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;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        DataSet ds;
        public Form1()
        {
            InitializeComponent();
            ds = new DataSet();

            ds.Tables.Add("table1");
            ds.Tables.Add("table2");

            ds.Tables[0].Columns.Add("id",typeof(string));
            ds.Tables[0].Columns.Add("name", typeof(string));
            ds.Tables[1].Columns.Add("id", typeof(string));
            ds.Tables[1].Columns.Add("gender", typeof(string));
            ds.Tables[1].Columns.Add("age", typeof(string));
            ds.Tables[1].Columns.Add("name", typeof(string));

            DataRow newRow1 = ds.Tables[0].NewRow();
            newRow1[0] = 0;
            newRow1[1] = "Anna Nowak";
            ds.Tables[0].Rows.Add(newRow1);

            DataRow newRow2 = ds.Tables[0].NewRow();
            newRow2[0] = 1;
            newRow2[1] = "Jan Kowalski";
            ds.Tables[0].Rows.Add(newRow2);

            DataRow newRow3 = ds.Tables[1].NewRow();
            newRow3[0] = 0;
            newRow3[1] = "male";
            newRow3[2] = "Adam";
            ds.Tables[1].Rows.Add(newRow3);

            DataRow newRow4 = ds.Tables[1].NewRow();
            newRow4[0] = 0;
            newRow4[1] = "female";
            newRow4[2] = "Zosia";
            ds.Tables[1].Rows.Add(newRow4);

            DataRow newRow5 = ds.Tables[1].NewRow();
            newRow5[0] = 1;
            newRow5[1] = "female";
            newRow5[2] = "Inga";
            ds.Tables[1].Rows.Add(newRow5);

            

            System.Data.DataRelation relPersonChild;
            System.Data.DataColumn colPerson;
            System.Data.DataColumn colChild;
            colPerson = ds.Tables[0].Columns[0];
            colChild = ds.Tables[1].Columns[0];
            relPersonChild = new System.Data.DataRelation("RelPersonChild", colPerson, colChild);
            ds.Relations.Add(relPersonChild);

            dataGridView1.DataSource = ds.Tables[0];
            dataGridView2.DataSource = ds;
            dataGridView2.DataMember = "table1.RelPersonChild";
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}

0
  1. Napiszę jeszcze raz: System.Windows.Forms.BindingSource. Zainteresuj sie nim, gdyz on "dostarcza" modelu ActiveRecord, ktory tobie caly czas siedzi w glowie

  2. nie mam teraz czasu analizowac, ale ta konfiguracja .DSource/DMember ktora zrobiles jest dziwna. dla grid1 - ok, ale grid2 w takim ukladzie jak masz wypelnia sie najprawdopodobniej wszystkimi wierszami objetymi w podanej relacji BEZ zwracania uwagi czy naleza one do zaznaczonego czy nie. grid2 powienien raczej byc ladowany w stylu .DataSource = grid1.selectedrows[0].GetChildRows("RelPersonChild")..

  3. A rozwijając myśl: w tej chwili pokonfigurowales zrodla danych, kontrolki sie zainicjalizowaly, odczytaly sobie dane i sa happy ze skonczyly prace. NIKT nie slucha na eventach *Changed, wiec nic sie nie odswieza. Jezeli chcialbys teaz dorobic reakcje na wybieranie roznych elementow i przeladowywanie danych w drugim gridzie, dokladnie tak musialbys to zrobic: podpiac sie gdzies a'la grid1.SelectedIdnexChanged, w tymże handlerze wymusisz przeladowanie danych w gridzie2 przez g2.datasource = getchildrows na zaznaczonym elemencie grida1. Z kolei jezeli bys posluchal i uzyl w koncu BINDINGSOURCE, Twoja konfugiracja wygladalaby mniejwiecej tak:

// stworz/zaladuj dset, dtable, drelation, i wiersze
bs = new BindingSource
bs.DataSource = ds
bs.DataMember = "table1"

g1.DataSource = bs // uzywa BS jako źródła listy

textboxX.DataBindings.Add("Text", bs, "name"); // używa CurrencyManager z BS
textboxY.DataBindings.Add("Text", bs, "RelPersonChild.age");

0

No z tym:

Linq2Sql albo EntityFramework
to nie tak radosnie, no chyba ze mamy msql bo taki mysql tego nie wspiera i wtedy tzreba ladowac sie w nhibernate. Sa niby jakies darmowki do mysql'a ale nie widzialem nic wartego uwagi.

Z innych rozwiazani mozna jeszcze strongly typed DataSet co z przedstawionymi rozwiazaniami dalo by to co chiales uzyskac (ale jest to rozwiazanie grosze - pod wzgledem projektowania niz Linq2Sql, EntityFramework)

//---
a i jeszcze te dataset mozna generowac z automatu ale nie polecam duzo kodu i nie wiadomo co sie dzieje jak sie cos spapra w kreatorze (szczegolnie poczatkujacy). Druga wersja to generowanie (albo pisanie samemu) z xsd.

1 użytkowników online, w tym zalogowanych: 0, gości: 1