MVVM jak uložit do db (jak se nechat informovat o změně)   zodpovězená otázka

C#, Databáze

Zdravím.. Mám jednoduchý viewModel, pro čitelnost pouze s jednou proměnnou:

       public  List<VideoData>  VideoData
        {
            get { return _VideoData; }
            set
            {
                if (_VideoData != value)
                {
                    _VideoData = value;
                    NotifyPropertyChanged(" VideoData");
                }
            }
        }
        private  List<VideoData> _VideoData;

třída videoData, má též jednu proměnnou:

public bool IsStored
        {
            get { return _isStored; }
            set
            {
                if (_isStored != value)
                {
                    _isStored= value;
                    NotifyPropertyChanged("IsStored");
                    //NotifyPropertyChanged("DisplayedCount");
                }
            }
        }
        private bool _isStored;

Hloupý příklad: Na IsStored mám namapované checkboxy... Kdy je checkbox false, potřeboval bych celý objekt VideoData, kterému kýžená proměnná IsStored náleží uložit do databáze (a třeba změnit IsStored na true, ale to je jedno)...

Otázka je, jak to udělám, jak se ve svém ViewModelu (v hlavním viewModelu) dozvím, že se změnila jedna vlastnost v Listu...

Je správně to dělat tak, že v každém ViewModelu mám přístup k databázi, popřípadě k nějaké servise, která dělá db dotazy a přehazuje Model do ViewModelu a obráceně???

Jak tedy na to?

Děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pro MVVM se vřele doporučuje implementovat INotifyPropertyChanged a s daty pracovat za pomoci ObservableCollection

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Ano to chápu a samozřejmě to tak mám (jak by se dalo odvodit z toho kousku kódu)...S checkboxy je to spárované a vlastnost se mění.. Ale nevím kde odchytit změnu vlastnosti IsStored a uložit jí do db

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dobrý den,

s tímhle už nějaký týden zápasím a odpověď na tuto otázku bych také chtěl znát.

Nicméně zatím to řeším takto:

Modelová třída, třída co vyzvrací EF u DBFirst, případně vy u CodeFirst :)

public partial class VideoDataModel
    {

        public int Id { get; set; }
        public bool IsStored { get; set; }    

    }

Bázová třída pro ViewModely

    public abstract class ModelViewBase : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

    }

ViewModel objektu:

    public class VideoDataModelView : ModelViewBase 
    {

        //zobrazovaný model
        private readonly Model.VideoDataModel _videoDataModel;

        public VideoDataModelView(Model.VideoDataModel videoDataModel)
        {
            _videoDataModel = videoDataModel;
        }

        public bool IsStored
        {
            get { return _videoDataModel.IsStored; }
            set
            {
                _videoDataModel.IsStored = value;
                NotifyPropertyChanged("IsStored");
                
                //Zde uložení do databáze
                /*
                using (var dc = new EFDataContext())
                {
                    var o = from x in dc.VideoDatas
                            where x.ID == _videoDataModel.ID
                            select x;
                 
                    o.Single().IsStored = value;
                    dc.SaveChanges();
                }
                */

                MessageBox.Show("Uloženo");
                
            }
        }

 
    }

ViewModel kolekce:

    public class VideoDataCollectionModelView : ModelViewBase 
    {

        public ObservableCollection<Model.VideoDataModel> VideoDataModelCollection { get; set; }

        public VideoDataCollectionModelView()
        {
            //načtení nějaké kolekce z DB či jiného zdroje
            //EF -> VideoDataModelCollection = new ObservableCollection<Model.VideoDataModel>(DbContext.VideoDatas);
            //Pro příklad dva nové modely
            VideoDataModelCollection = new ObservableCollection<Model.VideoDataModel>
            {
                new Model.VideoDataModel(),
                new Model.VideoDataModel()
            };
        }

        //Model vybraný z kolekce UI ho binduje sem (ke zdroji)
        Model.VideoDataModel _selectedModel;
        public Model.VideoDataModel SelectedModel
        {
            get { return _selectedModel; }
            set
            {
                if (value == null) return;
                _selectedModel = value;
                SelectedModelChanged();
            }
        }

        public ViewModel.VideoDataModelView SelectedViewModel { get; set; }

        //Zde vytvořím modelview jednoho objektu
        private void SelectedModelChanged()
        {
            SelectedViewModel = new VideoDataModelView(SelectedModel);
            NotifyPropertyChanged("SelectedViewModel");
        }


    }

