Click here to Skip to main content
15,879,239 members
Articles / Desktop Programming / WPF

Model-View-ViewModel in WPF

Rate me:
Please Sign up or sign in to vote.
3.74/5 (15 votes)
21 Dec 2007CPOL5 min read 105.9K   1.8K   42  
An article on creating WPF applications, following the Model-View-ViewModel pattern
  • codeproject.zip
    • CodeProject
      • .bzr
        • branch
          • branch-name
          • format
          • lock
          • revision-history
        • branch-format
        • branch-lock
        • checkout
          • conflicts
          • dirstate
          • format
          • lock
        • README
        • repository
          • format
          • inventory.kndx
          • inventory.knit
          • knits
            • 01
              • assemblyinfo.cs-20071213013430-sngkh9ui5e83ud60-8.kndx
              • assemblyinfo.cs-20071213013430-sngkh9ui5e83ud60-8.knit
              • tasklist.datamodel-20071213014434-wjgek8uvcjo8yp5s-1.kndx
              • tasklist.datamodel-20071213014434-wjgek8uvcjo8yp5s-1.knit
            • 08
              • properties-20071213014434-wjgek8uvcjo8yp5s-3.kndx
              • properties-20071213014434-wjgek8uvcjo8yp5s-3.knit
            • 0a
              • taskcollectiontest.c-20071213180529-6351e013ut030x8d-1.kndx
              • taskcollectiontest.c-20071213180529-6351e013ut030x8d-1.knit
            • 10
              • tasklist.viewmodel-20071213212525-zmxqp3frjbsg0b0z-1.kndx
              • tasklist.viewmodel-20071213212525-zmxqp3frjbsg0b0z-1.knit
            • 15
              • itasklistapplication-20071213212525-zmxqp3frjbsg0b0z-3.kndx
              • itasklistapplication-20071213212525-zmxqp3frjbsg0b0z-3.knit
            • 16
              • resources.designer.c-20071213035543-53ny0xm8ahdeup8a-3.kndx
              • resources.designer.c-20071213035543-53ny0xm8ahdeup8a-3.knit
            • 19
              • assemblyinfo.cs-20071213213342-s7iwkoswpulzwbg4-5.kndx
              • assemblyinfo.cs-20071213213342-s7iwkoswpulzwbg4-5.knit
            • 1b
              • propertychangedwatch-20071213013237-ucb9omrtgj50gglg-10.kndx
              • propertychangedwatch-20071213013237-ucb9omrtgj50gglg-10.knit
            • 27
              • commandsinkattribute-20071214020122-tzvrpu3a2hvv9ioh-1.kndx
              • commandsinkattribute-20071214020122-tzvrpu3a2hvv9ioh-1.knit
              • test.tasklist.viewmo-20071213213342-s7iwkoswpulzwbg4-1.kndx
              • test.tasklist.viewmo-20071213213342-s7iwkoswpulzwbg4-1.knit
            • 2a
              • test.tasklist.viewmo-20071213213342-s7iwkoswpulzwbg4-4.kndx
              • test.tasklist.viewmo-20071213213342-s7iwkoswpulzwbg4-4.knit
            • 2c
              • tasklistviewmodel.cs-20071213213222-558xu0jc4awt8fgg-1.kndx
              • tasklistviewmodel.cs-20071213213222-558xu0jc4awt8fgg-1.knit
            • 32
              • selection.cs-20071215202735-qp5k90odcm8iomjv-1.kndx
              • selection.cs-20071215202735-qp5k90odcm8iomjv-1.knit
            • 38
              • testdataerrorinfo.cs-20071213023410-3b817j85lvxslkns-1.kndx
              • testdataerrorinfo.cs-20071213023410-3b817j85lvxslkns-1.knit
            • 3a
              • tasklistcommands.cs-20071215160037-lz7a3je7txcjyri5-1.kndx
              • tasklistcommands.cs-20071215160037-lz7a3je7txcjyri5-1.knit
            • 3c
              • edittaskpage.xaml-20071215212433-9gnk5rr3mjw0gjrf-1.kndx
              • edittaskpage.xaml-20071215212433-9gnk5rr3mjw0gjrf-1.knit
              • properties-20071213013430-sngkh9ui5e83ud60-6.kndx
              • properties-20071213013430-sngkh9ui5e83ud60-6.knit
            • 3f
              • taskcollection.cs-20071213181230-6z9ws0p8k1vkjzuc-1.kndx
              • taskcollection.cs-20071213181230-6z9ws0p8k1vkjzuc-1.knit
            • 40
              • mainwindowviewmodelt-20071213213449-ns60l2kj4h237pzg-1.kndx
              • mainwindowviewmodelt-20071213213449-ns60l2kj4h237pzg-1.knit
            • 41
              • edittaskpage.xaml.cs-20071215212433-9gnk5rr3mjw0gjrf-2.kndx
              • edittaskpage.xaml.cs-20071215212433-9gnk5rr3mjw0gjrf-2.knit
            • 45
              • globalsuppressions.c-20071217043309-o86x25nntk0bk6lo-1.kndx
              • globalsuppressions.c-20071217043309-o86x25nntk0bk6lo-1.knit
            • 4c
              • globalsuppressions.c-20071213211235-souqg3uilzehioee-1.kndx
              • globalsuppressions.c-20071213211235-souqg3uilzehioee-1.knit
            • 4e
              • localtestrun.testrun-20071213013430-sngkh9ui5e83ud60-2.kndx
              • localtestrun.testrun-20071213013430-sngkh9ui5e83ud60-2.knit
            • 4f
              • precondition.cs-20071213022255-ecv7q7up7nar12vq-1.kndx
              • precondition.cs-20071213022255-ecv7q7up7nar12vq-1.knit
            • 51
              • codeproject.snk-20071213021143-3x1ioaofarxdc7k2-2.kndx
              • codeproject.snk-20071213021143-3x1ioaofarxdc7k2-2.knit
            • 54
              • properties-20071213213342-s7iwkoswpulzwbg4-3.kndx
              • properties-20071213213342-s7iwkoswpulzwbg4-3.knit
            • 57
              • tasktest.cs-20071213013555-48d7c3agymuoj2i0-1.kndx
              • tasktest.cs-20071213013555-48d7c3agymuoj2i0-1.knit
            • 58
              • assemblyinfo.cs-20071213021143-3x1ioaofarxdc7k2-5.kndx
              • assemblyinfo.cs-20071213021143-3x1ioaofarxdc7k2-5.knit
            • 5e
              • iedittaskpageview.cs-20071217021058-4xiyah3s4mh60qow-1.kndx
              • iedittaskpageview.cs-20071217021058-4xiyah3s4mh60qow-1.knit
            • 61
              • assemblyinfo.cs-20071213022943-ws0x3cedbvac5k3p-5.kndx
              • assemblyinfo.cs-20071213022943-ws0x3cedbvac5k3p-5.knit
            • 67
              • codeprojectcore.cspr-20071213021143-3x1ioaofarxdc7k2-3.kndx
              • codeprojectcore.cspr-20071213021143-3x1ioaofarxdc7k2-3.knit
            • 6d
              • tasklistpageviewmode-20071215194732-4g7n1tutd5u4iig0-4.kndx
              • tasklistpageviewmode-20071215194732-4g7n1tutd5u4iig0-4.knit
            • 71
              • codeproject.sln-20071213013011-q70xfq7n7ogllazi-1.kndx
              • codeproject.sln-20071213013011-q70xfq7n7ogllazi-1.knit
            • 76
              • test.codeprojectcore-20071213022943-ws0x3cedbvac5k3p-1.kndx
              • test.codeprojectcore-20071213022943-ws0x3cedbvac5k3p-1.knit
            • 79
              • test.codeprojectcore-20071213022943-ws0x3cedbvac5k3p-4.kndx
              • test.codeprojectcore-20071213022943-ws0x3cedbvac5k3p-4.knit
            • 7f
              • authoringtests.txt-20071213013430-sngkh9ui5e83ud60-4.kndx
              • authoringtests.txt-20071213013430-sngkh9ui5e83ud60-4.knit
              • codeprojectcore-20071213021143-3x1ioaofarxdc7k2-1.kndx
              • codeprojectcore-20071213021143-3x1ioaofarxdc7k2-1.knit
            • 86
              • resources.resx-20071213013237-ucb9omrtgj50gglg-16.kndx
              • resources.resx-20071213013237-ucb9omrtgj50gglg-16.knit
            • 8a
              • bzrignore-20071213012954-kvrppfyxdd192lwi-1.kndx
              • bzrignore-20071213012954-kvrppfyxdd192lwi-1.knit
            • 8d
              • resources.resx-20071213211717-wf3kh2bgsnduzgg4-12.kndx
              • resources.resx-20071213211717-wf3kh2bgsnduzgg4-12.knit
            • 90
              • viewmodel.cs-20071214020122-tzvrpu3a2hvv9ioh-2.kndx
              • viewmodel.cs-20071214020122-tzvrpu3a2hvv9ioh-2.knit
            • 93
              • codeproject.snk-20071213013237-ucb9omrtgj50gglg-3.kndx
              • codeproject.snk-20071213013237-ucb9omrtgj50gglg-3.knit
            • 94
              • properties-20071213021143-3x1ioaofarxdc7k2-4.kndx
              • properties-20071213021143-3x1ioaofarxdc7k2-4.knit
            • 95
              • tasklist.datamodel.c-20071213014434-wjgek8uvcjo8yp5s-4.kndx
              • tasklist.datamodel.c-20071213014434-wjgek8uvcjo8yp5s-4.knit
            • 97
              • stringlengthvalidato-20071213035543-53ny0xm8ahdeup8a-2.kndx
              • stringlengthvalidato-20071213035543-53ny0xm8ahdeup8a-2.knit
            • 98
              • authoringtests.txt-20071213213342-s7iwkoswpulzwbg4-2.kndx
              • authoringtests.txt-20071213213342-s7iwkoswpulzwbg4-2.knit
            • 9c
              • properties-20071213022943-ws0x3cedbvac5k3p-3.kndx
              • properties-20071213022943-ws0x3cedbvac5k3p-3.knit
            • 9f
              • codeproject.snk-20071213211717-wf3kh2bgsnduzgg4-4.kndx
              • codeproject.snk-20071213211717-wf3kh2bgsnduzgg4-4.knit
            • a5
              • resources.designer.c-20071213013237-ucb9omrtgj50gglg-15.kndx
              • resources.designer.c-20071213013237-ucb9omrtgj50gglg-15.knit
              • tasklist.viewmodel.c-20071213212525-zmxqp3frjbsg0b0z-5.kndx
              • tasklist.viewmodel.c-20071213212525-zmxqp3frjbsg0b0z-5.knit
            • a6
              • tasklisttestapplicat-20071213214943-dyyzzbvhjnv2ggob-1.kndx
              • tasklisttestapplicat-20071213214943-dyyzzbvhjnv2ggob-1.knit
            • ac
              • resources.designer.c-20071213211717-wf3kh2bgsnduzgg4-11.kndx
              • resources.designer.c-20071213211717-wf3kh2bgsnduzgg4-11.knit
            • ae
              • specify.cs-20071213013237-ucb9omrtgj50gglg-12.kndx
              • specify.cs-20071213013237-ucb9omrtgj50gglg-12.knit
            • af
              • imainwindowview.cs-20071214025649-nyfq33grd351tyuj-1.kndx
              • imainwindowview.cs-20071214025649-nyfq33grd351tyuj-1.knit
            • b1
              • mainwindow.xaml-20071213211717-wf3kh2bgsnduzgg4-5.kndx
              • mainwindow.xaml-20071213211717-wf3kh2bgsnduzgg4-5.knit
            • b2
              • app.xaml-20071213211717-wf3kh2bgsnduzgg4-2.kndx
              • app.xaml-20071213211717-wf3kh2bgsnduzgg4-2.knit
            • b3
              • tasklist.csproj.user-20071213211717-wf3kh2bgsnduzgg4-9.kndx
              • tasklist.csproj.user-20071213211717-wf3kh2bgsnduzgg4-9.knit
            • b4
              • codeproject.snk-20071213212525-zmxqp3frjbsg0b0z-2.kndx
              • codeproject.snk-20071213212525-zmxqp3frjbsg0b0z-2.knit
              • frameworkmessages.cs-20071213013237-ucb9omrtgj50gglg-6.kndx
              • frameworkmessages.cs-20071213013237-ucb9omrtgj50gglg-6.knit
            • b6
              • mainwindow.xaml.cs-20071213211717-wf3kh2bgsnduzgg4-6.kndx
              • mainwindow.xaml.cs-20071213211717-wf3kh2bgsnduzgg4-6.knit
            • b7
              • app.xaml.cs-20071213211717-wf3kh2bgsnduzgg4-3.kndx
              • app.xaml.cs-20071213211717-wf3kh2bgsnduzgg4-3.knit
              • settings.designer.cs-20071213211717-wf3kh2bgsnduzgg4-13.kndx
              • settings.designer.cs-20071213211717-wf3kh2bgsnduzgg4-13.knit
            • bc
              • assemblyinfo.cs-20071213212525-zmxqp3frjbsg0b0z-6.kndx
              • assemblyinfo.cs-20071213212525-zmxqp3frjbsg0b0z-6.knit
            • bd
              • app.config-20071215154029-mlxydmaa3bclnaag-1.kndx
              • app.config-20071215154029-mlxydmaa3bclnaag-1.knit
            • be
              • edittaskpageviewmode-20071215212433-9gnk5rr3mjw0gjrf-3.kndx
              • edittaskpageviewmode-20071215212433-9gnk5rr3mjw0gjrf-3.knit
            • c0
              • codeproject.visualst-20071213013237-ucb9omrtgj50gglg-1.kndx
              • codeproject.visualst-20071213013237-ucb9omrtgj50gglg-1.knit
            • c1
              • codeproject.visualst-20071213013237-ucb9omrtgj50gglg-2.kndx
              • codeproject.visualst-20071213013237-ucb9omrtgj50gglg-2.knit
            • c2
              • tasklistpageviewmode-20071215200239-p788d71fwwxauwrm-1.kndx
              • tasklistpageviewmode-20071215200239-p788d71fwwxauwrm-1.knit
            • c5
              • commandtester.cs-20071214020412-lzl7v3k2q5et9xoj-1.kndx
              • commandtester.cs-20071214020412-lzl7v3k2q5et9xoj-1.knit
              • specificationvalue.c-20071213013237-ucb9omrtgj50gglg-11.kndx
              • specificationvalue.c-20071213013237-ucb9omrtgj50gglg-11.knit
              • tasklist.csproj-20071213211717-wf3kh2bgsnduzgg4-8.kndx
              • tasklist.csproj-20071213211717-wf3kh2bgsnduzgg4-8.knit
            • c6
              • codeproject.snk-20071213014434-wjgek8uvcjo8yp5s-2.kndx
              • codeproject.snk-20071213014434-wjgek8uvcjo8yp5s-2.knit
            • c9
              • assemblyinfo.cs-20071213013237-ucb9omrtgj50gglg-14.kndx
              • assemblyinfo.cs-20071213013237-ucb9omrtgj50gglg-14.knit
            • ca
              • collectionchangedwat-20071213013237-ucb9omrtgj50gglg-4.kndx
              • collectionchangedwat-20071213013237-ucb9omrtgj50gglg-4.knit
            • cb
              • collectionchangedwat-20071213013237-ucb9omrtgj50gglg-5.kndx
              • collectionchangedwat-20071213013237-ucb9omrtgj50gglg-5.knit
            • cc
              • testextensions.cs-20071213013237-ucb9omrtgj50gglg-13.kndx
              • testextensions.cs-20071213013237-ucb9omrtgj50gglg-13.knit
            • cd
              • assemblyinfo.cs-20071213014434-wjgek8uvcjo8yp5s-5.kndx
              • assemblyinfo.cs-20071213014434-wjgek8uvcjo8yp5s-5.knit
              • codeproject.vsmdi-20071213013430-sngkh9ui5e83ud60-1.kndx
              • codeproject.vsmdi-20071213013430-sngkh9ui5e83ud60-1.knit
            • d0
              • assemblyinfo.cs-20071213211717-wf3kh2bgsnduzgg4-10.kndx
              • assemblyinfo.cs-20071213211717-wf3kh2bgsnduzgg4-10.knit
            • d2
              • mainwindowviewmodel.-20071214021535-pfu4qerfstp78gcd-1.kndx
              • mainwindowviewmodel.-20071214021535-pfu4qerfstp78gcd-1.knit
            • d4
              • manualtest1.mht-20071213013430-sngkh9ui5e83ud60-5.kndx
              • manualtest1.mht-20071213013430-sngkh9ui5e83ud60-5.knit
              • settings.settings-20071213211717-wf3kh2bgsnduzgg4-14.kndx
              • settings.settings-20071213211717-wf3kh2bgsnduzgg4-14.knit
            • d6
              • task.cs-20071213014820-kfzciheohayefljq-1.kndx
              • task.cs-20071213014820-kfzciheohayefljq-1.knit
            • d9
              • properties-20071213013237-ucb9omrtgj50gglg-8.kndx
              • properties-20071213013237-ucb9omrtgj50gglg-8.knit
            • de
              • itasklistpageview.cs-20071215201802-5gm7npkr8rynfbpn-1.kndx
              • itasklistpageview.cs-20071215201802-5gm7npkr8rynfbpn-1.knit
            • e0
              • authoringtests.txt-20071213022943-ws0x3cedbvac5k3p-2.kndx
              • authoringtests.txt-20071213022943-ws0x3cedbvac5k3p-2.knit
            • e3
              • dataerrorinfo.cs-20071213023841-9p8uxe73oezcfbdz-1.kndx
              • dataerrorinfo.cs-20071213023841-9p8uxe73oezcfbdz-1.knit
              • properties-20071213211717-wf3kh2bgsnduzgg4-7.kndx
              • properties-20071213211717-wf3kh2bgsnduzgg4-7.knit
            • ea
              • tasklistpage.xaml-20071215194732-4g7n1tutd5u4iig0-1.kndx
              • tasklistpage.xaml-20071215194732-4g7n1tutd5u4iig0-1.knit
            • ed
              • test.tasklist.datamo-20071213013430-sngkh9ui5e83ud60-3.kndx
              • test.tasklist.datamo-20071213013430-sngkh9ui5e83ud60-3.knit
            • ef
              • tasklistpage.xaml.cs-20071215194732-4g7n1tutd5u4iig0-2.kndx
              • tasklistpage.xaml.cs-20071215194732-4g7n1tutd5u4iig0-2.knit
            • f1
              • test.tasklist.datamo-20071213013430-sngkh9ui5e83ud60-7.kndx
              • test.tasklist.datamo-20071213013430-sngkh9ui5e83ud60-7.knit
            • f3
              • propertychangedwatch-20071213013237-ucb9omrtgj50gglg-9.kndx
              • propertychangedwatch-20071213013237-ucb9omrtgj50gglg-9.knit
            • f4
              • objectextensions.cs-20071213035543-53ny0xm8ahdeup8a-1.kndx
              • objectextensions.cs-20071213035543-53ny0xm8ahdeup8a-1.knit
            • f5
              • numerics.cs-20071213013237-ucb9omrtgj50gglg-7.kndx
              • numerics.cs-20071213013237-ucb9omrtgj50gglg-7.knit
            • f7
              • properties-20071213212525-zmxqp3frjbsg0b0z-4.kndx
              • properties-20071213212525-zmxqp3frjbsg0b0z-4.knit
              • resources.resx-20071213035543-53ny0xm8ahdeup8a-4.kndx
              • resources.resx-20071213035543-53ny0xm8ahdeup8a-4.knit
            • f9
              • validatorattribute.c-20071213025856-7hxu8ce3k2040pyr-1.kndx
              • validatorattribute.c-20071213025856-7hxu8ce3k2040pyr-1.knit
            • fe
              • titleconverter.cs-20071215194732-4g7n1tutd5u4iig0-3.kndx
              • titleconverter.cs-20071215194732-4g7n1tutd5u4iig0-3.knit
            • ff
              • tasklist-20071213211717-wf3kh2bgsnduzgg4-1.kndx
              • tasklist-20071213211717-wf3kh2bgsnduzgg4-1.knit
          • lock
          • revisions.kndx
          • revisions.knit
          • revision-store
          • signatures.kndx
          • signatures.knit
      • .bzrignore
      • CodeProject.sln
      • CodeProject.VisualStudio.QualityTools.UnitTestFramework
      • CodeProject.vsmdi
      • CodeProjectCore
      • LocalTestRun.testrunconfig
      • TaskList.DataModel
      • TaskList.ViewModel
      • TaskList
      • Test.CodeProjectCore
      • Test.TaskList.DataModel
      • Test.TaskList.ViewModel
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Permissions;

