[C# / WinForms] Two-way Databinding & tracking changes

Pagina: 1
Acties:

  • Crazybyte
  • Registratie: Juli 2002
  • Laatst online: 15-09 10:07
Ik ben opzoek naar wat hulp / advies bij het volgende:

Bij het bedrijf waar ik werk zijn er technische tekeningen voor machines, de onderdelen op de tekening worden aangeduid met codes. Één tekening kan bij meerdere machines van toepassing zijn, maar de waarde/instelling van een onderdeel verschilt wel per machine. Per samenstelling van de machine kunnen er dan ook weer meerdere revisies beschikbaar zijn.

Nu ben ik afgelopen tijd bezig geweest met het ontwikkelen van een programma om al deze informatie op te slaan in een database, waarna er vervolgens per samenstelling van de machine een PDF gegenereerd wordt waarin de tekening zit en een index-blad met daarop de waardes/instellingen die de onderdelen moeten hebben.

Voor het bewerken en opslaan van deze gegevens heb ik een WindowsForm. Bovenin links specificeer ik nogmaals welke samenstelling men gekozen heeft om te bewerken. Bovenin rechts staat een ListView met de beschikbare revisies en voor welke periode deze zijn. Onderin is een tabindeling, met per groep onderdelen een tabblad en op elk tabblad textvelden en checkboxen om alles te definiëren.

Nu heb ik alle velden zelf gekoppeld, maar ik wil dit gaan doen met behulp van databinding. De listView wil ik vervangen door een DataGridView, waarin dan ook weer de revisies staan. Als je een revisie aanklikt, moet hij in de velden op de tabbladen de bijbehorende details laden. Dit heb ik geprobeerd en tot zover gaat het allemaal nog goed.

Wat ik nu echter wil is, dat wanneer iemand de inhoud van een textbox of de status van een checkbox veranderd, ik een seintje krijg dat er 'iets' veranderd is. Als iemand dan weer een andere revisie (regel in de DataGridView) aanklikt, dat hij eerst controleert of er veranderingen zijn en of de gebruiker die dan wil opslaan, dan handelt naar de keuze van de gebruiker en uiteindelijk pas de aangeklikte revisie gaat inladen.

Ik heb wel wat uitleg gevonden over ChangeNotification etc., maar ik mis eigenlijk een simpel concreet voorbeeld van wat ik moet implementeren om hier gebruik van te kunnen maken. Als ik een beetje een voorbeeld heb van hoe het werkt, dan kan ik daar zelf wel weer mee aan de slag om het precies voor mijn situatie uit te zoeken.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:16
Wat ik nu echter wil is, dat wanneer iemand de inhoud van een textbox of de status van een checkbox veranderd, ik een seintje krijg dat er 'iets' veranderd is.
Ben je er zeker van dat je dat wilt ?
Wat als gebruiker X 3 keer dezelfde tekstbox wijzigt, en dan nadien beslist om zijn wijzigingen toch maar niet op te slaan ?
Zolang de gebruiker niet bevestigd heeft dat zijn wijzigingen OK zijn, is er voor mij niets veranderd.
dat hij eerst controleert of er veranderingen zijn en of de gebruiker die dan wil opslaan
Hier volg ik je niet.
Er zijn veranderingen, dus die zijn dan toch al opgeslagen ? Anders zijn er geen veranderingen ...

Of, begrijp ik je verkeerd en wil je dat:
- indien gebruiker X regel 2 in je datagrid wijzigt, er bijgehouden wordt dat regel 2 gewijzigd is
- gebruiker X nadien naar regel 3 navigeert, je programma moet waarschuwen dat er iets gewijzigd is op regel 2, en of de gebruiker dit wil opslaan ?

Indien dit het geval is, dan moet je eens kijken naar IEditableObject, IBindingList, ITypedList etc...

https://fgheysels.github.io/


  • Crazybyte
  • Registratie: Juli 2002
  • Laatst online: 15-09 10:07
whoami schreef op donderdag 03 september 2009 @ 17:29:
Of, begrijp ik je verkeerd en wil je dat:
- indien gebruiker X regel 2 in je datagrid wijzigt, er bijgehouden wordt dat regel 2 gewijzigd is
- gebruiker X nadien naar regel 3 navigeert, je programma moet waarschuwen dat er iets gewijzigd is op regel 2, en of de gebruiker dit wil opslaan ?
Hier gaat het inderdaad om. Ik wil dat er bijgehouden wordt dat er iets is veranderd, dat de inhoud van een control veranderd is kan ik zelf dan nog wel bij de control controleren. Ik wil echter niet bij het veranderen van de regel alle controls moeten doorlopen om te zien of hun waarde nog gelijk is aan die in de database. Ik wil gewoon kunnen zien dat er iets veranderd is.
whoami schreef op donderdag 03 september 2009 @ 17:29:
Indien dit het geval is, dan moet je eens kijken naar IEditableObject, IBindingList, ITypedList etc...
Daar zal ik eens mee beginnen dan.

Wat ik het mooiste zou vinden is het volgende: Als een gebruiker iets invoert in een control, dat die control gelijk controleert of die invoer valid is, wanneer dat niet is maakt ie het veld rood. Stond er al iets in en is de invoer geldig en anders dan maakt ie het veld blauw ofzo. Zodat je in een oogopslag kunt zien of je invoer correct is en/of dat die veranderd is. Maar ik heb het idee dat mij dat nog wel eens wat werk kan kosten.

Side question:
Er is vast een goed boek dat over dit soort dingen gaat. Het bouwen van Windows Forms met databinding, validation, changenotifications etc., maar dan wel met praktische voorbeelden. Weet iemand er daar een van aan te raden? Dan kan ik mij daar nog meer in verdiepen.

  • Reptile209
  • Registratie: Juni 2001
  • Laatst online: 22:59

Reptile209

- gers -

Volgens mij heeft iedere control waar je informatie in kunt veranderen een OnChange event dat afgaat als er iets is veranderd en de focus naar een andere control gaat, of bijv. op Enter wordt gedrukt. Als je daar een inputcontrole aanhangt, ben je een heel eind op weg.

Zo scherp als een voetbal!


Verwijderd

Deze gaat diep in op de zaken die je aanhaalt:

http://www.amazon.com/Dat...s-Forms-2-0/dp/032126892X

  • urk_forever
  • Registratie: Juni 2001
  • Laatst online: 17-09 15:08
Volgens mij moet je de INotifyPropertyChanged interface implementeren.

Als je controls aan data koppeld wordt automatisch gekeken of dit event beschikbaar is en zo ja wordt er aan gekoppeld.

Hier is nog wel meer informatie te vinden:

http://msdn.microsoft.com/en-us/library/c8aebh9k.aspx

Hail to the king baby!


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
Bij de bestaande controls kun je onder de advanced properties bij databinding ook instellen dattie een update doet on change ipv on validate.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • whoami
  • Registratie: December 2000
  • Laatst online: 23:16
Als je gebruik maakt van databinding, dan is het imho net niet de bedoeling dat je de controls zelf gaat gaan overlopen.

Je hebt ook validators die je aan een control kunt hangen.
INotifyPropertyChanged is gewoon om two-way binding mogelijk te maken.
Met deze interface kan je er voor zorgen dat een control gerefreshed wordt, als de property waar deze control aan 'databound' is, wijzigt.
Dat is dus iets anders, maar neemt niet weg dat deze interface wellicht ook wel nodig zal zijn voor de TS.

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • urk_forever
  • Registratie: Juni 2001
  • Laatst online: 17-09 15:08
Ik heb voor school eens iets gedaan wat de TS wil. Een databound WinForms applicatie met Linq-To-SQL objecten (Die standaard de INotifyPropertyChanged interface implementeren).

In de Form_Load het volgende:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        private void Form1_Load(object sender, EventArgs e) {

            //Haal de gegevens op uit de database en koppel ze aan de navigators
            db = new NorthwindDataContext();
            customerBindingSource.DataSource = db.Customers;
            employeeBindingSource.DataSource = db.Employees;
            productBindingSource.DataSource = db.Products;

            //Bij wijzigingen van klanten dit event uitvoeren
            foreach (Customer cust in db.Customers)
            {
                cust.PropertyChanged += new PropertyChangedEventHandler(cust_PropertyChanged);
            }
        }


En een object (verkort):

C#:
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
    [Table(Name="dbo.[Order Details]")]
    public partial class Order_Detail : INotifyPropertyChanging, INotifyPropertyChanged
    {
        
        private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
        
        private int _OrderID;
        
        private int _ProductID;
        
    #region Extensibility Method Definitions
    partial void OnLoaded();
    partial void OnValidate(System.Data.Linq.ChangeAction action);
    partial void OnCreated();
    partial void OnOrderIDChanging(int value);
    partial void OnOrderIDChanged();
    partial void OnProductIDChanging(int value);
    partial void OnProductIDChanged();
    #endregion
        
        public Order_Detail()
        {
            this._Order = default(EntityRef<Order>);
            this._Product = default(EntityRef<Product>);
            OnCreated();
        }
        
        [Column(Storage="_OrderID", DbType="Int NOT NULL", IsPrimaryKey=true)]
        public int OrderID
        {
            get
            {
                return this._OrderID;
            }
            set
            {
                if ((this._OrderID != value))
                {
                    if (this._Order.HasLoadedOrAssignedValue)
                    {
                        throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
                    }
                    this.OnOrderIDChanging(value);
                    this.SendPropertyChanging();
                    this._OrderID = value;
                    this.SendPropertyChanged("OrderID");
                    this.OnOrderIDChanged();
                }
            }
        }
        
        [Column(Storage="_ProductID", DbType="Int NOT NULL", IsPrimaryKey=true)]
        public int ProductID
        {
            get
            {
                return this._ProductID;
            }
            set
            {
                if ((this._ProductID != value))
                {
                    if (this._Product.HasLoadedOrAssignedValue)
                    {
                        throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
                    }
                    this.OnProductIDChanging(value);
                    this.SendPropertyChanging();
                    this._ProductID = value;
                    this.SendPropertyChanged("ProductID");
                    this.OnProductIDChanged();
                }
            }
        }
    }


En de event handler:

C#:
1
2
3
4
5
6
        void cust_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //Als een klant gewijzigd is, op laten slaan
            IsNewCustomer = false;
            customerBindingNavigatorSaveItem.Enabled = true;
        }


Wat er dus gebeurt is dat ik tijdens het laden bij alle objecten de PropertyChanged eventhandler koppel aan een event handler in mijn Form. Als het event afgevuurd wordt dan wordt het Save knopje actief en kan de gebruiker opslaan.

Dat is wat de TS wil volgens mij

Hail to the king baby!

Pagina: 1