A konečně UI v XAMLu

    <Window.DataContext>
        <viewModels:VideoDataCollectionModelView />
    </Window.DataContext>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>

        <ListBox ItemsSource="{Binding VideoDataModelCollection}"
                 SelectedItem="{Binding SelectedModel, Mode=OneWayToSource}"/>
        <CheckBox Content="CheckBox"
                  
                  Grid.Column="1" 
                  DataContext="{Binding SelectedViewModel}"
                  IsChecked="{Binding IsStored}" />

    </Grid>
</Window>
nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jo, takže to prostě uložíte v tom view modelu, kde dojde ke změně události (v tomto případě ve vlastnosti IsStored)...

Na tom mi trochu vadí následující: Bude strašně moc datacontextů po celé apliaci(představa je taková, že mám třeba list o 300 položkách a a všechny najednou změním)...To by asi vyřešil kontejner (http://www.dotnetportal.cz/blogy/3/Tomas... --- je to ono?

Tak se to má dělat?

Pak mi na tom ještě vadí to, že se to řeší přímo v tom settru, ale to by se asi pořešilo nějakou servisou a její metodou...

Nicméně ještě otázka:Proč ve ViewModel kolekci používáte třídu z Modelu?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Použití třídy modelu v observable kolekci byla chyba. Měl jsem použít vm objektu.

Přístup k DB kontextu v reálném projektu dělám přes sevice (factory).

Pokud budete k zápisu do db pozivat EF, tak ten není moc pro hromadné operace použitelný.

Alespoň se to zmiňovalo u altaira Valáška na přednášce o ORM viz. Youtube.

Pak se ještě koukněte na ICommand.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pokud řešíte obecný problém jak se v hlavním ViewModelu dozvědět, že se změnila nějaká vlastnost na ViewModelu (nebo modelu) prvku kolekce, tak se to řeší standardně přes událost. Konkrétně tou událostí je PropertyChanged, kterou prvek kolekce stejně již implementuje.

    public class VideoDataViewModel : NotifiableObject<VideoDataViewModel>
    {
        #region member varible and default property initialization
        private bool m_IsStored;
        #endregion

        #region constructors and destructors
        internal VideoDataViewModel(bool isStored)
        {
            this.IsStored = isStored;
        }
        #endregion

        #region property getters/setters
        public bool IsStored
        {
            get { return m_IsStored; }
            set
            {
                if (m_IsStored != value)
                {
                    m_IsStored = value;
                    OnPropertyChanged(o => o.IsStored);
                }
            }
        }
        #endregion
    }

    public class MainViewModel
    {
        #region member varible and default property initialization
        private IList<VideoDataViewModel> m_VideoData;
        #endregion
 
        public IList<VideoDataViewModel> VideoData
        {
            get { return m_VideoData; }
            private set
            {
                if (m_VideoData != value)
                {
                    if (m_VideoData != null)
                    {
                        foreach (var item in m_VideoData)
                        {
                            item.PropertyChanged -= VideoData_PropertyChanged;
                        }
                    }

                    m_VideoData = value;

                    if (m_VideoData != null)
                    {
                        foreach (var item in m_VideoData)
                        {
                            item.PropertyChanged += VideoData_PropertyChanged;
                        }
                    }
                }
            }
        }

        private void VideoData_PropertyChanged(object sender, EventArgs e)
        {
            if (e.PropertyName != "IsStored")
            {
                var item = (VideoDataViewModel)sender;
                //TODO:
            }
        }
    }
nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Přijde mi to těžce neelegantní, ale je to přesně to co jsem potřeboval.Děkuji.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback