none
passare context,repository, model ad un viewmodel generico RRS feed

  • Domanda

  • ciao a tutti, sto creando un applicazione wpf mvvm. Sto utilizzando anche entity framework code first la mia soluzione è composta da un 2 progetti:

    1) application.domain dove ci sono tutte le classi poco ,i repository ed il mio dbcontext per potermi creare il db da code first.

    2)application.ui dove ce la mia view,viewmodel,e model.

    quindi se io nella mia application.domain ho una classe poco articoli :

    public class Articolo{
       Codice {get;set,}
       Descrizione {get;set}
    }

    applicationUnitOfWork:

        public class SednaUnitOfWork : DbContext,IContext 
        {
     
            static string _connection;
    
            public SednaUnitOfWork()
            :base(_connection)
            {
    
    
            }
            public SednaUnitOfWork(string connString)
                : base(connString)
            {
                _connection = connString;
                Database.SetInitializer(new MigrateDatabaseToLatestVersion<SednaUnitOfWork, Configuration>());
    
    
            }
     
    
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    
                modelBuilder.Entity<Articoli>();
    }

    nella mia application.ui avro un model simile solo dove implemento INotifyPropertyChanged:

     private string codice;
     private string descrizione;
     
    
     public string Codice
            {
                get { return codice; }
                set
                {         
                    codice = value;
                    OnPropertyChanged("Codice");
                }
            }
    
    
            public string Descrizione
            {
                get { return descrizione; }
                set
                {
                    descrizione = value;
                    OnPropertyChanged("Descrizione");
                }
            }


    Intanto volevo sapere se questa è la strada piu idonea, visto che la classe articolo sembra essere ripetitiva(vabbe una mi server per crearmi il db ,l altra è il model da collegare alla view).

    Adesso nel mi view model ogni volta instanzio i repositori e il context. Ad esempio se sto creando la view articoli, a sua volta creero il viewmode articoli dove inizializzo repositoryArticoli e passo il model(articoliModel) lo stesso faro per un altra view e cosi via... C'è un modo per crearmi un viewModel generico dove a seconda la view gli passo il repository e il model specifico? Perche dovrei fare le operaizoni crud su queste view (saranno un 50 view) tutte simili tra loro quandi volevo crearmi un unico viewmodel oppure un user control pero non riesco a passare il repository,il model e il context della view

    lunedì 27 gennaio 2014 22:31