namespace TaskList.DataModel
{
    [Serializable]
    public sealed class TaskCollection : ObservableCollection<Task>, ISerializable
    {
        [NonSerialized]
        private bool isDirty;

        public TaskCollection()
        {
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1805:DoNotInitializeUnnecessarily")]
        private TaskCollection(SerializationInfo info, StreamingContext context)
        {
            int count = info.GetInt32("Count");
            for (int i = 0; i < count; ++i)
            {
                Task task = (Task)info.GetValue(string.Format(CultureInfo.InvariantCulture, "Item{0}", i), typeof(Task));
                Add(task);
            }
            isDirty = false;
        }

        public bool IsDirty
        {
            get { return isDirty; }
            set
            {
                if (isDirty != value)
                {
                    isDirty = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("IsDirty"));
                }
            }
        }

        public static TaskCollection Load(string fileName)
        {
            using (FileStream stream = new FileStream(fileName, FileMode.Open))
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                return binaryFormatter.Deserialize(stream) as TaskCollection;
            }
        }

        public void Save(string fileName)
        {
            using (FileStream stream = new FileStream(fileName, FileMode.Create))
            {
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(stream, this);
            }
        }

        protected override void InsertItem(int index, Task item)
        {
            base.InsertItem(index, item);
            AddChangeListener(item);
            IsDirty = true;
        }

