[ wex-alpha @ 07.01.2013. 22:46 ] @
Treba mi *.sln projekat koji implementira MVVM. Nista pretjerano kompleksno, nego nesto za MVVM pocetnika.

Idelano bi bilo kada bi projekat bio dobro dokumentiran, zasto MVVM bas ovdje i slicno.

Da li mnogo trazim? :)


Hvala
[ Dusan Kondic @ 08.01.2013. 08:31 ] @
Za dobro dokumentovan projekat je potrebno mnogo vremena. Evo hronologije izrade jednog primera a sam primer možeš skinuti sa https://skydrive.live.com/redir?resid=CEAE48DB2CB34B53!446 pošto ne mogu da nađem dugme "Upload uz poruku".

- kreiraj SQL bazu MVVMExamDB
- kreiraj SQL tabelu VrstePoreza sa poljima Id INT IDENTITY(1,1), Sifra VARCHAR(10), Naziv NVARCHAR(50) i Vrednost DECIMAL(18,2)
- kreiraj WPF projekat
- u WPF projektu kreiraj direktorijume ViewModels, Views i Services (ovo nije obavezno ali je jako korisno zbog bolje organizacije fajlova)
- projektu dodaj ADO.NET EntityDataModel MVVMExamEF (Generate from database > New Connection > izaberi naziv servera > izaberi bazu MVVMExamEF > OK > Next > izaberi tabelu VrstePoreza > Finish)
- u direktorijumu Services kreiraj WCF servis MojWCFServis
- u interfejsu IMojWCFServis izbriši red sa "DoWork" i pripadajućim atributom [OperationContract] pa nabroj metode
List<VrstePoreza> VrstePorezaSelect,
void VrstePorezaInsert(string sifra, string naziv, decimal vrednost);,
void VrstePorezaUpdate(Int32 id, string sifra, string naziv, decimal vrednost); i
void VrstePorezaDelete(Int32 id);
sa atributom [OperationContract]
- u servisu MojWCFServis izbriši "DoWork" metodu pa implementiraj metode iz nasleđenog
interfejsa (desni klik na : IMojWCFServis > Implement Interface)
Code:

        public List<VrstePoreza> VrstePorezaSelect()
        {
            MVVMExamDBEntities ent = new MVVMExamDBEntities();
            var res = from rows in ent.VrstePorezas select rows;
            return new List<VrstePoreza>(res);
        }

        public void VrstePorezaInsert(string sifra, string naziv, decimal vrednost)
        {
            MVVMExamDBEntities ent = new MVVMExamDBEntities();
            VrstePoreza vp = new VrstePoreza() { Sifra = sifra, Naziv = naziv, Vrednost = vrednost };
            ent.VrstePorezas.AddObject(vp);
            ent.SaveChanges();
        }

        public void VrstePorezaUpdate(int id, string sifra, string naziv, decimal vrednost)
        {
            MVVMExamDBEntities ent = new MVVMExamDBEntities();
            VrstePoreza vp = ent.VrstePorezas.Single(e => e.Id == id);
            vp.Sifra = sifra;
            vp.Naziv = naziv;
            vp.Vrednost = vrednost;
            ent.SaveChanges();
        }

        public void VrstePorezaDelete(int id)
        {
            MVVMExamDBEntities ent = new MVVMExamDBEntities();
            VrstePoreza vp = ent.VrstePorezas.Single(e => e.Id == id);
            ent.VrstePorezas.DeleteObject(vp);
            ent.SaveChanges();
        }

- u direktorijumu ViewModels kreiraj klasu VrstePorezaViewModel
- kreiranoj klasi dodaj "public", nasledi od INotifyPropertyChanged, dodaj using System.ComponentModel
(Ctrl+. pa Enter), implementiraj nasleđeni interfejs
Code:

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

- kreiraj klasu RelayCommand i zameni kreiranu klasu narednim kodom
Code:

    public class RelayCommand : ICommand
    {
        #region Fields

        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;

        #endregion // Fields

        #region Constructors

        public RelayCommand(Action<object> execute)
            : this(execute, null)
        {
        }

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }
        #endregion // Constructors

        #region ICommand Members

        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        #endregion // ICommand Members
    }

- dodaj using System.Windows.Input; i using System.Diagnostics;
- radi preglednosti u klasi VrstePorezaViewModel implementirani kod od INotifyPropertyChanged stavi
u region INPC i dodaj regione Constructors, Members, Properties i Commands
- u regionu Members dodaj private članove
Code:

        List<VrstePoreza> vrstePoreza;
        VrstePoreza vrstePorezaSelected;
        string sifra;
        string naziv;
        decimal vrednost;
        MojWCFServis mojServis;

- nazivi neka započnu malim slovima
- za sve ove private članove osim servisa mojServis kreiraj Properties-e (klik na naziv određenog člana, zatim Ctrl+R E Enter Enter)
- premesti properties-e u region Properties i u svaki set dodaj
RaisePropertyChanged("NazivTekućegProperties-a");
- u set delu VrstePorezaSelected property-ja dodaj kod tako da izgleda
Code:

        public VrstePoreza VrstePorezaSelected
        {
            get { return vrstePorezaSelected; }
            set
            {
                vrstePorezaSelected = value;
                if (value == null)
                {
                    Sifra = "";
                    Naziv = "";
                    Vrednost = 0;
                }
                else
                {
                    Sifra = value.Sifra;
                    Naziv = value.Naziv;
                    Vrednost = value.Vrednost;
                }
                RaisePropertyChanged("VrstePorezaSelected");
            }
        }