Tutte le risposte

  • Ciao,

    potresti postare un esempio di viewmodel ed uno del repository? Giusto da chiudere il cerchio e capire il design che hai in testa e ragionare su quello (dal tuo codice si vede metà della tua idea:)

    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    martedì 28 gennaio 2014 09:10
  • certo , hai ragione scusami :D 

    un mio view model :

    class CreaArticoliViewModel : ViewModelBase { private SednaUnitOfWork _ctx; public ArticoliModel _articoliModel { get; set; } public ArticoliRepository<Articoli> articoliRepository; public RelayCommand SalvaCommand { get; set; } public RelayCommand EliminaCommand { get; set; } public RelayCommand AnnullaCommand { get; set; } public InfoLogin infoLogin; public CreaArticoliWindow articoliWindow; public CreaArticoliViewModel(ImballaggiModel imballaggi,CreaArticoliWindow _articoliWindow) { infoLogin = (InfoLogin) Application.Current.Properties["InfoLogin"]; _ctx = new SednaUnitOfWork(infoLogin.ConnString); articoliWindow = _articoliWindow; articoliRepository = new ArticoliRepository<Articoli>(_ctx); articoliModel = new ArticoliModel(); SalvaCommand = new RelayCommand(Salva); EliminaCommand = new RelayCommand(Elimina); AnnullaCommand = new RelayCommand(Annulla); } /* siccome non volevo inserire all'interno del viewmodel le classi per il model della view cioè le classi

    dove è implementato OnPropertyChanged esempio:

            private string codice;

         public string Codice
            {
                get { return codice; }
                set
                {
                    codice = value;
                    OnPropertyChanged("Codice");
                }
            }

    Ho creato una classe separata appunto chiamata ArticoliModel dove ci sono tutte le proprieta.

    */ public ArticoliModel articoliModel { get { return _articoliModel; } set { if (_articoliModel != value) { _articoliModel = value; OnPropertyChanged("articoliModel"); } } } void Elimina(object parametr) { if (MessageBox.Show("Vuoi davvero eliminare il dato?", "Question", MessageBoxButton.YesNo,MessageBoxImage.Warning) == MessageBoxResult.Yes) { articoliRepository.EliminaPerId(articoliModel.Id); _ctx.SaveChanges(); articoliModel = new ArticoliModel(); articoliWindow.Close(); } } void Salva(object parametr) { var articoliNuovo = Mapper.Map<ArticoliModel, Articoli>(articoliModel);// è un automapper non faccio altro che mappare la mia classe poco (articoli,che mi serve per crearmi il Db tramite codefirst) con il modello che e agganciato alla view articoliModel articoliNuovo.DataCreazione = DateTime.Now; if (articoliModel.HasErrors) { var msgService = new MsgBoxService(); msgService.ShowNotification("Attenzione ci sono degli errori !"); return; } if (articoliNuovo.Id == Guid.Empty) { articoliNuovo.Id = Guid.NewGuid(); articoliRepository.Aggiungi(articoliNuovo); } else { articoliRepository.Aggiorna(articoliNuovo); } _ctx.SaveChanges(); articoliModel = new ArticoliModel();//per azzerare la mia view } void Annulla(object parametr) { if (MessageBox.Show("Vuoi davvero annullare?", "Conferma", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes) { articoliModel = new ArticoliModel(); } } } }


    Sono un po confuso perchè non mi piace tutto questo codice, articoliModel poi e agganciato al xaml l'ho creato per evitare di scrivere tutte le propietà all'interno del view model, cosi li trovo tutti in una classe separata.

    il mio repository invece :

        public class ArticoliRepository<T> : RepositoryBase<T> where T:class 
        {
    
            public ArticoliRepository(DbContext _context)
                : base(_context)
            {
            }
    
    
        }

    repositorybase:

     public class RepositoryBase<T> where T : class
        {
            private readonly DbSet<T> ctx;
            internal DbContext context;
    
            public RepositoryBase(DbContext _context)
            {
                context = _context;
                ctx = _context.Set<T>();
    		}
    
    
            public void Aggiungi(T oggetto)
            {
                ctx.Add(oggetto);
            }
    
            public bool EliminaPerOggetto(T oggetto)
            {            
               ctx.Remove(oggetto);
                return true;
            }
    
            public void EliminaPerId(object id)
            {
                var entityToDelete = ctx.Find(id);
                ctx.Remove(entityToDelete);
            }
    
            public T PrendiPerId(T id)
            {
                return ctx.Find(id);
            }
    
            public void RimuoviLista(List<T> entities)
            {
                foreach (var entity in entities)
                {
                    Rimuovi(entity);
                }
            }
    ...etc...
    }

    Ho creato un repository specifico che eredita da uno base perchè in futuro mi serviranno determinate operazioni solo per lo specifico repository

    martedì 28 gennaio 2014 09:58
  • Ciao,

    allora, secondo me è inutile creare una classe del modello da riferire nel viewmodel: riferisci direttamente le property nel viewmodel.

    Riguardo il repository, io userei direttamente RepositoryBase<T> nei viewmodel (magari rinominati come Repository<T>). Per i metodi custom usa degli extension method tipizzati, ad esempio:

    public static class ArticoloRepositoryExtension
    {
       public static IQueryable<Articolo> RitornaArticoliPiuVenduti(this Repository<Articolo> source)
      {
         throw new NotImplementedException();
      }
    }

    In questo modo ti eviti di dover creare una classe per ogni tipo del modello, e nello stesso tempo puoi customizzare dei metodi specifici per entità.

    Ti quadra?

    Ciao

    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    martedì 28 gennaio 2014 12:43
  • grazie per la risposta,

    per quanto riguarda i repository in effetti ci avevo pensato , di dichiarare direttamente il repository generico e poi dove m iserviva quello specifico ne creavo una ad hoc.

    invece per quanto riguarda di creare una classe del modello invece di inserire le propieta direttamente nel view model, lho fatto semplicemente perche se una view ho 50 campi(propieta) il  mio viewmodel cresce enormemente(come linee di codice intendo) 

    Infine in base alla mia situazione se io dovrei far passare ad un view model il context corrente e il model della view corrente come potrei fare( esempio un usercontrol per le operazioni crud in cui passandogli il conteext e il model cn relativo repository. ne creo uno per tutte le view simili cosi senza implementare in ogni viewmodel le operaizoni crud... non so se sia possibile fare tutto ciò)

    martedì 28 gennaio 2014 12:58
  • Infine in base alla mia situazione se io dovrei far passare ad un view model il context corrente e il model della view corrente come potrei fare( esempio un usercontrol per le operazioni crud in cui passandogli il conteext e il model cn relativo repository. ne creo uno per tutte le view simili cosi senza implementare in ogni viewmodel le operaizoni crud... non so se sia possibile fare tutto ciò)

    non ho capito:D mi faresti un esempio?

    Grazie!


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    martedì 28 gennaio 2014 13:16
  • certo :D,
    in base alla mia situazione. io devo creare diverse view tutte simili tra loro semplici operazioni crud.

    esempio ho una view articoli con due textbox codice e descrizione(lo stesso vale per le altre view, clienti,fornitori,articoli,mastri,conti etc...) 

    In ogni view ci saranno i tasti elimina inserisci salva ricerca. adesso io invece di implementare in tutte le view questi tasti (operazioni crud) volevo crearmi un user control cosi da farne uno e inserilo in ogni view.

    Il problema (in primis la mia ignoranza sono nuovo cn qst tecnologie ;) ) come faccio a crearmi questo user control generico perche in base alla view dove lo inserisco devo passarlgi il context, il repository e il model(perche una volta la tabella sara articoli, poi sara tara e cosi via)

    ad esempio per adesso il tasto elimina lho inserito direttamente all interno della view e nel rispettivo view model lho implementato :

            private void Elimina(object _obj)
            {
                if (MessageBox.Show("Vuoi davvero eliminare il dato?", "Attenzione", MessageBoxButton.YesNo,
                    MessageBoxImage.Warning)
                    == MessageBoxResult.Yes)
                {
                        articoliRepository.EliminaPerId(articoliModel.Id);
                        _ctx.SaveChanges();
                        articoliModel = new ArticoliModel();
                }
    
            }

    questo(cosi come salva ricerca ed inserisci) invece di implementarlo in ogni mio viewmodel ,vorrei farlo solo una volta in un usercontrol. 

    Ma non riesco a capire come passargli il context corrente il repository adatto per quella view...

    Non so se mi sono spiegato bene, non so se e la strada giusta se ci sono altre soluzioni,o se non si puo fare, siccome mi sembra trp ripetitivo implementare le operazioni crud per tutte quelle view simili tra loro dove cambia solo il contesto e il repository. quindi vorreo inserire nella mi view un usercontrol con tutti i tasti e le implementazioni per le operazioni crud pero dovrei passargli il context e le tabelle giuste perche cambiano a secondo della view

    martedì 28 gennaio 2014 13:26
  • Ok inizio a capire:D

    Ultima domanda: nella view hai una griglia con tutti gli elementi e su cui fai editing inline, oppure per ogni entità hai dei form di inserimento e/o modifica di un singolo elemento?


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    martedì 28 gennaio 2014 14:42
  • scusami ma dipende da me come mi espogno =( e scusami se non sono troppio chiaro ;) 

    allora per ogni entita(articoli,tara,conti,clienti,mastro) ho una view di inserimento/modifica. 

    Poi mi sono creato una view generica con una griglia , quando nella view inserimento/modifica clicco su ricerca(si apre la mia view genercia con la griglia) gli passo la lista dell'oggetto che mi interessa e facendo doppio click me lo riporto nella view di inserimento/modifica.(cosi ho creato una sola view per fare la ricerca di tutte le view simili)



    • Modificato brux88 martedì 28 gennaio 2014 20:03
    martedì 28 gennaio 2014 15:23
  • Non preoccuparti:)

    Allora, mettiamo alcuni punti fermi: dovresti avere un viewmodellocator che:

    • costruisce gli usercontrol
    • costruisce i viewmodel
    • assegna al datacontext di ogni usercontrol, il corretto viewmodel

    lo usercontrol se ha la stessa identica forma per più entità può essere un singolo usercontrol istanziato più volte. Es.:

    var viewArticolo = new EditUserControl();
    viewArticolo.DataContext = CreateArticoloViewModel();
    var viewReso = new EditUserControl();
    viewReso.DataContext = CreateResoViewModel();
    ....

    Buona fin qui?

    Le dipendenze (repository ed entità) le passi nel viewmodel che a questo punto può essere anch'esso unico (almeno quello per gestire le griglie) sfruttando i generic. Es.:

    public class ListViewModel<T>
    {
      Repository<T> repository;
    
      public ListViewModel(ObjectContext context)
    {
      repository = new Repository<T>(context);
      this.Items = repository.GetAll();
      RaisePropertyChange(t=>t.Items);
    }
    
    
      ObservableCollection<T> Items = new ObservableCollection<T>();
    }

    La parte complessa da generalizzare sono le view e i view model di edit e inserimento. Io vedo 2 possibilità: o nel view model tramite reflection generi una lista di proprietà da editare con i rispettivi valori, e li metti in binding nella view; oppure puoi generarti le view e i viewmodel tramite templare T4 e tramite partial class customizzare eventuali comportamenti di un singolo viewmodel.

    Spero di essermi spiegato:D

    Gianluca 


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    mercoledì 29 gennaio 2014 00:05
  • ciao grazie per questi aiuti che mi dai, sto entrando sempre piu nell'ottica.

    L unica cosa che non mi è chiara e proprio questo viewmodellocator, non ho mai avuto modo di lavorarci e di capire bene cosa fa.

    Infine io  non riesco proprio a passare i tipi generic T nel mio viewmodel lo dovrei far da questo "viewmodelocator"??

    perche se io dalla mia view articoli richiamo la view ricerca entrambi avrnano un loro viewmodel come faccio a passare prima il tipo t = Articoli e poi il tipo T = tara

            private void Ricerca(object _obj)
            {
                                  };
    
    
    
                    var ricercaWindow = new RicercaWindow();
                    ricercaWindow.ShowDialog();
    }

    ricercaWindows.cs

        public partial class RicercaWindow
        {
            public RicercaWindow()
            {
                InitializeComponent();    
                DataContext = new RicercaViewModel();
            }
    }

    In ricercaViewModel come faccio a passare il T generci. UNa volta puo essere articoli un altra volta tara ,clienti e cosi viaa



    • Modificato brux88 mercoledì 29 gennaio 2014 08:25
    mercoledì 29 gennaio 2014 08:18
  • Il ViewModelLocator è quel "tizio" che ha il compito di costruire i viewmodel con tutte le dipendenze e di associare i viewmodel al datacontext delle rispettive view. Esistono millemila implementazioni e spesso utilizzano librarie di dependency injection (Unity di Enterprise Library o Castle, per esempio), ma nel tuo caso ti conviene - almeno inizialmente - eseguire queste operazioni a "manina". Di fatto è esattamente il punto in cui fare quello su cui tu avevi il dubbio di come e dove mettere, ovvero costruzione dei viewmodel, e dei repository (vedi esempio di codice precedente).

    Il modo più semplice di implementarlo è creare una classe statica (ViewModelLocator) che espone come property tutti i tuoi viewmodel e metterla in binding come static resource alla proprietà DataSource.

    Fatto questo, nella tua window puoi definire tramite xaml tutti gli usercontrol che ti servono, e mettere in binding ognuno di esso con il viewmodel corrispondente esposto dalla rispettiva property del locator.

    Nel costruttore statico del locator istanzi tutti i viewmodel risolvendo le dipendenze e li associ alle property che poi esponi.

    Questa è l'implementazione più semplice possibile, esistono svariati modi - più furbi - per ottenere lo stesso risultato, ma sicuramente più complessi. Io ti consiglierei questa strada e appena ci prendi la mano googoleggi "mvvm ViewModelLocator" e ti studi le alternative:)

    Buon lavoro!

    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    mercoledì 29 gennaio 2014 09:03
  • ciao =) sono un stress lo so me ne rendo conto hihi,

    ho googlato un po per capire meglio questo viewmodellocator. Infatti i miei dubbi e perplessità credo dipendano proprio dal fatto che non conoscevo questo pattern.

    Ho creato un nuovo progetto da zero semplice semplice per capre meglio tutto cio.

    questa applicazione ha una windows con due textbox codice e Descrizione. e un tasto Salva

    Ho creato il mi viewmodellocator(proprio basilare anche perche per adesso non so come implementarlo a dovere per le mie esigenze):

        public class ViewModelLocator
        {
            public MainWindowViewModel MainPage
            {
                get
                {
                    return new MainWindowViewModel();
                }
            }
        }

    ho la mia window:

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid DataContext="{Binding MainPage, Source={StaticResource ViewModelLocator}}">
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,69,0,0" TextWrapping="Wrap" Text="{Binding Codice}" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,109,0,0" TextWrapping="Wrap" Text="{Binding Descrizione}" VerticalAlignment="Top" Width="120"/>
            <Label Content="Codice" HorizontalAlignment="Left" Margin="30,66,0,0" VerticalAlignment="Top"/>
            <Label Content="Descrizione" HorizontalAlignment="Left" Margin="30,106,0,0" VerticalAlignment="Top"/>
            <Button Content="Salva" HorizontalAlignment="Left" Margin="432,288,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SalvaCommand}"/>
    
        </Grid>
    </Window>

    e infine il mio viewmodel creato con i tuoi suggerimenti non istanziando una classe del model ma direttamente tutte le proprietà all'interno di esso e istanziando RepositoryBase<T>:

      public class MainWindowViewModel:ViewModelBase
        {
            #region Model
    
            private string _codice;
            private string _descrizione; 
    
            public string Codice
            {
                get { return _codice; }
    
                set
                {
                    _codice = value;
                    OnPropertyChanged();
                }
            }
    
             
    
            public string Descrizione
            {
                get { return _descrizione; }
                set
                {
                    _descrizione = value;
                    OnPropertyChanged();
                }
            }
    
            #endregion
       
            
            #region Command
                  public RelayCommand SalvaCommand { get;set; }
            #endregion
        
            
            
            public RepositoryBase<Articoli> articoliRepository;
            public SednaUnitOfWork Ctx ;
            public MainWindowViewModel()
            {
                Ctx = new SednaUnitOfWork();
                articoliRepository = new RepositoryBase<Articoli>(Ctx);
    
                SalvaCommand = new RelayCommand(Salva);    
            }
    
    
    
            private void Salva(object _obj)
            {
                var codice = Codice;
                var descrizione = Descrizione;
                var nuovoOggetto = new Articoli
                                   {
                                       Codice = codice,
                                       Descrizione = descrizione
                                   };
                articoliRepository.Aggiungi(nuovoOggetto);
                MessageBox.Show(codice+"-"+descrizione);
            }
        }


    Arrivato a questo punto. Non riesco a capire come passare al viewmodel tramite il locator la mia classe Articoli o tara o clienti in base alle view. 

    =(

    mercoledì 29 gennaio 2014 13:35
  • Dai che ci sei quasi:)

    Fai diventare static la tua classe ViewModelLocator e definisci da qualche parte (per semplicità nella window una risorsa del viewmodel locator). Fatto questo dovrebbe funzionare (occhio a dichiarare correttamente il namespace del locator!):

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    		xmlns:vm="clr-namespace:Qui.ILNAMESPACE.DEL.VIEWMODELLOCATOR"
            Title="MainWindow" Height="350" Width="525">
    	<Window.Resources>
    		<ResourceDictionary>
    			<vm:ViewModelLocator x:Key="Locator" />
    		</ResourceDictionary>
    	</Window.Resources>
    		
        <Grid DataContext="{Binding MainPage, Source={StaticResource Locator}}">
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,69,0,0" TextWrapping="Wrap" Text="{Binding Codice}" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,109,0,0" TextWrapping="Wrap" Text="{Binding Descrizione}" VerticalAlignment="Top" Width="120"/>
            <Label Content="Codice" HorizontalAlignment="Left" Margin="30,66,0,0" VerticalAlignment="Top"/>
            <Label Content="Descrizione" HorizontalAlignment="Left" Margin="30,106,0,0" VerticalAlignment="Top"/>
            <Button Content="Salva" HorizontalAlignment="Left" Margin="432,288,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SalvaCommand}"/>
    
        </Grid>
    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka


    mercoledì 29 gennaio 2014 13:47
  • scusami ma non riesco a capire questa parte :

    	<Window.Resources>
    		<ResourceDictionary>
    			<vm:ViewModelLocator x:Key="Locator" />
    		</ResourceDictionary>
    	</Window.Resources>

    mercoledì 29 gennaio 2014 14:07
  • Serve per informare lo xaml, che la risorsa statica è la classe Qui.ILNAMESPACE.DEL.VIEWMODELLOCATOR.ViewModelLocator e nello xaml sarà riferito con la chiave "Locator", così da poterla mettere in binding come data source.

    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    mercoledì 29 gennaio 2014 14:50
  • Scusami ma c'è di nuovo qualcosa che mi sfugge.

    Facendo ciò non riesco a capire come posso fare a passare Articoli,tara o Clienti :

    <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:viewModel="clr-namespace:BrunoMvvmLocator.ViewModel"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <ResourceDictionary>
                <viewModel:ViewModelLocator x:Key="Locator" />
            </ResourceDictionary>
        </Window.Resources>
        <Grid DataContext="{Binding MainPage, Source={StaticResource Locator}}">
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,69,0,0" TextWrapping="Wrap" Text="{Binding Codice}" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,109,0,0" TextWrapping="Wrap" Text="{Binding Descrizione}" VerticalAlignment="Top" Width="120"/>
            <Label Content="Codice" HorizontalAlignment="Left" Margin="30,66,0,0" VerticalAlignment="Top"/>
            <Label Content="Descrizione" HorizontalAlignment="Left" Margin="30,106,0,0" VerticalAlignment="Top"/>
            <Button Content="Salva" HorizontalAlignment="Left" Margin="432,288,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SalvaCommand}"/>
    
        </Grid>
    </Window>

    EDIT:

    la resource dictionary l avevo inserita nell app.xaml

        <Application.Resources>
            <viewModel1:ViewModelLocator x:Key="ViewModelLocator" />
        </Application.Resources>

    Per non continuo a capire come posso ottenere il mio risultato =(

    • Modificato brux88 mercoledì 29 gennaio 2014 15:33
    mercoledì 29 gennaio 2014 14:56
  • Devi far derivare tutte le tue entità da una interfaccia comune o una classe base che espone la proprietà codice e descrizione.

    Fatto questo, facilmente fai refactoring del ViewModel rendendolo generico vincolato al tipo dell'interfaccia o della classe base (così da poter richiamare la proprietà codice e descrizione.

    Fatto questo la proprietà MainPage la puoi cambiare a runtime con una istanza differente per modello:

       public static class ViewModelLocator
        {
            public object MainPage{get;set }
    
    static MainWindowViewModel<Articolo> articoloViewModel = new  MainWindowViewModel<Articolo>();
    
    
    static MainWindowViewModel<Cliente> clienteViewModel = new  MainWindowViewModel<Cliente>();
    
    static ViewModelLocator(){
    MainPage = articoloViewModel;
    }
    
    public static RelayCommand CambioTipoCommand = new RelayCommand(p=>{
    if (p is string && p == "articolo") MainPage = articoloViewModel;
    if (p is string && p == "cliente") MainPage = clienteViewModel;
    });
    
        }

    Giusto come esempio, adesso se agganci tramite  il comando del locator CambioTipoCommand, puoi usare la windows sia per il cliente e per l'articolo.

    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    mercoledì 29 gennaio 2014 15:47
  • si esatto io avevo fatto qualcosa del genere:

        public  class ViewModelLocator
        {
            public  MainWindowViewModel<Articoli> MainPage
            {
                get
                {
                    return new MainWindowViewModel<Articoli>();
                }
            }
    
            public ClientiViewModel<Clienti> ClientiView
            {
                get
                {
                    return new ClientiViewModel<Clienti>();
                }
            }
    }

    Perchè il mio caso non e di avere una view per le stesse operazioni ma al contrario. Perche nella view Articoli ci sara Codice e Descrizione mentre nella view Clienti ci sara codice e Indirizzo. quindi avranno propieta diverse.

    Se dovrei ereditarmi tutte le mie entita da una base dovrei inserire sia le propietà degli articoli che dei clienti giusto?

    Pero non credo sia ottimale perche se no la classe base aumentara enormemente per ogni view ci saranno 50 propieta tutte diverse a seconda della view.(non so se mi sto facendo capire heheh )

    Quindi sto cercando di crearmi una view per articoli e una per clienti. passandogli tramite il locator al viewmodel la mia tabella di riferimento(articoli o clienti) posso inizializzare il repository generico Repositoybase<T> .

    Per questo sto cercando di creare un user control dove vorrei passargli il model e poi persisterli nel db. 

    Perchè secondo la mia logica arrivato finalmente a questo punto :D io dovrei avere una view Articoli con il suo viewmodel dove ci saranno tutte le propieta. , dovrei inseire un user control dove saranno implementate le operazioni crud, ma questo user control dovra sfruttare il model della view che lo contiene perche una volta puo essere articoli un altra clienti.

    Ho fatto qualcosa del genere ma non so se è giusto ne mio metodo salva:

            private void Salva(object _obj)
            {
    
            
                _articoliModel.Id = Guid.NewGuid();
                var articoliModel = Mapper.Map<ArticoliModel, T>(_articoliModel);
    
                articoliRepository.Aggiungi(articoliModel);
                Ctx.SaveChanges();
                MessageBox.Show(_articoliModel.Codice + "-" + _articoliModel.Descrizione);
                ArticoliModel = new ArticoliModel();
    
            }

    ho creato una classe ArticoliModel e lho inizializzata nel mio view model è dove ci sono le proprietà del model. Perchè se ho 50 propieta nel model, quando dovevo aggiungerlo nel db dovevo passargli o tutte e 50 la propieta o crearmi un oggetto cone le 50 propieta, invece cosi creandomi questo ArticoliModel e instnaziandolo cosi:

    viewmodel:

            public MainWindowViewModel()
            {
                Ctx = new SednaUnitOfWork();
                articoliRepository = new RepositoryBase<T>(Ctx);
                Mapper.CreateMap<ArticoliModel, T>();
                SalvaCommand = new RelayCommand(Salva);
                _articoliModel = new ArticoliModel();
    
            }  
    
      public class ArticoliModel:ViewModelBase
        {
            private string _codice;
            private string _descrizione;
            public Guid Id {get;set;}
            public string Codice
            {
                get { return _codice; }
    
                set
                {
                    _codice = value;
                    OnPropertyChanged();
                }
            }
    
    
    
            public string Descrizione
            {
                get { return _descrizione; }
                set
                {
                    _descrizione = value;
                    OnPropertyChanged();
                }
            }
        }

    view:

    <Window x:Class="BrunoMvvmLocator.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:viewModel="clr-namespace:BrunoMvvmLocator.ViewModel"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <ResourceDictionary>
                <viewModel:ViewModelLocator x:Key="Locator"  />
            </ResourceDictionary>
        </Window.Resources>
        <Grid DataContext="{Binding MainPage, Source={StaticResource Locator}}">
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,69,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Codice}" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,109,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Descrizione}" VerticalAlignment="Top" Width="120"/>
            <Label Content="Codice" HorizontalAlignment="Left" Margin="30,66,0,0" VerticalAlignment="Top"/>
            <Label Content="Descrizione" HorizontalAlignment="Left" Margin="30,106,0,0" VerticalAlignment="Top"/>
            <Button Content="Salva" HorizontalAlignment="Left" Margin="432,288,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SalvaCommand}"/>
            <Button Content="Button" HorizontalAlignment="Left" Margin="61,272,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    
        </Grid>
    </Window>
    

    mi trovo tutto già in Articolimodel senza fare :

                var nuovoOggetto = new ArticoliModel
                                   {
                                       Id  = Guid.NewGuid(),
                                       Codice = codice,
                                       Descrizione = descrizione
                                   };*/

    Poi tramite automapper ho mappato il model della view con la ia classe poco per la persistenza del db

    • Modificato brux88 mercoledì 29 gennaio 2014 17:50
    mercoledì 29 gennaio 2014 17:23
  • Quindi problema risolto? (mi sono un po' perso;)

    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    mercoledì 29 gennaio 2014 19:07
  • heheeh in parte si... il mio unico problema adesso sta nel far capire al mio viewmodel o user coontrol quale model sto utilizzando. Cerco di spiegarmi meglio con un esempio:

    Ho creato sempre in riferimento al codice precedente nella view articoli ho inserito un user control(un tasto per effettuare il salvataggio):

    user control viewmodel

      public class CrudUserControlViewModel<T> : ViewModelBase where T : class
        {
            public RelayCommand SalvaCommand { get; set; }
            public RepositoryBase<T> repository;
            public SednaUnitOfWork Ctx;
            public object _model;
            public CrudUserControlViewModel(object model, SednaUnitOfWork ctx)
            {
                _model = model;
                Ctx = ctx;
                repository = new RepositoryBase<T>(Ctx);
                Salva2Command = new RelayCommand(Salva2);
                Mapper.CreateMap<object, T>();
            }
    
            private void Salva2(object _obj)
            {
        
                var articoliModel = Mapper.Map<object, T>(_model);
                // _articoliModel.Id = Guid.NewGuid();
    
                repository.Aggiungi(articoliModel);
                Ctx.SaveChanges();
    
            }
        }
    }

    user control xaml:

    <UserControl x:Class="BrunoMvvmLocator.UserControl.CrudUserControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:viewModel="clr-namespace:BrunoMvvmLocator.ViewModel"
                 mc:Ignorable="d" Height="46.24" Width="102.631">
        <UserControl.Resources>
            <ResourceDictionary>
                <viewModel:ViewModelLocator x:Key="Locator"  />
            </ResourceDictionary>
        </UserControl.Resources>
        <Grid DataContext="{Binding CrudUserControl, Source={StaticResource Locator}}">
            <Button Content="Salva" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SalvaCommand}"/>
    
        </Grid>
    </UserControl>

    e nel mio viewlmodellocator:

            public CrudUserControlViewModel<Articoli> CrudUserControl
            {
                get
                {
                    return new CrudUserControlViewModel<Articoli>(MainPage.ArticoliModel,MainPage.Ctx);
                }
            }

    In poche parole sto cercando di passare anche il model e il context della view a cui appartiene l user control.

    Il context riesco a passarlo mentre il model (MainPage.ArticoliModel) passandolo come l'ho passato io(

                    return new CrudUserControlViewModel<Articoli>(MainPage.ArticoliModel,MainPage.Ctx);

    ) ovviamente lo passa ma null. Perche ancora quando si inizializza l'usercontrol nel viewmodellocator non ho scritto nulla nelle textbox.

    Dunque tutto il discorso sta nel fatto che non so come aggiornare il model all user control.



    • Modificato brux88 mercoledì 29 gennaio 2014 19:16
    mercoledì 29 gennaio 2014 19:15
  • Non mi quadra da dove esce il CrudUserControlViewModel e che relazione ha rispetto al MainPage.

    ... il problema è che spiegarsi via forum è complesso.

    Ad ogni modo, il giro è questo: hai una view in cui metti in binding (potenzialmente bidirezionale) delle proprietà del viewmodel, in questo modo aggiorni il modello.

    Devi costruirti tutti i viewmodel allo startup dell'applicazione (nel locator) e quando ti serve editare una entità, dall'id dell'entità recuperi l'istanza del modello e la passi (o valorizzi) il viewmodel (senza reistanziarlo ogni volta).

    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    mercoledì 29 gennaio 2014 19:45
  • si infatti, hai ragione... =( 

    Ho creato un UserControl(CrudUserControl.xaml) e il suo rispettivo viewmodel (CrudUserControlViewModel.cs).

    L'ho inserito semplicemente nella MainWindows(articoli):

    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:viewModel="clr-namespace:BrunoMvvmLocator.ViewModel"
            xmlns:UserControl="clr-namespace:BrunoMvvmLocator.UserControl" x:Class="BrunoMvvmLocator.MainWindow"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <ResourceDictionary>
                <viewModel:ViewModelLocator x:Key="Locator"  />
            </ResourceDictionary>
        </Window.Resources>
        <Grid DataContext="{Binding MainPage, Source={StaticResource Locator}}">
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,69,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Codice}" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,109,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Descrizione}" VerticalAlignment="Top" Width="120"/>
            <Label Content="Codice" HorizontalAlignment="Left" Margin="30,66,0,0" VerticalAlignment="Top"/>
            <Label Content="Descrizione" HorizontalAlignment="Left" Margin="30,106,0,0" VerticalAlignment="Top"/>
            <Button Content="Salva" HorizontalAlignment="Left" Margin="432,288,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SalvaCommand}"/>
            <Button Content="Button" HorizontalAlignment="Left" Margin="61,272,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
    
            <UserControl:CrudUserControl HorizontalAlignment="Left" Margin="353,170,0,0" VerticalAlignment="Top" Height="47" Width="103"/>
    
        </Grid>
    </Window>

    Io vorrei sfruttare il model(ArticoliModel) della MainWindows nel mio user control, cioè quando cambio qualcosa nella mainwindows(articoli)(cioe scrivo qualcosa nei textbox) appena faccio click su salva(user control) esso deve avere il model(ArticoliModel) aggiornato.

    Non so se adesso è piu chiaro il concetto. 





    • Modificato brux88 mercoledì 29 gennaio 2014 19:57
    mercoledì 29 gennaio 2014 19:55
  • Io mi aspettavo che il CrudUserControl fosse proprio la griglia contenente textbox e bottoni, e che il viewmodel fosse in binding dove "istanzi" lo user control nello xaml. Pressapoco qualcosa di questo tipo:

    <!--User control -->
    <UserControl     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
    <TextBox HorizontalAlignment="Left" Height="23" Margin="116,69,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Codice}"
    x:Name="CrudUserControl"
     VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,109,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Descrizione}" VerticalAlignment="Top" Width="120"/>
            <Label Content="Codice" HorizontalAlignment="Left" Margin="30,66,0,0" VerticalAlignment="Top"/>
            <Label Content="Descrizione" HorizontalAlignment="Left" Margin="30,106,0,0" VerticalAlignment="Top"/>
            <Button Content="Salva" HorizontalAlignment="Left" Margin="432,288,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SalvaCommand}"/>
            <Button Content="Button" HorizontalAlignment="Left" Margin="61,272,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
        </Grid>
    </UserControl>
    
    
    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:viewModel="clr-namespace:BrunoMvvmLocator.ViewModel"
            xmlns:UserControl="clr-namespace:BrunoMvvmLocator.UserControl" x:Class="BrunoMvvmLocator.MainWindow"
            Title="MainWindow" Height="350" Width="525"
    DataSource
    >
    
        <Grid>
            <UserControl:CrudUserControl HorizontalAlignment="Left" Margin="353,170,0,0" VerticalAlignment="Top" Height="47" Width="103"
    DataContext="{Binding MainPage, Source={StaticResource Locator}}"
    />
    
        </Grid>
    </Window>
    
    

    Ovvero, tutta la logica di presenzione nello user control, tutta la logica di comunicazione model<-->view nel viewmodel.

    Io non capisco cosa vuol dire che devi avere il "model" ArticoliModel aggiornato: cosa ci vuoi fare? dove lo devi mettere? perchè se ti serve per salvarlo, crei una nuova istanza e valorizzi i campi dalle property del viewmodel e persisti nel repository; diversamente non mi è chiaro cosa ti serva.

    Gianluca


    Gianluca Carucci
    Software Engineer & Agile Coach
    ugidotnet|web|blog|@rucka

    giovedì 30 gennaio 2014 07:41
  • Si infatti nel senso che il mio usercontrol deve sapere quale model prendere riferimento per poter effettuare il salvatggio nel db, perche nella view ci sono i tetxbox con il model poi ce l usercontrol che deve essere generico perche devo utilizzarlo in altre view.

    Ti allego due immagine per rendere meglio quello che voglio ottenere.

    La view Articoli:

    questa la view per i clienti:

    Ovviamente l'UserControl deve essere uno. Le view avranno model diversi perche propieta diverse.

    questo e il codice xaml della view articoli:

    <Window
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:viewModel="clr-namespace:BrunoMvvmLocator.ViewModel"
            xmlns:UserControl="clr-namespace:BrunoMvvmLocator.UserControl" x:Class="BrunoMvvmLocator.MainWindow"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <ResourceDictionary>
                <viewModel:ViewModelLocator x:Key="Locator"  />
            </ResourceDictionary>
        </Window.Resources>
        <Grid DataContext="{Binding MainPage, Source={StaticResource Locator}}">
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,69,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Codice}" VerticalAlignment="Top" Width="120"/>
            <TextBox HorizontalAlignment="Left" Height="23" Margin="116,109,0,0" TextWrapping="Wrap" Text="{Binding ArticoliModel.Descrizione}" VerticalAlignment="Top" Width="120"/>
            <Label Content="Codice" HorizontalAlignment="Left" Margin="30,66,0,0" VerticalAlignment="Top"/>
            <Label Content="Descrizione" HorizontalAlignment="Left" Margin="30,106,0,0" VerticalAlignment="Top"/>
    
    
            <UserControl:CrudUserControl   HorizontalAlignment="Left" Margin="353,170,0,0" VerticalAlignment="Top" Height="47" Width="103"/>
    
        </Grid>
    </Window>
    
     

    Infine ho messo questo progetto d'esempio per capire come poter arrivare al mio obbiettivo.

    Link:BrunoMvvmLocator

    Spero che adesso lo scenario è un po piu chiaro, perche come dicevi tu e fdifficle (anche per colpa mia) spiegarsi attraverso un forum ;)

    giovedì 30 gennaio 2014 08:19