Newsgroup: it.comp.lang.visual-basic
Titolo: [WPF] Binding di una ObservableCollection ad un DataGrid control

Salve a tutti,
mi sto stampando su un problema che non riesco a risolvere.
Spiego cosa voglio fare:
Vorrei popolare un controllo DataGrid con delle righe di dati inseriti
dall'utente (ï¿œ una semplificazione ma prendetela per buona).
L'utente deve poter inserire, modificare o eliminare queste righe di dati.
Quando decide di salvare, i dati presenti nella DataGrid devono finire
in un array che utilizzo per certe elaborazioni.
NOTA: non vi sono interazioni con database o altro... ï¿œ tutto in RAM e
le righe sono create al volo dagli utenti.
Ecco come ho impostato la cosa:
1-Creo un DataGrid control sul form
2-Creo una classe chiamata "stcColonna" che mi contiene tutti i dati e
che implementa la INotifyPropertyChanged per gestire il binding TwoWay
con le celle della DataGrid
3-Creo una ObservableCollection (Of stcColonna) chiamata arrCampiTabella
4-Binding della ObservableCollection alla proprietï¿œ ItemsSource della
DataGrid
Fin qui funziona tutto bene, posso inserire righe, posso eliminarle e
modificarle...
Unico problema: rispetto al numero di righe che l'utente inserisce,
viene sempre visualizzata una riga in piï¿œ nella DataGrid.
Ecco un'immagine contenente quello che vedo nella datagrid e quello che
vedo facendo il quickwatch dell'ObservableCollection:
http://bayimg.com/GADFmAadK
Infine: se trasformo la classe stcColonna in una struttura, il problema
sparisce ma non riesco poi a modificare i dati nella datagrid.
Grazie a chi possa darmi una mano.
Nicola

 
puo' essere che sul datagrid sia attivo il flag 'enable adding' o come si 
chiama adesso con il 2010?
[cut]
-- 
Paolo opg
BE AWARE that this post uses a fake reply-to address
to contact me write to:
janickg ( at ) hotmail ( dot ) com
--

Al diavolo! Ho cercato per 2 ore su google e poi trovo la soluzione dopo
5 minuti dal post!!!
Va impostata la proprietï¿œ CanUserAddRows = False sulla DataGrid.
Nicola

 chiama adesso con il 2010?
Si, l'ho notato ora. E' una proprietï¿œ della DataGrid. Si chiama
CanUserAddRows e va esplicitamente impostata su False.
La cosa assurda ï¿œ che nell'IDE, andando nel pannello delle proprietï¿œ,
risulta giï¿œ essere a False di default. Perï¿œ se non lo scrivi nel codice
XAML non funge!
Non hai idea di quanto stia smadonnando con WPF. Documentazione zero
sull'MSDN. Un sacco di cose sono "innaturali" o particolarmente
complicate per effettuare operazioni semplici...
Il tutto aggravato dal fatto che il nostro programma ha delle interfacce
che si "disegnano" a comando dell'utente, per cui ï¿œ tutto parametrizzato
al volo.
Nicola

 complicate per effettuare operazioni semplici...
vero, ma solo perchï¿œ ti ci approcci a wpf aspettandoti che sia come 
windows forms mentre non hanno nulla in comune.
.m
-- 
Mauro Servienti
{C67C0157-5D98-4733-A75E-93CAEE4BADC8}
Microsoft MVP - Visual C# / MCTS
http://mvp.support.microsoft.com
blog @ 
http://milestone.topics.it
whynot [ at ] topics [ dot ] it

 windows forms mentre non hanno nulla in comune.
Ni, nel senso che sto cercando di buttare giù l'idea di lavorare secondo
l'approccio MV-VM, e va bene.
Però capisci che mi incazzo un pochino se per disabilitare il pulsante
"chiudi" di un form sono costretto a smadonnare con le API WIN32, quando
da VB6 a Windows Form era una stupidissima proprietà del form.
Poi la gestione pessima del ClearType che non si riesce a disabilitare
(che per un software come il nostro che viene usato al 100% via Terminal
Service o Citrix viene fuori una zozzeria)...
E come queste ce ne sono altre mille!
Nicola

 E come queste ce ne sono altre mille!
Se non ï¿œ un problema di volta in volta mi segnaleresti quello che ti 
ruga? anche direttamente via mail (mauro.servienti [ at ] gmail [ dot ] 
com) se non vuoi intasare il ng.


