1

I am just starting out with WPF and MVVM. I know this question was probably asked a lot on SO but I have read everything I could find on MVVM and EF, tried every example and tutorial out there, read "How to survive MVVM for Enterprise" but I still cannot understand how to properly use the pattern and the framework for a simple bind to a textbox. Can someone please help me with an easy to understand example?

I have created a model using EF Designer. Inside my Model folder, the LocationModel.Context looks like this:

MODEL:

namespace Location.Model
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class DailyEntities : DbContext
    {
        public DailyEntities()
            : base("name=DailyEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<LocationKPI> LocationKPI { get; set; }

    }
}

LocationKPI.cs

namespace Location.Model
{
    using System;
    using System.Collections.Generic;

    public partial class LocationKPI
    {
        public long sMonth { get; set; }
        public Nullable<decimal> Efficiency { get; set; }
    }
}

I've created a ViewModel folder with a class that implements INotifyPropertyChanged:

VIEWMODEL:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Location.ViewModel
{
    public class LocationViewModel: INotifyPropertyChanged
    {

        public decimal Efficiency
        {
            get { return _Efficienecy; }
            set
            {
                _Efficiency = value;
                OnPropertyChanged("Efficiency");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

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

XAML:

<Window x:Class="Location.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Location"
        xmlns:vm="clr-namespace:Location.ViewModel"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <DatePicker HorizontalAlignment="Left" Margin="392,17,0,0" VerticalAlignment="Top"/>
        <TextBlock Text="Efficiency"></TextBlock>
        <TextBox Text="{Binding Efficiency}" ></TextBox>

    </Grid>
</Window>

I am really losing my mind here. I am looking for some guidance on how to "glue" the model and the viewmodel to my view and I just need a simple example to understand. I am sorry if the question is too broad.

Is the query supposed to be written in the model or the viewmodel? How do I define the data context and write a simple select Efficiency where sMonth = 9 statement using linq? How do add the month from the datepicker as a parameter to the above query? I would be so grateful for any kind of help. Thank you.

2
  • 1
    You don't write any queries on your model or viewmodel, you would have a service layer that will do that, that could be whatever pattern you want to adopt on your application like Repository pattern or CQRS. Commented Sep 28, 2017 at 18:01
  • Thanks for pointing that out CQRS. Can you please show me an example? It's the only way I can make sense of things. Commented Sep 28, 2017 at 18:35

1 Answer 1

2

I am going to address your MVVM issue and leave the data source for another discussion. I am going to try to give you some good habits along with showing you how to wire together you MVVM environment.

Let's start with the INotifyPropertyChanged interface and how to implement it. Generally speaking I try to create an abstract classes that both the Model and ViewModel utilize that contains everything that is common among all my models and viewmodels. Here are those Abstract Classes:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfStackOverflow.Models
{
/// <summary>
/// Abstract class that provides common functionality accross all View Models.
/// </summary>
public abstract class modelBase : INotifyPropertyChanged
{

    #region INotifyPropertyChanged
    /// <summary>
    /// Provides a simplefied INotifyPropertyChanged interface.
    /// requires System.Runtime.CompilerServices and
    /// System.ComponentModel.
    /// </summary>
    /// <param name="property"></param>
    public void SetPropertyChanged([CallerMemberName] string property = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
#endregion
}

namespace WpfStackOverflow.ViewModels
{
    /// <summary>
    /// Abstract class that provides common functionality accross all View     Models.
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged
    {

        #region INotifyPropertyChanged
        /// <summary>
        /// Provides a simplefied INotifyPropertyChanged interface.
        /// requires System.Runtime.CompilerServices and
        /// System.ComponentModel.
        /// </summary>
        /// <param name="property"></param>
        public void SetPropertyChanged([CallerMemberName] string property = null)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }

        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
}

each class resides in a Models and ViewModels folder respectfully. Here is the View Model I created:

namespace WpfStackOverflow.ViewModels
{
    class BasicMVVMViewModel:ViewModelBase
    {

        private ObservableCollectionEx<LocationKPI> _locations;

        public BasicMVVMViewModel()
        {
            CreateTestData();
        }

        private DateTime _selectedDate;
        public DateTime SelectedDate
        {

            get { return _selectedDate; }
            set
            {
                _selectedDate = value;
                SetPropertyChanged();
                SetSelectedLocationKPI( _selectedDate.Month);
            }
        }

        private LocationKPI _selectedLocationKPI;
        public LocationKPI SelectedLocationKPI
        {
            get { return _selectedLocationKPI; }
            set
            {
                _selectedLocationKPI = value;
                SetPropertyChanged();
            }
        }

        private void  SetSelectedLocationKPI(long sMonth)
        {
            SelectedLocationKPI = _locations.Where(p => p.SMonth.Equals(sMonth)).FirstOrDefault();
        }


        private void CreateTestData()
        {

            _locations = new ObservableCollectionEx<LocationKPI>();
            for(int i=0; i < 12;i++)
            {
                _locations.Add(new LocationKPI() { SMonth = i, Efficiency = i*17 });
            }

        }

    }
}

Finally here is the XAML Markup:

<UserControl x:Class="WpfStackOverflow.Controls.BasicMVVM"
             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:local="clr-namespace:WpfStackOverflow.Controls"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="35"/>
            <RowDefinition Height="35"/>
            <RowDefinition Height="35"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <DatePicker HorizontalAlignment="Left" Margin="30,5,0,0"   Grid.Row="1" VerticalAlignment="Top" Width="150" SelectedDate="{Binding SelectedDate}"/>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Stretch"  Grid.Row="2" TextWrapping="Wrap" 
               Text="{Binding SelectedLocationKPI.Efficiency,Mode=TwoWay}" VerticalAlignment="Stretch" Margin="5"/>

    </Grid>
</UserControl>

In the Viewmodel I call a method that creates the test data. In your case you can get your data from a linq query. (you figure it out :))

You will have to adjust some references and namespaves to fit your environment. What I posted here is tested and works. I hope it helps you understand MVVM better. Oh yeah, one more thing, the XAML you see here is from a UserControl not a XAML Window. In the codebehind you have to instantiate the ViewModel and set it as the DataContext:

namespace WpfStackOverflow.Controls
{
    /// <summary>
    /// Interaction logic for BasicMVVM.xaml
    /// </summary>
    public partial class BasicMVVM : UserControl
    {
        public BasicMVVM()
        {
           InitializeComponent();
           DataContext = new BasicMVVMViewModel();
        }
    }
}

Good Luck with this. StackOverflow is mostly used to solve actual coding issues. This case is actually a coding lesson. Try to avoid using StackOverflow for lessons in the future.

Sign up to request clarification or add additional context in comments.

8 Comments

Bye the way, change the ObservableCollectionEX to just ObservableCollection. I didn't provide the code for the subclassed ObservableCollectionEX.
Ibrahim, thank you so much for taking the time to help me. I totally agree with you regarding the lesson part but I just can find anything else that helps. Your example really compounded my confusion. I have tried using what you have provided and failed miserably. I don't really have a grasp of abstract classes and from what I have read INotifyPropertyChanged should be implemented on the ViewModel and not the Model. Where and how should I write the linq query ( Model or LocationKPI.cs)? And how do I referrence that in the ViewModel. That's all I need to get going so I can bind it to my View.
>>what I have read INotifyPropertyChanged should be implemented on the ViewModel and not the Model. << Depends upon your context. I often do things inside a ViewModel that requires knowing when something has changed within a model. I will create an event handler within the Viewmodel (or perhaps some other business logic class) that monitors the state of a given model. It was overkill for your situation, but I was trying to impress on you the use of an abstract class to handle common properties or methods across a group of related classes.
At this point I have invested all the free time I can in this issue. We long ago crossed the line into tutoring instead of diagnosing a programming issue. I wish you luck on your endeavor. If you are stuck on an actual project you might consider acquiring some professional consulting from someone like myself.
>>and from what I have read INotifyPropertyChanged should be implemented on the ViewModel and not the Model. << if you want the UI to respond to changes in value of items within an observable collection, then you have to implement INotifyPropertyChanged in the model. :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.