        protected override void RemoveItem(int index)
        {
            Task item = this[index];
            base.RemoveItem(index);
            RemoveChangeListener(item);
            IsDirty = true;
        }

        protected override void ClearItems()
        {
            if (Count > 0)
            {
                foreach (Task item in this)
                    RemoveChangeListener(item);
                base.ClearItems();
                IsDirty = true;
            }
        }

        protected override void SetItem(int index, Task item)
        {
            if (this[index] != item)
            {
                RemoveChangeListener(this[index]);
                base.SetItem(index, item);
                AddChangeListener(item);
                IsDirty = true;
            }
        }

        protected override void MoveItem(int oldIndex, int newIndex)
        {
            base.MoveItem(oldIndex, newIndex);
            IsDirty = true;
        }

        private void AddChangeListener(Task item)
        {
            if (item != null)
                item.PropertyChanged += item_PropertyChanged;
        }

        private void RemoveChangeListener(Task item)
        {
            if (item != null)
                item.PropertyChanged -= item_PropertyChanged;
        }

        private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            IsDirty = true;
        }

        #region ISerializable Members

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Count", Count);
            for (int i = 0; i < Count; ++i)
            {
                info.AddValue(string.Format(CultureInfo.InvariantCulture, "Item{0}", i), this[i]);
            }
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Windows developer with 10+ years experience working in the banking industry.

Comments and Discussions