Tornando alla storia del binding. Non capisco perchï¿œ se modifico un
valore in una textbox o ne seleziono uno da una combobox (sempre nella
DataGrid) la cosa funzione e si scatena l'evento PropertyChanged nella
ObservableCollection.
Stessa ObservableCollection, stessa datagrid stesso tutto, se il valore
ï¿œ selezionato da una checkbox invece non si scatena l'evento (e quindi
il valore nella observablecollection resta a false).
Faccio notare che il binding dalla collection alla checkbox funziona. E'
il contrario che non va.
XAML:
<DataGridCheckBoxColumn x:Name="chkValue" Binding="{Binding
Path=Checked, Mode=TwoWay}" Header="Values" Width="100*">
  <DataGridCheckBoxColumn.ElementStyle>
     <Style TargetType="CheckBox">
        <Setter Property="ContentControl.Content" Value="{Binding
Valore}" />
        <EventSetter Event="ToggleButton.Checked"
Handler="chkValue_Checked" />
        <EventSetter Event="ToggleButton.Unchecked"
Handler="chkValue_Unchecked" />
      </Style>
  </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>
Nicola

 com) se non vuoi intasare il ng.
Volentieri! :-)
Nicola

Una  parziale spiegazione qui:
http://tinyurl.com/6zldbw3
Ma non risolve il problema principale: mi aspetto che facendo click
sulla checkbox, automaticamente si propaghi il valore alla
observablecollection.
Invece ora sono obbligato ad "entrare" nella checkbox con i tasti Spazio
ed Invio della tastiera e, solo successivamente si scatena l'evento
PropertyChanged.
Mauro, mi confermi che il comportamento standard ï¿œ quello (sgradevole)
che ho descritto? O sto sbagliando qualcosa?
Nicola

 che ho descritto? O sto sbagliando qualcosa?
Non lo so, non ho capito il problema. Mi descrivi come ï¿œ fatta la 
classe con cui vai in binding?


 
Te la incollo:
Notare che la proprietï¿œ "Valore" non viene dichiarata esplicitamente con
i Get e Set, perchï¿œ ï¿œ in binding OneWay.
Public Class stcCheckedValues
    Implements INotifyPropertyChanged
    Public Event PropertyChanged(ByVal sender As Object, _
        ByVal e As PropertyChangedEventArgs) _
        Implements INotifyPropertyChanged.PropertyChanged
    Protected Overridable Sub OnPropertyChanged(ByVal PropertyName As
String)
        ' Raise the event, and make this procedure
        ' overridable, should someone want to inherit from
        ' this class and override this behavior:
        RaiseEvent PropertyChanged( _
          Me, New PropertyChangedEventArgs(PropertyName))
    End Sub
    Private _Checked As Boolean
    Public Property Valore As String
    Public Property Checked As Boolean
        Get
            Return _Checked
        End Get
        Set(ByVal value As Boolean)
            _Checked = value
            Call OnPropertyChanged("Checked")
        End Set
    End Property
End Class
Grazie,
 Nicola

Trovata la soluzione!!!
Bisogna mettere una ulteriore "proprietï¿œ della proprietï¿œ" (scusate il
gioco di parole): UpdateSourceTrigger=PropertyChanged
Quindi quello che era
Binding="{Binding Path=Checked, Mode=TwoWay}"
diventa
Binding="{Binding Path=Checked, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}">
qui la spiegazione:
http://social.msdn.microsoft.com/Forums/en/wpf/thread/7b1d5c07-a1d7-40c4-ac5e-d4e4eff86efe
Cavolo, 2 giorni a cercare informazioni su questa cosa... ecco perchï¿œ
dico che l'MSDN ï¿œ peggiorata. Magari trovi tutto, ma le cose cosï¿œ
semplici si perdono in un marasma generale.
Nicola

 semplici si perdono in un marasma generale.
Mi sono perso per strada il messaggio, questa secondo me ï¿œ tutto tranne 
che una cosa semplice, anzi mi pare molto una "strunzata" molto simile 
ad un bug. Cambiare il comportamento di default a tutti i binding non ï¿œ 
molto sano.


 Trovata la soluzione!!!
zac
Scusa eh....al di là che una volta che uno lo sà....è una proprietà in
più da settare!
...è il saperlo che è un problema!
Ma una via più semplice non c'era?
...chiedo eh....tra i mille controlli di wpf non c'era una griglia
unbound (un tempo si diceva così!) che faceva quello che volevi?
Lo chiedo per mia cultura eh!

 Lo chiedo per mia cultura eh!
Si è appunto il controllo DataGrid (che poi deriva da una ListView, per
cui le stesse cose puoi farle con una ListView).
Nicola

 unbound (un tempo si diceva così!) che faceva quello che volevi?
la griglia è sia "bound" che "unbound" l'inghippo è che con Wpf gestire 
manulamente il rapporto tra un controllo e i dati è spesso un delirio, 
come ad esempio nel caso delle liste/griglie, conviene sempre passare 
per il binding.