- u regionu Constructors kreiraj konstruktor (otkucaj "ctor" pa Tab Tab)
- u regionu Commands dodaj metodu
Code:

        private void VrstePorezaSelect()
        {
            VrstePoreza = mojServis.VrstePorezaSelect();
        }

i istu pozovi iz konstruktora
- u konstruktoru instanciraj mojServis
Code:
mojServis = new MojWCFServis();

- u regionu Commands dodaj komande
Code:

        public ICommand Insert { get { return new RelayCommand(insert, canInsert); } }
        private void insert(object par)
        {
            mojServis.VrstePorezaInsert(Sifra, Naziv, Vrednost);
            VrstePorezaSelect();
        }
        private bool canInsert(object par)
        {
            return (VrstePorezaSelected == null && !(string.IsNullOrEmpty(Sifra) || string.IsNullOrEmpty(Naziv)));
        }

        public ICommand Update { get { return new RelayCommand(update, canUpdate); } }
        private void update(object par)
        {
            mojServis.VrstePorezaUpdate(VrstePorezaSelected.Id, Sifra, Naziv, Vrednost);
            VrstePorezaSelect();
        }
        private bool canUpdate(object par)
        {
            return (VrstePorezaSelected != null && !(string.IsNullOrEmpty(Sifra) || string.IsNullOrEmpty(Naziv)));
        }

        public ICommand Delete { get { return new RelayCommand(delete, canDelete); } }
        private void delete(object par)
        {
            mojServis.VrstePorezaDelete(VrstePorezaSelected.Id);
            VrstePorezaSelect();
        }
        private bool canDelete(object par)
        {
            return VrstePorezaSelected != null;
        }

        public ICommand Reset { get { return new RelayCommand(reset, canReset); } }
        private void reset(object par)
        {
            VrstePorezaSelected = null;
        }
        private bool canReset(object par)
        {
            return true;
        }

- u direktorijumu Views kreiraj Window VrstePorezaView
Code:

<Window x:Class="MVVMExample.Views.VrstePorezaView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="VrstePorezaView" Height="300" Width="300">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBlock Text="Šifra" />
            <TextBox Name="txtSifra" Grid.Column="1" Text="{Binding Sifra}" />
            <TextBlock Text="Naziv" Grid.Row="1" />
            <TextBox Name="txtNaziv" Grid.Row="1" Grid.Column="1" Text="{Binding Naziv}" />
            <TextBlock Text="Vrednost" Grid.Row="2" />
            <TextBox Name="txtVrednost" Grid.Row="2" Grid.Column="1" Text="{Binding Vrednost}" TextAlignment="Right" />
            <Button Name="btnInsert" Grid.Row="3" Grid.ColumnSpan="2" Command="{Binding Insert}" Content="Insert" />
            <Button Name="btnUpdate" Grid.Row="4" Grid.ColumnSpan="2" Command="{Binding Update}" Content="Update" />
            <Button Name="btnDelete" Grid.Row="5" Grid.ColumnSpan="2" Command="{Binding Delete}" Content="Delete" />
            <Button Name="btnReset" Grid.Row="6" Grid.ColumnSpan="2" Command="{Binding Reset}" Content="Reset" />
        </Grid>
        <DataGrid Name="dgVrstePoreza" Grid.Column="1" 
                  ItemsSource="{Binding VrstePoreza}" SelectedItem="{Binding Path=VrstePorezaSelected, Mode=TwoWay}" />
    </Grid>
</Window>

- u konstruktoru kreiranog View-a dodati
Code:

            this.Loaded += (s, e) => { this.DataContext = new VrstePorezaViewModel(); };

(dodati using MVVMExample.ViewModels;)
- u MainWindow-u dodati button kojim ćemo da pozovemo kreirani prozor

Za sva pitanja ...
Pozdrav
[ mmix @ 08.01.2013. 08:35 ] @
Ima dobar tutorial kao plugin za vs, s u njemu gomila solutiona sa konkretnim primerima, mislim da ti j e to mnogo bolje, sad cu da probam da ti nadjem to.
[ mmix @ 08.01.2013. 09:01 ] @
Evo ga:

http://karlshifflett.wordpress...n-the-box-ndash-mvvm-training/

http://visualstudiogallery.msd...2f-0c54-453c-b437-8e8d57eb9942

[ wex-alpha @ 09.01.2013. 09:37 ] @
Hvala na odgovorima :)

Sad imam materijala.
[ del-boy @ 11.01.2013. 06:39 ] @
Ono što je meni pomoglo da pohvatam neke stvari (više sa WPF-om nego sa MVVM-om, ali i za MVVM je korisno) je ovaj članak i prateći kod: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
[ ssi @ 06.03.2013. 09:47 ] @
Postoji i dobar framework za MVVM, Caliburn Micro.

http://caliburnmicro.codeplex.com/

tu imas i dokumentaciju i primere.