190 messaggi dal 09 novembre 2005
Ciao a tutti,
potrei essere demodé, ma mi imbatto in una situazione per me nuova.
Ho sempre usato MVVM, ma mai incapsulando della logica in una combobox all'interno di uno usercontrol.

Vorrei ottenere uno usercontrol tipizzato, che:
-popola la combobox nel costruttore dello user control
-gestisca setter e getter del selecteitem dall'esterno

Scenario:
Ho una scheda cliente con un campo BancaAppoggio, quindi, questa Window mostra l'oggetto Cliente.
La proprietà BancaRelativa mostra l'attuale banca del cliente.
Dovrei mostrare il mio ComboBoxUserControl passandogli il Cliente.BancaRelativa, lui mi mostra la banca corrente e mi fornisce l'elenco delle banche (eventualmente per cambiare la banca del cliente), e quindi la gestione TwoWay del binding.

Arg!!!!

Ora creo una DependecyProperty nel ComboBoxUserControl

#region DP Value

public BancaAppoggio Banca
{
  get { return (BancaAppoggio) GetValue(BancaAppoggioProperty); }
  set { SetValue(BancaAppoggioProperty, value); }
}
public static readonly DependencyProperty BancaAppoggioProperty =
  DependencyProperty.Register("Banca", typeof(BancaAppoggio),
  typeof(BancheAppoggioComboBox), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, Changed));
private static void Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  var c = d as BancheAppoggioComboBox;
  var i = (BancaAppoggio) e.NewValue;

  if (c.LocalValue == null)
    c.BancheAppoggioComboBox_Loaded(c, null);

  c.LocalValue = i;
}

#endregion


Nella Window del cliente uso questo
<combobox:BancheAppoggioComboBox Banca="{Binding BancaRelativa, UpdateSourceTrigger=PropertyChanged}" Width="300"/>


Appena parte la Window so che scatta il setter della proprietà Cliente.BancaRelativa, ma non appare selezionata a livello visuale.
Se provo a cambiare la banca dalla combobox funziona il tutto.

Questo è lo usercontrol

<Grid x:Name="Root">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <telerik:RadButton Content="..." Width="25" Height="25" Margin="0,0,1,0"
                           Command="{Binding LookupCommand}"/>
        <telerik:RadComboBox IsEditable="false" Grid.Column="1" CanAutocompleteSelectItems="True"
                             StaysOpenOnEdit="True"
                             ItemTemplate="{StaticResource ComboBoxTemplate}"
                             ItemsSource="{Binding BancheAppoggio}"
                             SelectedItem="{Binding Path=Banca,Mode=TwoWay,ElementName=userControl}">
            <telerik:RadComboBox.FilteringBehavior>
                <local:BancheAppoggioFilteringBehavior />
            </telerik:RadComboBox.FilteringBehavior>
        </telerik:RadComboBox>
    </Grid>


Domanda:
1) Come posso rendere Cliente.BancaAppoggio un'istanza della List<BancaAppoggio> utilizzata nella ComboBox?
2) Mi sono posto la domanda giusta?
Modificato da dakyn77 il 28 aprile 2016 15.19 -
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,


Vorrei ottenere uno usercontrol tipizzato, che:
-popola la combobox nel costruttore dello user control

Mmmh, ok. Se possibile dovresti esporre una ulteriore dependency property affinché la view possa fornire l'elenco delle opzioni dall'esterno, altrimenti lo user control è costretto ad andarseli a prendere lui (es. facendo una query LINQ) ed interessarsi di business logic (es. sapere quando una banca può essere visualizzata e quando no).


Ho una scheda cliente con un campo BancaAppoggio, quindi, questa Window mostra l'oggetto Cliente.

Il tuo ViewModel è un'istanza di "Cliente"? Metti invece una proprietà di tipo Cliente, così potrai crearne anche un altra di tipo List<BancaAppoggio> per fornire alla view il suddetto elenco di banche selezionabili.


Ora creo una DependecyProperty nel ComboBoxUserControl

Ok, corretto.


Appena parte la Window so che scatta il setter della proprietà Cliente.BancaRelativa, ma non appare selezionata a livello visuale.

Provo ad indovinare: succede perché non è la stessa istanza di BancaAppoggio.
Dato che lo usercontrol sta estraendo esso stesso l'elenco delle banche, ha dovuto crearsi delle proprie istanze di oggetti BancaAppoggio.
Quando riceve la banca selezionata per mezzo della dependency property, troverà un'istanza di BancaAppoggio diversa, che era stata invece creata dal viewmodel.

Quindi, quando la combobox prova a confrontare il SelectedValue con uno degli altri items, non troverà alcuna corrispondenza. Come saprai, in C# questo restituisce false.
var istanza1 = new Banca { ID = 1, Nome = "Banca ABC"};
var istanza2 = new Banca { ID = 2, Nome = "Banca ABC"};
//false
var uguale = istanza1.Equals(istanza2);

...a meno che tu non abbia effettuato l'override dei metodi Equals / GetHashCode.

Secondo me, questo è un motivo ulteriore per farti dare l'elenco delle banche dall'esterno, esponendo un'apposita dependency property.

Sarà compito del viewmodel assicurarsi che la banca del cliente sia una delle istanze della lista. Se stai usando lo stesso DbContext per estrarre sia il cliente che l'elenco di banche, allora è garantito che l'istanza di BancaAppoggio sarà la stessa perché EF mantiene nel contesto solo un'istanza di una certa entità.


private static void Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)

Perché hai dovuto usare questo metodo Changed? Non potresti semplicemente mettere in binding two-way la proprietà SelectedValue della combobox con la dependency property Banca dello usercontrol in cui si trova?

ciao,
Moreno

Enjoy learning and just keep making
190 messaggi dal 09 novembre 2005
Ciao e grazie per la tua riposta, anche se un po' in ritardo..... ma ho valanghe di richieste...
Se ho capito bene, tu intendi che il ViewModel della Scheda Cliente dovrebbe fornire allo user control la List<BancaAppoggio>, in modo che passando anche al SelectedItem una istanza BancaAppoggio della stessa List<T>, il tutto funziona.

Tutto chiaro, ma lo scopo è quello di incapsulare tutta la logica di recupero dati per la combobox nello usercontrol.

Il motivo di questo è anche limitare il codice nel viewmodel della scheda cliente, se devo recuperare la lista di banche nel viewmodel della scheda cliente, a sto punto mi faccio carico di tutta la gestione della combobox direttamente.
Invece l'idea è che se nel CustomerViewModel ho la property CurrentCustomer (oggetto CustomeModel) che ha a sua volta la property BankAccount (oggetto BankAccountModel), nella view vorrei scrivere <ctl:CustomBankAccountComboBox CustomValue="{Binding CurrentCustomer.BankAccount,Mode=TwoWay}"/>
quindi nella mia CustomBankAccountComboBox avrò il viewmodel che si occuperà del recupero della List<BankAccountModel> e della DP chiamata CustomValue di tipo BankAccountModel.
Quindi come posso recuperare al PropertyChanged della DP, la BankAccountModel corrente e cercare nella List<BankAccountModel>? (Tenendo conto del l'evento PropertyChanged della DP è static) non so come si fa.... :-(

Il problema è solo passare il primo valore che arriva da CurrentCustomer.BankAccount, poi se seleziono un altro valore dalla ComboBox ritorna indietro correttamente.

Perché se dovessi adottare il tuo approccio avrei una situazione un po' ibrida, no? Tutta la logica è nella combobox ma tranne la lista che dovrebbe mostrarmi...

Che ne pensi del mio ragionamento? Oppure ho frainteso?

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.