My Master's Thesis Problems and solutions encountered…

24Jan/110

Epilogue

So I wanted to post a small epilogue for bringing closure to this blog.

I handed in my Thesis on November 1st 2010, and defended it on November 23rd. I was very nervous about the result as I had spent the better part of 9 months coding the Silverlight application, and really not focusing on the writing of my Thesis until much later than anticipated. But at the end, everything went well - and I got a 12 for my Thesis (an A), which of course was very nice considering the immense amount of hours and stressful months spent on the project.

For the Thesis defence, I made a small presentation that outlined the main aspects of my Thesis, along with its main contributions. My main contributions were centered around:

  • The actual Silverlight application (that can be used for streamlining the certification processes for the standards SA8000 and ISO14001),
  • A new process model for software development, that takes into account the special circumstances of the development of RIA's, and lastly,
  • The demonstration of how the MVVM architectural pattern can be implemented.

My Thesis blog has of course focused on the last contribution - the implementation of the MVVM pattern. I have created a model showing the structure of the MVVM pattern, which I have added below, as it provides a good overview and is nice to have seen for anyone reading the other posts in this blog (click to enlarge):

Model-View-ViewModel (MVVM) - Silverlight

The figure lists the content of the View, the ViewModel, and the various classes within the Model:

  • The Model contains all data consumed and modified by the user. It defines the objects needed and the database data access, which populates the objects. The data retrieval and population of objects is completely separated from the other aspects, and can be tested in isolation through unit tests.
  • The View is the actual UI of the application. Written in the declarative language XAML, it defines all buttons, datagrids, dropdown-boxes, and other controls.
  • The ViewModel serves as data binding between the View and the Model. It has several purposes: It acts as data binder/converter as it changes data from the Model into the View, and it executes commands from the View to the Model.

MVVM project - Visual Studio
The MVVM project in Visual Studio is seen in the figure to the right, and shows that the Model, View and ViewModel each are created as individual projects. The View project is created as a Silverlight Application, and contains all the .xaml files, where the UI is specified. The ViewModel, on the other hand, is created as Silverlight Class Library, and contains the .cs files that are binded to the the .xaml files of the View. A .xaml file can be bound to one, and only one, class in the ViewModel, but several .xaml files can be bound to the same ViewModel. The Model is created as a WCF Service Application, which is designed to offer a manageable approach to creating WebServices.

I have zipped my Visual Studio application and stored in my public Dropbox folder. Do not expect it to compile, as I have shut down the WebService and made the database inaccessible. But maybe it can help you somehow: http://dl.dropbox.com/u/29076/Silverlight-MVVM-app.zip

Enjoy!

Filed under: Metapost No Comments
31Oct/100

Cascading Comboboxes in MVVM

Cascading comboboxes refers to having a combobox being populated depending on the selected item of another combobox. In my example, I have what is called a Group Questionnaire, which can contain any number of Questionnaires.

The main purpose with this post is to show how to deal with the Silverlight bug that entails that the binding of the SelectedItem to the second combobox is broken the second time the first combobox is updated, if it is bound to an ObservableCollection.

The actual populating of the Cascading comboboxes is not at all different than when a combobox is populated normally, but I will show it very quickly anyway.

The first thing you need to do is create a new class that will inherit the normal ComboBox:

Step 1: Create the following class in your ViewModel, which inherits the ComboBox.


  public class XComboBox : ComboBox
    {
        private BindingExpression bE;
        public XComboBox()
        {
            this.SelectionChanged += new SelectionChangedEventHandler(XComboBox_SelectionChanged);
        }

        void XComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (bE==null)
            {
               bE = this.GetBindingExpression(ComboBox.SelectedValueProperty);
            }
            else
            {
                if (this.GetBindingExpression(ComboBox.SelectedValueProperty) == null)
                {
                   this.SetBinding(ComboBox.SelectedValueProperty, bE.ParentBinding);
                }
            }
        }

    }

Step 2: In your View, where you want to add the cascading comboboxes, add a reference to the ViewModel, so you can access the XCombobox. Notice that the reference is called NewCombo:


xmlns:NewCombo="clr-namespace:ViewModel;assembly=ViewModel"

Step 3: Add the combobox in the View. Notice the NewCombo:XComboBox:

<!-- FIRST COMBOBOX -->
<NewCombo:XComboBox  x:Name="AllParentQstionnaires"
        ItemsSource="{Binding GroupQuestionnaireCB, Mode=OneWay}"
       SelectedValue="{Binding SelectedGroupQuestionnaireCB, Mode=TwoWay}"
       DisplayMemberPath="ParentQuestionnaireName"
       SelectedValuePath="ParentQuestionnaireID"
                                  />

<!-- SECOND COMBOBOX -->
   <NewCombo:XComboBox  x:Name="AllQuestionnaires"
       ItemsSource="{Binding QuestionnaireCB, Mode=OneWay}"
       SelectedValue="{Binding SelectedQuestionnaireCB, Mode=TwoWay}"
       DisplayMemberPath="QuestionnaireName"
       SelectedValuePath="QuestionnaireID"
                            />

And that's basically it! The rest works as usual, and you will want to create the properties of the ComboBoxes in the ViewModel.

Notice that the two comboboxes are bound to the GroupQuestionnaireCB and the QuestionnaireCB.

Step 4: Create all the properties for the comboboxes, and populate the first in the constructor, and the second combobox in the setter of the first combobox.


using ViewModel;
using ViewModel.QMServiceReference; 

namespace ViewModel
{
    public class Client_Questionnaire3_ViewModel : INotifyPropertyChanged
    {

        QMServiceReference.Service1Client WebService; 

        #region combobox properties

        //First combobox
        private ObservableCollection<ParentQuestionnaire> groupQuestionnaireCB;
        public ObservableCollection<ParentQuestionnaire> GroupQuestionnaireCB
        {
            get
            {
                return groupQuestionnaireCB;
            }
            set
            {

                groupQuestionnaireCB = value;
                RaisePropertyChanged("GroupQuestionnaireCB");

            }

        }

        private int selectedGroupQuestionnaireCB;
        public int SelectedGroupQuestionnaireCB
        {
            get
            {

                return selectedGroupQuestionnaireCB;
            }
            set
            {
                selectedGroupQuestionnaireCB = value;
                //Vi populate combobox nr. 2 with the SelectedValue from combobox 1. 

                RaisePropertyChanged("SelectedGroupQuestionnaireCB");
                //Populate next combobox
                WebService.GetAllQuestionnairesCompleted += new EventHandler<GetAllQuestionnairesCompletedEventArgs>(WebService_GetAllQuestionnairesCompleted);
                WebService.GetAllQuestionnairesAsync(2, SelectedGroupQuestionnaireCB);
            }
        }

        //Second combobox

        private ObservableCollection<AllQuestionnaires> questionnaireCB;
        public ObservableCollection<AllQuestionnaires> QuestionnaireCB
        {
            get
            {
                return questionnaireCB;
            }
            set
            {
                questionnaireCB = value;
                RaisePropertyChanged("QuestionnaireCB");
            }
        }

        private int selectedQuestionnaireCB;
        public int SelectedQuestionnaireCB
        {
            get
            {
                return selectedQuestionnaireCB;
            }
            set
            {
                selectedQuestionnaireCB = value;
                RaisePropertyChanged("SelectedQuestionnaireCB");

            }

        }

        #endregion

        //Contructor

        public Client_Questionnaire3_ViewModel()
        {

                WebService = new Service1Client();
                 //calls webservice to populate the first combobox
                WebService.GetParentQuestionnaireCompleted += new EventHandler<GetParentQuestionnaireCompletedEventArgs>(WebService_GetParentQuestionnaireCompleted);
                WebService.GetParentQuestionnaireAsync(2); 

        }

        void WebService_GetParentQuestionnaireCompleted(object sender, GetParentQuestionnaireCompletedEventArgs e)

     //populates the first combobox
       {
            GroupQuestionnaireCB = e.Result;
            //selects the first value as deafult
            if (GroupQuestionnaireCB.Count > 0)
            {
             SelectedGroupQuestionnaireCB = GroupQuestionnaireCB[0].ParentQuestionnaireID;
            }
        }

        void WebService_GetAllQuestionnairesCompleted(object sender, GetAllQuestionnairesCompletedEventArgs e){
        //populates the second combobox
            QuestionnaireCB = e.Result;
        //selects the first value as default
            if (QuestionnaireCB.Count > 0)
            {
                SelectedQuestionnaireCB = QuestionnaireCB[0].QuestionnaireID;
            }

        }

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

  }

}

And that's it!

Well, I have not shown the whole Model aspect, but it it's completely like described in my previous post.

29Oct/100

Upload Files to MS SQL DB – MVVM

In my application, I needed the users to be able to upload a file in order to document their answer to questions about their working and environmental conditions.

First, I am just going to show the sequence of windows the user has to go through in order to upload a specific file.

1) The users clicks the "Upload file" button
2) The user chooses which file to upload
3) The user is informed about the upload (progress bar)
4) The user is informed of whether the upload succeeded or failed

Step 1: Create the "Upload file" button.


        <Button x:Name="Upload"
            Content="Upload file"
            Command="{Binding UploadFile}"
            HorizontalAlignment="Center"/>

Step 2: Create the UploadFile command that the button is bound. If you have not already created the DelegateCommand.cs needed to handle your commands from buttons, add the following class to your ViewModel:

using System;
using System.Windows.Input;

namespace ViewModel
{
    public class DelegateCommand : ICommand //
    {
        private Predicate<object> _canExecute;
        private Action<object> _method;
        public event EventHandler CanExecuteChanged;

        public DelegateCommand(Action<object> method)
            : this(method, null)
        {
        }

        public DelegateCommand(Action<object> method, Predicate<object> canExecute)
        {
            _method = method;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }

            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _method.Invoke(parameter);
        }

        protected virtual void OnCanExecuteChanged(EventArgs e)
        {
            var canExecuteChanged = CanExecuteChanged;

            if (canExecuteChanged != null)
                canExecuteChanged(this, e);
        }

        public void RaiseCanExecuteChanged()
        {
            OnCanExecuteChanged(EventArgs.Empty);
        }
    }
}

Otherwise, just create UploadFile command, that defines what needs to be done when the user clicks the button.


        private DelegateCommand uploadFile;
        public DelegateCommand UploadFile // property bound to the button
        {
            get
            {
                if (uploadFile == null)
                    uploadFile = new DelegateCommand(executeuploadFile, canExecuteUploadFile);
                return uploadFile;
            }
        }
 //Defines if the button is clickable.
        private bool canExecuteUploadFile(object parameter)
        {
                return true; //always clickable... for now.
          }

      //Execute
        private void executeuploadFile(object parameter)
        {

            //Provides the dialog box that allows the user to chose files from their computer
            OpenFileDialog openDialog = new OpenFileDialog();
          //New instance of WebService
            WebService = new Service1Client();

           //Open dialog box, where user choses file
           if (openDialog.ShowDialog() == true)
            {
                try
                {
                    using (Stream stream = openDialog.File.OpenRead())
                    {
                        // Don't allow really big files (more than 5 MB).
                        if (stream.Length < 5120000)
                        {
                            byte[] data = new byte[stream.Length];
                            stream.Read(data, 0, (int)stream.Length);

                             //The method that is called after the upload has completed:
                            WebService.UploadFileCompleted += new EventHandler<AsyncCompletedEventArgs>(WebService_UploadFileCompleted);
                            // The method that uploads to the database: An ID, the name of the file, and the file in a bite array.
                            WebService.UploadFileAsync(AID, openDialog.File.Name, data);
                           //Open progress bar that lets the user know the file is being uploaded (window 2).
                             ShowText = "Uploading file";
                            BusyWindow = true;

                        }
                        stream.Close();
                    }

                }
                catch (FileNotFoundException ex)
                {

                }

            }
        }

//The method that is called when the file has been uploaded
  void WebService_UploadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            //Close busyWindow
            BusyWindow = false;

//Show verification childwindow. 

        }

Remember that you have to make changes to the .config files on both the client and the server, in order to allow larger files to be sent.

Step 4: Be sure to have a table in your database, where you can upload the files: You'll need a table with the following 3 columns: An Int attribute to store the unique value, a varchar(50) for the name of the file, and a varbinary(MAX) for containing the bite array that constitutes the file.

Step 5: I am not going show how to add the [ServiceContract] etc. in the Model, as it has been showed many times before, so I am just showing the UploadFile() that is defined in the Model:


 public class FileDTO_DAC : DBConnection
    {

        public void UploadFile(int a_ID, string FileType, byte[] Data)
        {
            //Open SQL connection
            SqlConnection dbConn = connectToDB();

         try
            {
                dbConn.Open();
                using (SqlCommand cmd = new SqlCommand("INSERT INTO attachments (a_ID, fileName, fileBin) VALUES (@a_ID, @Type, @BinaryData)", dbConn))
                {
                    cmd.Parameters.Add("@a_ID", SqlDbType.Int).Value = a_ID;
                    cmd.Parameters.Add("@Type", SqlDbType.VarChar, 50).Value = FileType;
                    cmd.Parameters.Add("@BinaryData", SqlDbType.VarBinary).Value = Data;
                    cmd.ExecuteNonQuery();
                }
             }
            catch (Exception)
            {
                throw;
            }
            dbConn.Close();

Enjoy!

Filed under: C#, MVVM, Silverlight 4 No Comments
29Oct/100

Download files from a MS SQL Database – MVVM

This post will show to download a file that is located in a MS SQL Database. The user goes through the following steps:

1) The user clicks the download button
2) The user is informed that the download is in progress (progress bar)
3) The user has to confirm the download
4) The user is asked to define where he want the file to be saved
5) The user is of the success or failure of saving the file to his desktop

The most important thing to notice is that the user has to 'confirm' the download twice: When he first clicks the button, and again when it has been downloaded, and the user can chose to 'Save' or 'Cancel' to open the dialog box, where the user determines where on his desktop he want to save the file.

Step 1. Create the object that is returned from the database containing the file you want to download. The file object has two attributes: The name of the file, and the file itself, which is saved as a bite array, and is of type SqlBytes:

using System.Data.SqlTypes;

  [DataContract]
    public class FileDTO
    {

        private string _fileType;
        private SqlBytes _data;

        [DataMember]
        public string FileType
        {
            get { return _fileType;}
            set { _fileType = value; }
        }

        [DataMember]
        public SqlBytes Data
        {
            get  {return _data;}
            set  {_data = value; }
        }
    }

Step 2: While you're in the Model, create the method GetFile() that returns an instance of the FileDTO class, that contains the file from the database.


 public FileDTO GetFile(int ID)
        {

            //New instance
            FileDTO fileDTO = new FileDTO();
            SqlConnection dbConn = connectToDB();
            //The query
            string _selectQuery = string.Format("Select * from attachments where a_ID = " + ID + "");
          try
            {
                dbConn.Open();
                using (SqlCommand cmd = new SqlCommand("Select * from attachments where a_ID = @ID", dbConn))
                {
                    cmd.Parameters.Add("@ID", SqlDbType.Int).Value = ID;
                    SqlDataReader rdr = cmd.ExecuteReader();
                    while (rdr.Read())
                    {
                        fileDTO.FileType = rdr.GetString(2);
                        fileDTO.Data = rdr.GetSqlBytes(3);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }

            dbConn.Close();
            return fileDTO;
        }

Step 3: Create the "Download file" button in the View. Notice that it binds to the command DownloadFile

<Button x:Name="Get" Content="Download file"
                Style="{StaticResource Knap}"  Width="80"
                Command="{Binding DownloadFile}"
  />
 

Step 4: In the ViewModel, create the command that executes when the "Download File" button is clicked, and that calls the GetFile() method described in step 2.

You will have to notice several things: First, the executeDownloadFile calls the GetFile(), and when the call is completed, the WebService_GetFileCompleted method is called, and return value (the file) is saved in a newly created object of type FileDTO , i.e. the class you created in step 1.


//Property bound to the button
 private DelegateCommand downloadFile;
        public DelegateCommand DownloadFile
        {
            get
            {
                if (downloadFile == null)
                    downloadFile = new DelegateCommand(executeDownloadFile, canExecuteDownloadFile);
                return downloadFile;
            }
        }

//Defines if the button is clickable
        private bool canExecuteDownloadFile(object parameter) //Definerer om knappen er klik-bar.
        {
                return true; //always clickable
        }

        private void executeDownloadFile(object parameter)
        {
           //Shows progress bar while downloading
           ShowText = "Downloading file";
            BusyWindow = true;

            WebService = new Service1Client();
            //defines the method that is called when it returns with a value
            WebService.GetFileCompleted += new EventHandler<GetFileCompletedEventArgs>(WebService_GetFileCompleted);
             //Calls the method
            WebService.GetFileAsync(AID);

        }
         //Method is called when the Model has returned with a value
        void WebService_GetFileCompleted(object sender, GetFileCompletedEventArgs e)
        {
            // Call the method CallBackFromService with the result (the file) as a parameter
           CallBackFromService(e.Result);
        }
        //Create new instance of FileDTO.
        FileDTO fileDTO;
        public void CallBackFromService(FileDTO fileDTOCallBack)
        {
            Set to the local version of the fileDTO, close progressbar
            fileDTO = fileDTOCallBack;
            BusyWindow = false;

            //Makes button from (3) visible: The user has to confirm that he wants to download the file.
            AfterDownload = Visibility.Visible;
 }

Step 6: After the CallBackFromService has been called, the user must confirm that he wants to download the file. The button in "Save File" in window (3) shown above is bound to the command SaveAttachment:

     //Property bound to the button
        private DelegateCommand saveAttachment;
        public DelegateCommand SaveAttachment
        {
            get
            {
                if (saveAttachment == null)
                    saveAttachment = new DelegateCommand(executeSaveAttachment);
                return saveAttachment;
            }
        }
 //Execute:
        private void executeSaveAttachment(object parameter)
        {
            //Enables the apperance of a Dialog, where the user can specify where to save the file
            SaveFileDialog textDialog = new SaveFileDialog();

            //We found out what type of file it is (.doc, .pdf, etc). 

            //name of file, for example MyFile.doc
            string test = fileDTO.FileType;
            //Gets the number of characters before the "."
            int index = test.LastIndexOf(@".");
            //Find the type of the file by retrieving the characters after the index number
            string docType = test.Substring(index);
            //Doctype : .doc, .pdf, etc. 

           //Knowing the type, we can now define which default type-value has to be chosen in the Dialog, where the user saves the file. 

            if (docType == ".jpg")
            {

                textDialog.DefaultExt = ".jpg";
                textDialog.Filter = "JPG|*.jpg";

            }

            else if (docType == ".docx")
            {
                textDialog.DefaultExt = ".docx";
                textDialog.Filter = "Microsoft Office 2008 .docx|*.docx";

            }

            else if (docType == ".doc")
            {
                textDialog.DefaultExt = ".doc";
                textDialog.Filter = "Microsoft Office 2003 .doc|*.doc";

            }

//10 other formats have been added

             //save the file in a bite array
            byte[] fileBytes = fileDTO.Data;//your bytes here
            //Open dialog where the user determines where to save the file.
             bool? result = textDialog.ShowDialog();
            if (result == true)
            {
                When the user clicks OK, the file is saved.
                using (Stream fs = (Stream)textDialog.OpenFile())
                {
                    fs.Write(fileBytes, 0, fileBytes.Length);
                    fs.Close();
                }
            }

            //The user is informed of the download.
            AfterRealDownload = Visibility.Visible;

And that's it!

Filed under: C#, MVVM, Silverlight 4 No Comments
21Aug/103

Create a Pie Chart with Silverlight toolbox – MVVM

This post quickly shows how to create a pie chart in your MVVM Silverlight application, like the one shown below:

Pie chart MVVM Silverlight

Step 1: Add the System.Windows.Controls.DataVisualization.Toolkit into your project, and insert this at the top of your MyPage.xaml in the View:

   xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"    

Step 2: Insert the pie chart in MyPage.xaml. Notice the ItemSource, which we will bind to in the ViewModel.

 <charting:Chart HorizontalAlignment="Stretch"
                BorderBrush="Transparent"
                VerticalAlignment="Top" Height="170"
                Name="pieChart" Margin="0 -10 0 -10">

                <charting:Chart.Series >
                    <charting:PieSeries ItemsSource="{Binding ChartItems}"
                          IndependentValueBinding="{Binding Key}"
                          DependentValueBinding="{Binding Value}" >
                     </charting:PieSeries>
                </charting:Chart.Series>
</charting:Chart>

Step 3: In the ViewModel, create the following property, that will contain the array of the chart:


  private KeyValuePair<string, int>[] _chartItems;
         public KeyValuePair<string, int>[] ChartItems
         {
             get
             {
                 return _chartItems;
             }

             set
             {
                 _chartItems = value;
             }
         }

Step 4: In your ViewModels constructor, create the ChartItems and populate them.


    ChartItems = new KeyValuePair<string, int>[4];

             ChartItems[0] = new KeyValuePair<string, int>("Lorem ipsum dolor sit amet", 20);
             ChartItems[1] = new KeyValuePair<string, int>("Maecenas iaculis dapibus", 90);
             ChartItems[2] = new KeyValuePair<string, int>("Nulla facilisi. Curabitur laoreet", 112);
             ChartItems[3] = new KeyValuePair<string, int>("Pellentesque non turpis elit", 160); 

             //RaisePropertyChanged("ChartItems"); //Only necessary of you create the ChartItems outside the constructor

And that's it!

Of course, you will want to populate the chart with integers retrieved from a database, and in that case, just create properties for each of the items.

Filed under: C#, MVVM, Silverlight 4 3 Comments
7Aug/106

CRUD operations in Silverlight Datagrid – MVVM

This post will explain how you can add, edit or delete data from the database, by having it inserted into a Datagrid in your Silverlight application, and editing it from there.

The premise for following the guide in this post is that you have a project with the MVVM design pattern, and that you have already created a Datagrid that is populated with data from a database. Furthermore, you should be willing to open ChildWindows using the slightly un-MVVM'ish method described in my last post. If anybody wants to follow the guide I provide in this post, it is definitely recommended first to have followed the guide on how to open ChildWindows, although the main aspects of it also are covered here.

Now, I use my grid in order to display questions that are used for a questionnaire, that determines whether a company is eligible for becoming certified for the standard SA8000, ie. whether their working conditions are acceptable. Therefore, the questions in the example are all related to working conditions. The colors each question is given represents the severity associated with a company answering 'yes' or 'no' to the question (obviously, the companies filling out the questionnaire can't see the colors - it's just used afterwards, to get an overview over how well the company did).

To simplify the example, I will only post the code related to editing of the question. The add and delete methods are very much alike, and after having gone through the how-to, you can probably figure out how to change what needs to be changed. If not, drop a comment and I'll add it. To simplify further, I will not add the editing of the groups or the colors.

My whole grid looks like this:

MVVM edit/add/delete data in datagrid

So, what I wish to achieve is this: When I select a row from the grid and press the edit button, a child window has to appear with the data from the selected row inserted into an editable textbox. When I hit the save button in the child window, the database has to be updated, and the datagrid in the main window has to be updated as well, having inserted the changes from the database.

To sum up, I want my ChildWindow to look like this:

Again, you can disregard the colors and the group section, as I will only be focusing on the textbox with the question.

OBS: All code for both the MainPage and the ChildWindow are in the ViewModel for the MainPage.

So. From the start:

Step 1: In the ViewModel for you MainPage, you'll add properties for the grid, the selected row in the grid, the question in the mainpage, and the question in the ChildWindow. Notice that the SelectedQuestion property for the MainPage is set in the SelectedQuestionRow which is updated everytime the user clicks on a new row in the grid.

Notice that the object I will populate my grid with is called QuestionGrid, which was of course defined in the Model. You'll just have to update this to whatever you named yours.


//The property that will be tied to the ItemSource in XAML
   private QuestionGrid _questionGrid;
        public QuestionGrid QuestionGrid
        {
            get { return _questionGrid; }
            set
            {
                _questionGrid = value;
                RaisePropertyChanged("QuestionGrid");
            }

        }

        //Selected row.  THe property that will be binded to SelectedItem in XAML.
        private QuestionGrid _selectedQuestionRow;
        public QuestionGrid SelectedQuestionRow
        {
            get
            {
                return _selectedQuestionRow;
            }
            set
            {

                _selectedQuestionRow = value;

 //sets the value for the string that will be passed to the childwindow
                SelectedQuestion = value.Question;

 //We want to retrieve the ID as well, for when we update the database
               SelectedQuestionID = value.Q_UI; 

            }
        }
//QuestionID, MainPage
  public int selectedQuestionID;
        public int SelectedQuestionID
        {
            get
            {
                return selectedQuestionID;
            }
            set
            {
                selectedQuestionID = value;
                RaisePropertyChanged("SelectedQuestionID");
            }
        }

//Question for mainpage
        public string selectedQuestion;
        public string SelectedQuestion
        {
            get
            {
                return selectedQuestion;
            }
            set
            {
                selectedQuestion = value;
                RaisePropertyChanged("SelectedQuestion");
            }
        }

 //Properties for the grid. 

   //The question

            private string question_EditCW;
            public string Question_EditCW
            {
                get { return question_EditCW; }
                set
                {
                    question_EditCW = value;
                    RaisePropertyChanged("Question_EditCW");
  //SaveEdit is the name of the command we will create later, to save the changes to the database
                    SaveEdit.RaiseCanExecuteChanged();

                }
            }  

So, now I have created the properties, and now we will define the xaml to both the MainPage and the ChildWindow:

Step 2: Create the grid and button in the MainPage (the command binded to the button will open the child window)

Notice that the grid binds to QuestionGrid and SelectedQuestionRow, created earlier, but also notice that the question itself in the Textblock in the gird is binded to the attribute name of the object, created in the Model.


<!-- MainPage: DATAGRID -->

 <data:DataGrid x:Name="AllCompaniesGrid"
                SelectedItem="{Binding SelectedQuestionRow, Mode=TwoWay}"
                ItemsSource="{Binding QuestionGrid}"   

                AutoGenerateColumns="False"
                VerticalScrollBarVisibility="Visible" >

    <data:DataGrid.Columns>
        <!--Question Column. -->
        <data:DataGridTemplateColumn Header="Questions">
            <data:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Question}" />
                </DataTemplate>
            </data:DataGridTemplateColumn.CellTemplate>
        </data:DataGridTemplateColumn>
 </data:DataGrid>

<!-- The button! -->

 <Button Content="Edit" Style="{StaticResource Knap1}" Width="60" Command="{Binding EditQuestion}"  />

Step 3: Create textbox and button in the ChildWindow (the command binded to the button will update the database, close the window, and update the grid).


<!-- The textbox -->
 <TextBox Text="{Binding Question_EditCW, Mode=TwoWay}"     />

<!-- The button! -->

  <Button x:Name="Add" Command="{Binding SaveEdit}" Content="Editquestion"  />

Step 4: Define the command for button in the MainPage, in the ViewModel. I will go through this very quickly, but look at my old post here, if you have doubts about the DelegateCommand, or anything else.

But remember: The delegate command is binded to a button and is divided into three parts: 1) The property part that creates the property that will bind to the edit button, and calls the CanExecute and Execute methods, 2) the CanExecute part that tells wether the button is clickable or not (returns true or false), and 3) the Execute part, that executes if the button is pressable and is pressed: In our case, the Execute will open the new ChildWindow, called EditQuestionCW.


//property for the button command
            private DelegateCommand editQuestion;
            public DelegateCommand EditQuestion
            {
                get
                {
                    if (editQuestion == null)
                        editQuestion = new DelegateCommand(executeEditQuestion, canExecuteEditQuestion);
                    return editQuestion;
                }
            }
//Is the button clickaable? True = yes, False = no.
            private bool canExecuteEditQuestion(object parameter)
            { //Button only clickable if row in grid is selected
                if (SelectedQuestion != null) { return true; }
                else { return false; }
            }

            //New instance of the childwindow. My ChildWindow EditQuestionCW is in the folder ChildWindows.
            ChildWindows.EditQuestionCW EditQuestionCW;
            private void executeEditQuestion(object parameter)
            {

                //Sets the question
                Question_EditCW = SelectedQuestion;
                RedYes_EditCW = true;

                //Opens Child Window
                EditQuestionCW = new ChildWindows.EditQuestionCW(this);
                EditQuestionCW.Show();
           }

These next steps differentiates this post from the former. Here we will define what happens, when the SaveEdit button is pressed in the childWindow, and therefore how we update the changes to the database. But first: Creating the SQL query.

Step 5: Create the SQL query that will update the database and insert the new data. This will happen in your Model . Mine looks somethink like this:

public class EditAddQuestionDA : DBConnection
    {
  public void EditQuestion(int q_ID, string question) //The id and the question as parameters
        {
            SqlConnection dbConn = connectToDB();
            SqlCommand cmd;
            string updateQuestion = string.Format("update question set question = '" + question + "' where q_ID = " + q_ID + "; "); 

            try
            {
                dbConn.Open();

                if (question != "")
                {
                    cmd = new SqlCommand(updateQuestion, dbConn);
                    cmd.ExecuteNonQuery();
                }
                dbConn.Close();
            }
            catch (Exception e) { Console.WriteLine(e.ToString()); }

        }
}

Step 6: In the Service1.svc.cs make the method available to the ViewModel:

 public void EditQuestion(int q_ID, string question)
        {
            EditAddQuestionDA allDA = new EditAddQuestionDA();
            allDA.EditQuestion(q_ID, question);
        }

Step 7: In the IService1.cs:

 [ServiceContract]
    public interface IService1
    {
  [OperationContract]
        void EditQuestion(int q_ID, int G_ID, string question, int yes, int no);
}

So, now the query can be accessed from the ViewModel, so we can create the DelegateCommand for the button in the ChildWindow, that will call the EditQuestion() method:

Step 8: In the ViewModel we create the SaveEdit DelegateCommand, that is divided - like before - to three parts: 1) the DelegateCommand SaveEdit property, 2) The boolean method that determines if the button is clickable, and 3) The Execution of the code that will save the new question to the database, and update the grid in the MainPage.


      private DelegateCommand saveEdit;
            public DelegateCommand SaveEdit
            {
                get
                {
                    if (saveEdit == null)
                        saveEdit = new DelegateCommand(executeSaveEdit, canSaveEDit);
                    return saveEdit;
                }
            }

//Can Execute - Defines if the button should be clickable.
//True = Yes, false = no. Yes if the question is not identical to the one in the grid = no changes made
            private bool canSaveEDit(object parameter) //Definerer om knappen er klik-bar.
            {

              if (SelectedQuestion == Question_EditCW)
                {
                    return false;  //Only clickable if changes have been made
                }

                else { return true; } //Not identical -> return true
            }

//When the button is pressed:
            private void executeSaveEdit(object parameter)
            {
                //updates the grid (only visually, not in the DB
                SelectedQuestionRow.Question = Question_EditCW;

                //WE cose the childwindow, and call the method that will insert the new question into the database

                EditQuestionCW.Close();

                QMServiceReference.Service1Client WebService.EditQuestionCompleted += new EventHandler<AsyncCompletedEventArgs>(WebService_EditQuestionCompleted); //Defines the method that will be called when the database has been called.
                WebService.EditQuestionAsync(SelectedQuestionID, Question_EditCW); //Calls the method

            }

//The method that is called when the database has been updated: 

  void WebService_EditQuestionCompleted(object sender, AsyncCompletedEventArgs e)
        {
           //When the database has been updated we update the grid in the MainPage. 

            WebService.GetQuestionGridCompleted += new EventHandler<GetQuestionGridCompletedEventArgs>(WebService_GetQuestionGridCompleted);
            WebService.GetQuestionGridAsync(SelectedQuestionnaireCB);

        }

//When the GetQuestionGrid query has been run - insert the results into the grid: 

        void WebService_GetQuestionGridCompleted(object sender, GetQuestionGridCompletedEventArgs e)
        {

            QuestionGrid = e.Result;
        }

Enjoy!

Filed under: C#, MVVM, Silverlight 4, XAML 6 Comments
22Jul/1016

Open Child Window in a MVVM’ish design pattern

This post explains how to open a ChildWindow, pass data to the ChildWindow, and how to pass data back from the ChildWindow to the MainPage, using a MVVM Design pattern in a Silverlight 4 application.

The method I am using is not strickly MVVM, because I actually create my ChildWindows in the ViewModel, which is usually a no-go. But considering the endless Googling after alternatives only to find guides that use all kinds of toolkits in order for a ChildWindow to appear (see fx., here, here and (the one that takes the price in length and complexity) here), I consider this workaround the best way to do it. I hope and expect that an easier and strickly MVVM solution will be possible with Silverlight 5.

This post is just meant as a proof of concept, and is based on a very simple example: The MainPage.xaml contains two textboxes, Name and Address, respectively, and the ChildWindow, the same. When the user enters their Name in the MainPage and presses the button, the ChildWindow appears, with the Name value entered (see picture below). The user can then enter an address in the ChildWindow and press the button, and return to the MainPage, where the value has been inserted in to the Address textbox of the MainPage.

ChildWindow, MVVM

So. The solution is simple. Just create the ChildWindow in the View Model project, so you can parse data through the ChildWindow and MainPage. Then create properties for each of the 4 textboxes (2 for each), and create the commands for the buttons, that will open/close the Child Window, and connect the properties. Notice that the ChildWindow does not have a ViewModel, and everything thus happens in the ViewModel of the MainPage:

Step 1: Create a new ChildWindow in your ViewModel. Right-click on project >> Add >> Silverlight ChildWindow. I have named mine MyChildWindow.xaml.

Step 2: Create a ViewModel for your MainPage. I have named mine MainPage_ViewModel.cs.

Step 3: Connect the MainPage.xaml.cs and MyChildWindow.xaml.cs to the MainPage_ViewModel.cs:

MainPage.xaml.cs:


namespace View
{
    public partial class MainPage : UserControl
    {

        public MainPage()
        {
            InitializeComponent();
            this.DataContext = new MainPage_ViewModel();
         }
     }
}

MyChildWindow.xaml.cs:


namespace ViewModel
{
    public partial class MyChildWindow : ChildWindow
    {
        public MyChildWindow(MainPage_ViewModel ma)
        {
            InitializeComponent();
            this.DataContext = ma;
        }

    }
}

Step 4: Create properties for the textboxes of the MainPage and ViwModel (both have two textboxes), in the MainPage_ViewModel.cs:

using System.ComponentModel;
using System.Collections.ObjectModel;
using ViewModel; 

namespace ViewModel
{
    public class MainPage_ViewModel : INotifyPropertyChanged
    {
//Properties of Mainpage
private string myNameVM = "";
        public string MyNameVM
        {

            get { return myNameVM; }
            set {
                myNameVM = value;
                RaisePropertyChanged("myNameVM");
            }
        }

        private string myAddressVM = "";
        public string MyAddressVM
        {

            get { return myAddressVM; }
            set
            {
                myAddressVM = value;
                RaisePropertyChanged("MyAddressVM");
            }
        }

//Properties of ChildWindow
        private string myNameCW = "";
        public string MyNameCW
        {

            get { return myNameCW; }
            set
            {
                myNameCW = value;
                RaisePropertyChanged("MyNameCW");
            }
        }

        private string myAddressCW = "";
        public string MyAddressCW
        {

            get { return myAddressCW; }
            set
            {
                myAddressCW = value;
                RaisePropertyChanged("MyAddressCW");
            }
        }

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

 }

(Step 5): If you have not created one eralier, you will need to create a DelegateCommand class in your ViewModel, that will handle the button commands needed for the next step. So. Create a new class, name it DelegateCommand.cs, and insert the following:


using System;
using System.Windows.Input;

namespace ViewModel
{
    public class DelegateCommand : ICommand //
    {
        private Predicate<object> _canExecute;
        private Action<object> _method;
        public event EventHandler CanExecuteChanged;

        public DelegateCommand(Action<object> method)
            : this(method, null)
        {
        }

        public DelegateCommand(Action<object> method, Predicate<object> canExecute)
        {
            _method = method;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }

            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _method.Invoke(parameter);
        }

        protected virtual void OnCanExecuteChanged(EventArgs e)
        {
            var canExecuteChanged = CanExecuteChanged;

            if (canExecuteChanged != null)
                canExecuteChanged(this, e);
        }

        public void RaiseCanExecuteChanged()
        {
            OnCanExecuteChanged(EventArgs.Empty);
        }
    }
}

Step 6: Create the commands in the MainPage_ViewModel.cs, that you will bind to the buttons in the MainPage.xaml and MyChildWindow, respectively.

using System.ComponentModel;
using System.Collections.ObjectModel;
using ViewModel; 

namespace ViewModel
{
    public class MainPage_ViewModel : INotifyPropertyChanged
    {
//Properties of Mainpage
private string myNameVM = "";
        public string MyNameVM
        {
            get { return myNameVM; }
            set {myNameVM = value;
                RaisePropertyChanged("myNameVM");
                 }
            }

        private string myAddressVM = "";
        public string MyAddressVM
        {

            get { return myAddressVM; }
            set
            { myAddressVM = value;
                RaisePropertyChanged("MyAddressVM");
            }
        }

//Properties of ChildWindow
        private string myNameCW = "";
        public string MyNameCW
        {

            get { return myNameCW; }
            set
            {  myNameCW = value;
                RaisePropertyChanged("MyNameCW");
            }
        }

        private string myAddressCW = "";
        public string MyAddressCW
        {

            get { return myAddressCW; }
            set
            {  myAddressCW = value;
                RaisePropertyChanged("MyAddressCW");
            }
        }

         //When the button is pressed in MainPage, executes method ExecuteOpenChildWindow
        private DelegateCommand _openChildWindow;
        public DelegateCommand OpenChildWindow
        {
            get
            {
                if (_openChildWindow == null)
                    _openChildWindow = new DelegateCommand(executeOpenChildWindow);

                return _openChildWindow;
            }
        }

        // New instance of ChildWindow. Sets the NameProperty of the ChildWindow equal to the Name entered in the MainPage.
        MyChildWindow cw;
        private void executeOpenChildWindow(object parameter)
        {
            cw = new MyChildWindow(this);
            MyNameCW = MyNameVM;
            cw.Show();
        }

      //When OK-button is pressed in ChildWindow
        private DelegateCommand _okChildWindow;
        public DelegateCommand OkChildWindow
        {
            get {
                if (_okChildWindow == null)
                    _okChildWindow = new DelegateCommand(OkSaveChildWindow);

                return _okChildWindow;
            }
        }
        //MainPage Address property is set to the value entered in the address textbox in Child Window. Child Window is closed.
        private void OkSaveChildWindow(object parameter)
        {
            MyAddressVM = MyAddressCW;
            cw.Close();
        }

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

Step 7: Add the textboxes in the MainPage.xaml and MyChildWindow.xaml, and bind them to the properties created in MainPage_ViewModel. Also Create the buttons, that will bind to the commands.

MainPage.xaml:

<StackPanel>

        <Grid Margin="0 10 0 5" Width="350">

    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>

    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"/>
        <ColumnDefinition Width="*"/>

    </Grid.ColumnDefinitions>

    <!--TextBlocks-->
    <TextBlock Text="Name:" TextWrapping="Wrap" Margin="5,5,0,5" Grid.Row="0"  />
    <TextBlock Text="Address:" Grid.Row="1" Grid.Column="0"  />

   <!--TextBox, where the users enters data. Binds to the properties of MainPage_ViewModel-->
  <TextBox Text="{Binding MyNameVM, Mode=TwoWay}" Grid.Row="0" Grid.Column="1"/>
  <TextBox Text="{Binding MyAddressVM, Mode=TwoWay}"  Grid.Row="1" Grid.Column="1"/>

    <Button Content="Open Child Window"
            VerticalAlignment="Center"
            HorizontalAlignment="left"
            Width="auto"
            Margin="5"
            Grid.Row="2"
            Command="{Binding OpenChildWindow}" <!--Binds to CommandDelegate from the ViewModel -->
        />
        </Grid>
    </StackPanel>

MyChildWindow.xaml:


    <Grid Margin="0 30 0 5" Width="350">

        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="205*"/>

        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="*"/>

        </Grid.ColumnDefinitions>

        <TextBlock Text="Name: " Grid.Row="0" />
        <TextBlock Text="Address:" Grid.Row="1" Grid.Column="0"  />

        <!-- TextBoxes are bind to the properties from the ViewModel.  -->
        <TextBox x:Name="InputName" Text="{Binding MyNameCW, Mode=TwoWay}" Grid.Row="0" Grid.Column="1" Height="20"/>
        <TextBox x:Name="OutputAddress" Text="{Binding MyAddressCW, Mode=TwoWay}" Grid.Row="1" Grid.Column="1" Height="20"/>

       <!-- Button comand bind to CommandDelegate from ViewModel -->
      <Button x:Name="OKButton" Command="{Binding OkChildWindow}" Content="OK" Width="75" Height="23" Margin="0,12,79,0" Grid.Row="2" Grid.Column="1"/>
    </Grid>

And that's it! :)

Filed under: C#, MVVM, Silverlight 4 16 Comments
17Jul/100

Combobox two-way binding in MVVM

Almost all applications have a need of retrieving data into a combobox, and do something depending on what the user choses from the combobox. This is also the case in my application, and luckily Silverlight 4 has a pretty good way of dealing with the situation.

In this post I will show how you can populate a textbox with a QuestionnaireID depending on which QuestionnaireName the user has chosen from the combobox. Obviously, this is just a proof of method, as the the retrieved QuestionnaireID has another purpose (in my case it will be passed to a child window, and be used to update the database with the changes the user wants to make to the questionnaire). But for now, I will just show how you can solve the task taking into consideration the MVVM design structure.

I can recommend looking into the blog post called Binding to Silverlight ComboBox and Using SelectedValue, SelectedValuePath and DisplayMemberPath, if any questions come up, as you can download the complete source code from there.

So, as with all my other posts, the prerequisite is that you have a Model project where the objects are defined and populated with data fromn the database, and a View where you have all your .xaml files, and the ViewModel, that binds the two together and calls the Webservice.

Step 1: Go to your Model, and add a FirePropertyChanged to each of the attributes of the object.

    [DataContract(Name = "AllQuestionnaires")]
    public class DropBox_Questionnaire : INotifyPropertyChanged
    {

        string _questionnaireName;
        [DataMember]
        public string QuestionnaireName
        {
            get { return _questionnaireName; }
            set { _questionnaireName = value;
            FirePropertyChanged("QuestionnaireName");

            }
        }

        int _questionnaireID;
        [DataMember]
        public int QuestionnaireID
        {
            get { return _questionnaireID; }
            set { _questionnaireID = value;
            FirePropertyChanged("QuestionnaireID");
            }
        }

//INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void FirePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }

So you have now prepared the attributes for the two-way binding.

Step 2: In your ViewModel, create a SelectedQuestionnaire property that will contain the QuestionnaireID of the questionnaire, that the user has chosen. I have added all code, including the property for the Combobox, and the WebService call.


//Combox
      private ObservableCollection<AllQuestionnaires> _questList;
        public ObservableCollection<AllQuestionnaires> QuestList
        {
            get { return _questList; }
            set
            {
                _questList = value;
                RaisePropertyChanged("QuestList");
            }
        }

//Selected value
  private int _selectedQuestionnaire;
        public int SelectedQuestionnaire
        {
            get { return _selectedQuestionnaire; }
            set
            {
                _selectedQuestionnaire = value;
                RaisePropertyChanged("SelectedQuestionnaire");

            }
        }

//Constructor, Calls webservice
   public Client_Questionnaire2_ViewModel()
        {
            int UID = 2;
            int pq_ID = 1; //temporary hadrcoding

            QMServiceReference.Service1Client WebService = new Service1Client();

            WebService.GetAllQuestionnairesCompleted += new EventHandler<GetAllQuestionnairesCompletedEventArgs>(WebService_GetAllQuestionnairesCompleted);
            WebService.GetAllQuestionnairesAsync(UID, pq_ID);
}
//sets QuestList Property, returns data from database
   void WebService_GetAllQuestionnairesCompleted(object sender, GetAllQuestionnairesCompletedEventArgs e)
        {
            QuestList = e.Result;
        }

Step 3: Define the combobox in your xaml page in the View, and notice the ItemSource (that binds to the object) and the SelectedValue, that binds to the string property SelectedQuestionnaire that will contain what the user chooses (hence the TwoWay binding). The DisplayMemberPath and SelectedValuePath define the object attributes that the combobox will show, and the value it will send to SelectedQuestionnaire, respectively.

<!-- The combobox -->
<ComboBox  x:Name="QuestonnaireTest"
         ItemsSource="{Binding Path=QuestList, Mode=OneWay}"  //QuestList, property from ViewModel
         SelectedValue="{Binding Path=SelectedQuestionnaire, Mode=TwoWay}" //SelectedQuestionnaire, property from ViewModel
         DisplayMemberPath="QuestionnaireName" //Attribute from Model
         SelectedValuePath="QuestionnaireID" //Attribute from Model

/>

<!-- The textblock, where the QuestionnaireID is inserted -->

<TextBlock Name="textBlock" Text="{Binding Path=SelectedQuestionnaire, Mode=OneWay}" />

Enjoy!

Filed under: C#, MVVM, Silverlight 4 No Comments
11Jul/100

How to add background-color to cells in a DataGrid depending on content

When working on my Silverlight application I found need of giving cells in a DataGrid a specific color, so the user would get a better overview of the shown data. In my application, I have a questionnaire with a list of questions regarding the working and environmental conditions of a company. Now, the answer to each question is beforehand given a color: Red, yellow or green, depending on the severity of answering yes/no to the question.

I wanted to create a Datagrid that gave the creator of the questionnaire an overview over the answers he had created, and the color he given them. I ended up with this:

Step 1: In you .xaml page, create a DataGrid like the one shown below. Notice the Fill="{Binding Converter={StaticResource QuestionsResultConverterYES}}" in the Rectangle.

(Below is only shown the code for the two first columns).

...

xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
...
 <data:DataGrid x:Name="AllQuestionsGrid" MinHeight="10" IsReadOnly="True" Width="350"  AutoGenerateColumns="False" ItemsSource="{Binding QuestionList}" MaxHeight="320" VerticalScrollBarVisibility="Visible" Margin="5 10 5 0" >

    <data:DataGrid.Columns>
        <!--Question Column. -->
        <data:DataGridTemplateColumn Header="Questions" Width="190">
            <data:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock TextWrapping="Wrap" Text="{Binding Question}" /> <!-- OT:  This is how you wrap text inside a Datagrid. Simply make TemplateColumn and insert a TextBlock.  -->
                </DataTemplate>
            </data:DataGridTemplateColumn.CellTemplate>
        </data:DataGridTemplateColumn>

        <!--Yes-column-->
        <data:DataGridTemplateColumn Header="Yes" Width="auto">
            <data:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Rectangle Margin="4" x:Name="MyRectangle" Fill="{Binding Converter={StaticResource QuestionsResultConverterYES}}" /><!--We will create the Static Resource QuestionsResultConvertYES in the next step -->
                       </Grid>
                </DataTemplate>
            </data:DataGridTemplateColumn.CellTemplate>
        </data:DataGridTemplateColumn>

<!-- Repeat for the other no-column-->

    </data:DataGrid.Columns>
</data:DataGrid>

Step 2: Create a new class in your View project. I added a new folder, called Converter, where I put all the Converter classes. In this class we will create a new instance of the object that we want to insert into the datagrid, in my case called QuestionGrid. One of the attributes is called AnswerYes and contains a string with the values "Red", "Yellow" or "Green". So we insert a if-elseif-else that will return a specific SolidColorBrush value depending on the content of the string:


using System.Windows.Data;
using ViewModel.QMServiceReference;

namespace View.Converters
public class QuestionsResultConverterYES : IValueConverter //Important!
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {

            QuestionGrid ColorYes = value as QuestionGrid;

            if (ColorYes == null)
            {
                return value;
            }
            else if (ColorYes.AnswerYes == "Red")
            {
                return new SolidColorBrush(Color.FromArgb(255, 204, 51, 51)); //red
            }
            else if (ColorYes.AnswerYes == "Yellow")
            {
                return new SolidColorBrush(Color.FromArgb(255, 255, 255, 102)); //yellow
            }
            else if (ColorYes.AnswerYes == "Green")
            {
                return new SolidColorBrush(Color.FromArgb(255, 51, 102, 0));//green
            }
            else
            {
                return new SolidColorBrush(Color.FromArgb(255, 220, 220, 220)); //grey
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Notice that we return a color of the type ARGB. It's basically just normal RGB colors (the last three values), and the first just sets the opacity (255 = 100%, 0 = 0%, that is, transparent).

Step 3: In the App.xaml (where you probably have all your your style deifnitions), you will make the QuestionsResultConverterYES available to your .xaml page.

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:layout="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
              xmlns:nav="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
             xmlns:converters="clr-namespace:View.Converters" //add
             x:Class="View.App"
             >
        <Application.Resources>
                  <converters:QuestionsResultConverterYES x:Key="QuestionsResultConverterYES"/>
        </Application.Resources>
</Application>

And that's it!

Filed under: Misc. No Comments
8Jul/102

How to populate a combobox in a MVVM design pattern

This post just explains how to populate a dropdown box in your Silverlight application. It's almost the same as in the previous post, but I will just repeat it here, as I will be using this multiple times. One difference between this and the former post, is that we work with an ObservableCollection instead of normal strings, and another difference lies in having to populate a dropbox, which requires a partial class that makes sure that the data from the database is printed, and not the name of the object.

As in the previous post, this post will not be so thorough, and should anybody want to retrieve data from a MS SQL database trough a MVVM pattern with WCF, they should start by reading and following the steps on these two posts: MVVM structure and Deploying WCF Services.

Step 1: Model project -> Model folder -> New class.

I have called the new class ParentQuestionnaires.cs, and it will contain the data that I eventually want to retrieve from the database and insert into the application.


*
using System.Runtime.Serialization; 

namespace Model.Model
{
    [DataContract(Name = "ParentQuestionnaire")]
    public class ParentQuestionnaires
    {

        string _parentQuestionnaireName;
        [DataMember]
        public string ParentQuestionnaireName
        {
            get { return _parentQuestionnaireName; }
            set { _parentQuestionnaireName = value; }
        }

    }
}

Step 2: Model project -> Data_access folder -> New class.

I have called my class ParentQuestionnairesDA.cs, and it will contain the connection to the database and the query.

*using Model.Model;
using System.Data.SqlClient; 

namespace Model.Data_access
{
    public class ParentQuestionnairesDA: DBConnection
    {

        public List<ParentQuestionnaires> GetParentQuestionnaire(int UID)
        {

            List<ParentQuestionnaires> PQlist = new List<ParentQuestionnaires>();

            SqlConnection dbConn = connectToDB();
            string _selectQuery = string.Format("select blablbalbla from blabla where blabla = " + UID + ";");

            try
            {
                dbConn.Open();
                SqlCommand cmd = new SqlCommand(_selectQuery, dbConn);
                SqlDataReader rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    ParentQuestionnaires PQ = new ParentQuestionnaires();
                    PQ.ParentQuestionnaireName = (string)rdr[0];
                    PQlist.Add(PQ); 

                }

            }
            catch(Exception e) {

                Console.Write(e);
            }

            return PQlist; 

        }

    }
}

Step 3: Model project ->> IService1.cs

Connects client and server-side.


**
using Model.Model;

namespace Model
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        List<ParentQuestionnaires> GetParentQuestionnaire(int UID);
    }
}

Step 4: Model project -> Service1.svc.cs

Creates new instances of the two classes created above, calls the GetParentQuestionnaire(UID); method

**
using System.Data.SqlClient;
using Model.Model;
using Model.Data_access;

namespace Model
{

    public class Service1 : IService1
    {
        public List<ParentQuestionnaires> GetParentQuestionnaire(int UID)
        {

            List<ParentQuestionnaires> allQuestionnaires;
            ParentQuestionnairesDA AllDA = new ParentQuestionnairesDA();
            allQuestionnaires = AllDA.GetParentQuestionnaire(UID);
            return allQuestionnaires;
        }
    }
}

Step 5: This is the step that differentiates this guide from the rest: We need to make a partial class, that will make sure that we data from the database is printed in dropdown box - not the name of the object. First, create a new folder in your ViewModel, where you will put this class. I have named mine Model.

ViewModel project -> Model folder -> create class. I have called mine ParentQuestionnaire.cs


*using System.Windows.Shapes;

namespace ViewModel.QMServiceReference // name of your Service Reference!
{
    public partial class ParentQuestionnaire //will be called in the next step.
    {
        public override string ToString()
        {
            return this.ParentQuestionnaireName; //created in step 1.
        }
    }
}

After this step, you need to publish the Model and update your ServiceReference.

Step 6: ViewModel -> Create new class. I always name mine after the .xaml page where I want to insert the data, followeb by "_ViewModel". Hence, I have called mine .

*
using ViewModel.QMServiceReference;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace ViewModel
{
    public class Client_Questionnaire_ViewModel : INotifyPropertyChanged //inportant!
    {
        private ObservableCollection<ParentQuestionnaire> parentQuest; //ParentQuestionnaire, created in the previous step.
        public ObservableCollection<ParentQuestionnaire> ParentQuest
        {
            get { return parentQuest;  }
            set { parentQuest = value;
                    RaisePropertyChanged("ParentQuest"); 

            }
        }

        public Client_Questionnaire_ViewModel()
        {
            int UID = 2; //for now, hardcoding.
            QMServiceReference.Service1Client WebService = new Service1Client();
            WebService.GetParentQuestionnaireCompleted += new EventHandler<GetParentQuestionnaireCompletedEventArgs>(WebService_GetParentQuestionnaireCompleted);
            WebService.GetParentQuestionnaireAsync(UID);
        }
        void WebService_GetParentQuestionnaireCompleted(object sender, GetParentQuestionnaireCompletedEventArgs e)
        {
            ParentQuest = e.Result;
        }

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

And lastly: Insert into the combo box into your .xaml page:

  <ComboBox  x:Name="ParentQuestionnairej" ItemsSource="{Binding ParentQuest}" HorizontalAlignment="Left" Width="150" Height="20"  Style="{StaticResource ComboBox2}" Margin="0,2,0,0" Grid.Column="1" Grid.Row="0" />
4Jul/102

Retrieving data from a MS SQL DB

This post is basically just a recap of the former, and aims to quickly show how to retrieve data form the MS SQL database through WCF Services all the way through my MVVM design pattern and to my Silverlight application. The steps in this posts will be repeated many times in my application, as I will go through them each time I have to retrieve a piece of data from the database.

This posts presupposes that the user has followed the steps in my recent post, explaining how to setup the MVVM design pattern: MVVM Structure. Also, it's preferable that the user has followed the steps in my last post, as it explains how to overcome some of the small problems that I encountered when deploying the WCF Service: This blog post just recaps the whole thing (but ads some smaller structure changes, in steps 1-3), and will not be as thorough as my last blog post.

I have made two changes:

First, I have decided to add two new folders in my Model project, called Model and Data_access, respectively. The Model folder contains all classes whose attributes we want to retrieve to the Silverlight application. The Data_access folder contains all classes that actually calls the database, runs the query, and returns the desired values. This has been done so as to ease the overview, as I otherwise would end up with way to much code in IService1.svc.cs

Also, I have made a DBconnection.cs class in the Data_access folder that all other classes in the folder inherit.

So, from the start:

Step 1: Create two folders in the Model project, called Model and Data_access, respectively.

Step 2: Add a DBconnection class in your Model folder containing the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.SqlClient;

namespace Model.Data_access
{
    public class DBConnection
    {
        public SqlConnection connectToDB()
        {
            string connstring = "Data Source=********;Initial Catalog=*******;User ID=********;Password=*********;Integrated Security=False;";
            SqlConnection dbConn = new SqlConnection(connstring);

            return dbConn;
        }

    }
}

Step 3: Create a new class in your Model folder named after the place in your application, where you want to insert the data you retrieve from the database. I have called mine Client_Home.cs. In this class you will merely define the attributes of the object, and create their properties. Notice the DataContract and DataMember.

*
using System.Runtime.Serialization;

namespace Model.Model
{
    [DataContract]
    public class Client_Home
    {

        string active_parentQuestionnaire_;

        [DataMember]
        public string Active_parentQustionnaire
        {
            get { return active_parentQuestionnaire_; }
            set { active_parentQuestionnaire_ = value; }
        }

    }
}

Step 4: Go to your Data_access folder, and create the class that will call the database and populate the attributes defined in the Client_Home class created in the last step. Depending on what you use your data for, it could be usefull to name the class after the tables you mainly retrieve the data from... but I have decided (for now) just to name it after the class it is related to from the Model folder. Hence, I have called mine Client_HomeDA.cs.

Step 5: Now, in the class that you have just created: For each attribute that you have declared in your Client_Home.cs, you will create a method that retrieves that data from the database. My first (and for now, only) attribute in my Client_Home is named ActiveQuestionnaire, as I just want to retrieve the name of the active questionnaire of the current user. So, in my Client_HomeDA.cs I will create a method that has a userID as a parameter:

using System.Data.SqlClient;
using Model.Model;

namespace Model.Data_access
{
    public class Client_Home_DA : DBConnection
    {

  public string GetActiveQuestionnare(int UID)  //In this case we just want to retrieve a string, and not a list of objects, like in the previous example.
        {

            string client =""; //Empty string
            SqlConnection dbConn = connectToDB();
            string _query = string.Format("SELECT parent_questionnaire.title FROM parent_questionnaire, accessible WHERE accessible.active = 1 AND accessible.pq_ID = parent_questionnaire.pq_ID AND u_ID = " + UID);

            try
            {
                dbConn.Open();
                SqlCommand cmd = new SqlCommand(_query, dbConn);
                SqlDataReader rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {

                    client = (string)rdr[0];
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            return client;
        }
  }

}

Notice that the class inherits the DBConnection class.

Step 6: Go to the IService1.cs, where you will make the GetActiveQuestionnaire available. This class is basically the link between the server and the client, and whatever methods you define in this class have to be also in the one of the classes you have created in the Data_access folder.


*
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using Model.Model;

namespace Model
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetActiveQuestionnare(int UID);
    }
}

Step 7: Go to your Service1.svc.cs, where you will create a new instance of the Client_Home, and call the Client_Home_DA, that will populate the attributes with data from the database, and return it. Notice that we have added the Using Model.Model and Model.Data_access.

*
using System.Data.SqlClient;
using Model.Model;
using Model.Data_access;

namespace Model
{

    public class Service1 : IService1
    {
          public string GetActiveQuestionnare(int UID)
        {
            string cli;
            Client_Home_DA cliDA = new Client_Home_DA();
            cli = cliDA.GetActiveQuestionnare(UID);
            return cli; 

        }
    }
}

Step 8: Publish by right-clicking on you Model project >> Publish.

Step 9: Right-click on your Service Reference that you created in step 11 in my last post, and click 'Update Service Reference'.

Step 10: The next step is to create a class in your ViewModel, that will be connected to the .xaml page, where you want to insert the data. I want to insert the data in a page called Client_Home, so I create a class called Client_Home_ViewModel.cs, that will contain the necessary properties and eventhandlers. Remember that you have to have published and updated your Service References before you can execute the code in the constructor.

Also notice that you have to inherit the INotifyPropertyChanged .

*
using ViewModel.QMServiceReference;
using System.ComponentModel; 

namespace ViewModel
{
    public class Client_Home_ViewModel : INotifyPropertyChanged //Important!!!!
    {
        private string activeQuestionnaire_;
        public string ActiveQuestionnaire
        {//Property
            get { return activeQuestionnaire_;  }
            set { activeQuestionnaire_ = value;
            RaisePropertyChanged("ActiveQuestionnaire");
            }
        }
         public Client_Home_ViewModel()
        {//Constructor, calls WebService
            int UID = 2; //Temporary hardcoding.
            QMServiceReference.Service1Client WebService = new Service1Client();
            WebService.GetActiveQuestionnareCompleted += new EventHandler<GetActiveQuestionnareCompletedEventArgs>(WebService_GetActiveQuestionnareCompleted);
            WebService.GetActiveQuestionnareAsync(UID); 

        }

         void WebService_GetActiveQuestionnareCompleted(object sender, GetActiveQuestionnareCompletedEventArgs e)
         {
             ActiveQuestionnaire = e.Result; //Return value, sets property

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

    }
}

Step 11: The next step is of course to define the textblock in your .xaml code (mine is Client_Home.xaml), where you want to display the result of your query. Notice that we bind to ActiveQuestionnaire, which is the property that we defined in the code in the previous step:

 <TextBlock Grid.Row="1" Grid.ColumnSpan="4" Grid.Column="1" Foreground="#FF696969" Text="{Binding ActiveQuestionnaire}"/>

Step 12: The very last thing to do is to connect your Client_Home.xaml to the Client_Home_ViewModel, which is done by opening your Client_Home.xaml.cs and instantiating the Client_Home_ViewModel():

*
using ViewModel;

namespace View
{
    public partial class Client_Home : Page
    {
        public Client_Home()
        {
            InitializeComponent();
            this.DataContext = new Client_Home_ViewModel();
        }

       protected void Page_Loaded(object sender, RoutedEventArgs e)
        {
         }

    }
}

And so, these are the steps that must be repeated again and again and again, everytime data is retrieved from the database...

Enjoy!

Ps. In this post I have hardcoded the UserID that I needed, but I will soon blog about how to parse the data from one page to another, and how you can save data locally... but for now, I will just work on how figuring out what data I need, how the application will look like, which queries are necessary, and how to insert all this into my project.

Filed under: C#, Silverlight 4 2 Comments
14Jun/102

MS SQL Connection – Deploying WCF Services

So, I found a host for my WCF Service, which uses a IIS 7 server that can run my .svc WebService file. I could connect to my MySQL database hosted another place, but given that my new host uses MS SQL, I will be migrating to that.

This post explains how you can deploy your WCF Service and connect to the underlying database, and how to retrieve data all the way through the MVVM Design Pattern. The prerequisites for this post is that you have 1) created a project with a design pattern that somewhat resembles the MVVM covered in my previous post (see MVVM Structure), and 2) that you have created a table in a MS SQL database called 'Suppliers', and inserted three attributes called ID, name and country, respectively.

First, make sure that you have 3 projects in your solution, fx. called Model (a WCF Service Application), View (a Silverlight application), and ViewModel (a Silverlight class). You have connected the projects View and ViewModel together like it was described in step 4 of the previous post.

Step 1: Just to make sure that you have all the right information in order to deploy to your server, right-click on your Model project >> Publish, and enter all necessary data. Notice that you have to enter ftp://yourdomain.net and not just ftp.yourdomain.net.

If you have entered the correct data, the following output will be shown, and the WCF Service will have been added to the root of your server:

Step 2: Go to your Model project and chose Web.Config. Find the row that starts with < system.serviceModel>. It will look something like this:

 <system.serviceModel>
<!--Add code here -->
    <services>
      <service name="Model.Service1" behaviorConfiguration="Model.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="wsHttpBinding" contract="Model.IService1">
 (...)

Step 3: Right below the < system.serviceModel> and before < services> starts, you'll need to add the following code snippet:


  <serviceHostingEnvironment>
          <baseAddressPrefixFilters>
              <add prefix="http://yourDomain.net"/>
          </baseAddressPrefixFilters>
      </serviceHostingEnvironment>

Step 4: Then, a small change needs to be implemented to the endpoint binding. Shown in the code below step 2, you can see that the standard binding is wsHttpBinding. This needs to be changed to BasicHttpBinding.

After having completed step 3 and 4, you will thus end up with the code below:


<system.serviceModel>

      <serviceHostingEnvironment>
          <baseAddressPrefixFilters>
              <add prefix="http://yourDomain.net"/>
          </baseAddressPrefixFilters>
      </serviceHostingEnvironment>

    <services>
      <service name="Model.Service1" behaviorConfiguration="Model.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="BasicHttpBinding" contract="Model.IService1">
          <!-- 

Step 5: Repeat step 1., ie. right-click on your WebSevice >> Publish. You will then notice that two files and folder have been added to the root of your server: A Service1.svc and a Web.Config file, and a Bin folder.

Step 6: Still in your Model project, open your IService1.cs. Here you will create a class that will contain the attributes and properties for the Suppliers object that we create. Also notice the code inside the brackets [], fx. [OperationContract] and [DataMember], which make the methods and properties available to the other projects.


namespace Model
{

    [DataContract]//Makes the class available
    public class Suppliers //creates the objectet Suppliers, and defines its attributtes (properties).
    {
        int _ID;
        string _name;
        string _country;

        [DataMember]//makes the property available
        public int ID
        {
            get { return _ID; }
            set { _ID = value; }
        }
        [DataMember]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        [DataMember]
        public string Country
        {
            get { return _country; }
            set { _country = value; }
        }

    }

Step 7: Open your Service1.svc.cs file in the Model project. In this file we will connect to the database and run our queries. When you open the file you'll notice that a lot of code has already been created for you. Below is the standard content of the Service1.svc file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace Model
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }
    }
}

You just need to delete everything inside the class, and instead insert what is explained in the following steps.

Step 8: Add a reference to using System.Data.SqlClient; at the top.

Step 9: Create a SqlConnection ConnectToDB() method, that sets the connections string and returns the Sql Connection. If you have Winhost, you will find what you need to insert into your Connection String by logging in >> Site >> Site Tools >> MS SQL 2008 >> Manage. The ConnectToDB method looks something like this:


  public SqlConnection connectToDB()
        {
            string connstring = "Data Source=************;Initial Catalog=*****;User ID=******;Password=*******;Integrated Security=False;";
            SqlConnection dbConn = new SqlConnection(connstring);

            return dbConn;
        }

Step 8: Now we will add the method that will query the database and return a List of data that ultimately will be inserted into the Silverlight application. Notice that we create a method called getSupplierList() of type List< Suppliers>, where Suppliers is the name of the class created in step 6.

    public List<Suppliers> getSupplierList()
        {

            List<Suppliers> SupplierList = new List<Suppliers>(); //list that will containt all data retrieved from the database. 

            SqlConnection dbConn = connectToDB();//Method above
            string _selectQuery = string.Format("SELECT * FROM suppliers");//Query
            try
            {
                dbConn.Open();
                //Creates the comand object and sets the query of the command.
                SqlCommand cmd = new SqlCommand(_selectQuery, dbConn); //Executes
                SqlDataReader rdr = cmd.ExecuteReader(); //loop, read data

                while (rdr.Read())//for hver række der bliver hentet ind, gør vi følgende
                {

                    Suppliers Sup = new Suppliers();

                    Sup.ID = (int)rdr[0];
                    Sup.Name = (string)rdr[1];
                    Sup.Country = (string)rdr[2];

                    SupplierList.Add(Sup); //row is added

                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            return SupplierList;
        }
    }

Step 9: Open IService1.cs again. Before the public class Suppliers that you created earlier, add the OperationContract shown below, that exposes your getSupplierList() method and makes it accessable to the ViewModel.

[ServiceContract]
    public interface IService1
    {

        [OperationContract]
        List<Suppliers> getSupplierList(); //Name of method in Service1

    }

Step 10: Repeat step 1 (publish).

Now, we need to connect the ViewModel to the Model.

Step 11: On your ViewModel, right-click on References, and chose Add new Webservice. Here you will want to find the webService you have uploaded to the server. In the address field, enter http://yourDomain.com/Service1.svc, like shown below. Name your WebService (I have named mine QMWebService) and click 'OK'.

Now, you have connected the ViewModel to the Model.

If your service is not hosted locally and your Silverlight is, then you will get a warning about CrossDomain policy. To enable your service to receive calls from your locally hosted application, follow step 12:

Step 12: Create a new .xml file that contains the following code (source).


<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

Copy the file to the root of your server.

Step 13: This step is necessary in order for the View to reflect the changes made to it when the property in the ViewModel is set (updated). You will have to add a class to your ViewModel, and just copy-paste the code from below. It is taken from the MVVM demo application by Josh Smith, and can be also be found here. Name the class ViewModelBase.cs.

Name the class ViewModelBase, as all classes in the ViewModel are inherited from it.


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Diagnostics;

namespace SilverLightViewModel
{
    /// <summary>
    /// Base class for all ViewModel classes in the application.
    /// It provides support for property change notifications
    /// and has a DisplayName property.  This class is abstract.
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
        #region Constructor

        protected ViewModelBase()
        {
        }

        #endregion // Constructor

        #region DisplayName

        /// <summary>
        /// Returns the user-friendly name of this object.
        /// Child classes can set this property to a new value,
        /// or override it to determine the value on-demand.
        /// </summary>
        public virtual string DisplayName { get; protected set; }

        #endregion // DisplayName

        #region Debugging Aides

        /// <summary>
        /// Warns the developer if this object does not have
        /// a public property with the specified name. This
        /// method does not exist in a Release build.
        /// </summary>
        //[Conditional("DEBUG")]
        //[DebuggerStepThrough]
        //public void VerifyPropertyName(string propertyName)
        //{
        //    // Verify that the property name matches a real,
        //    // public, instance property on this object.
        //    if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        //    {
        //        string msg = "Invalid property name: " + propertyName;

        //        if (this.ThrowOnInvalidPropertyName)
        //            throw new Exception(msg);
        //        else
        //            Debug.Fail(msg);
        //    }
        //}

        /// <summary>
        /// Returns whether an exception is thrown, or if a Debug.Fail() is used
        /// when an invalid property name is passed to the VerifyPropertyName method.
        /// The default value is false, but subclasses used by unit tests might
        /// override this property's getter to return true.
        /// </summary>
        protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

        #endregion // Debugging Aides

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            //this.VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        #endregion // INotifyPropertyChanged Members

        #region IDisposable Members

        /// <summary>
        /// Invoked when this object is being removed from the application
        /// and will be subject to garbage collection.
        /// </summary>
        public void Dispose()
        {
            this.OnDispose();
        }

        /// <summary>
        /// Child classes can override this method to perform
        /// clean-up logic, such as removing event handlers.
        /// </summary>
        protected virtual void OnDispose()
        {
        }

#if DEBUG
        /// <summary>
        /// Useful for ensuring that ViewModel objects are properly garbage collected.
        /// </summary>
        ~ViewModelBase()
        {
            string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode());
            System.Diagnostics.Debug.WriteLine(msg);
        }
#endif

        #endregion // IDisposable Members
    }
}

Step 14: The next step is to go to your MainPage_ViewModel, that will contain the necessary properties and eventhandlers. The aim with this class is to register changes, call the WebService, and retrieve the data that will be inserted into the .xaml Grid, that will be created in the next step.

MainPage_ViewModel:


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SilverLightViewModel;//new
using System.Collections.ObjectModel;//new
using ViewModel.QMServiceReference; //new

namespace ViewModel
{
    public class MainPage_ViewModel : ViewModelBase
    {
        private ObservableCollection<Suppliers> _suppliers; //Collection registres changes. Updates run.
        //list of all supplies

        public MainPage_ViewModel()
        {

            QMServiceReference.Service1Client WebService = new Service1Client();
            WebService.getSupplierListCompleted += new EventHandler<getSupplierListCompletedEventArgs>(WebService_getSupplierListCompleted);//Eventhandler is trigged when the webservice call has been run, and data han been retrieved
            WebService.getSupplierListAsync(); //calls webservice. 

        }

        void WebService_getSupplierListCompleted(object sender, getSupplierListCompletedEventArgs e)
        {

            //Is called when the webservice returnes a list 

            Suppliers = e.Result;
        }

        # region Properties

        public ObservableCollection<Suppliers> Suppliers
        {
            get { return _suppliers; } //instance of Suppliers
            set
            {
                _suppliers = value;
                OnPropertyChanged("Suppliers");
            }//property name
        }

        # endregion

    }
}

Step 15 (last step!): Create a Grid in your MainPage.xaml, like the one shown below. Notice that the name of the binding attribute is not named after the name you have created in your database, but rather in what you declared them in your Model, in the Suppliers class (see step 6).

MainPage.xaml:

 <data:DataGrid x:Name="SupplerGrid" MinHeight="100" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Suppliers}">
                <data:DataGrid.Columns>
                    <data:DataGridTextColumn x:Name="ID" Header="ID" Binding="{Binding ID}" />
                    <data:DataGridTextColumn x:Name="ID2" Header="Name" Binding="{Binding Name}" />
                    <data:DataGridTextColumn x:Name="testData" Header="Value" Binding="{Binding Country}" />
                </data:DataGrid.Columns>
            </data:DataGrid>

And no... this time I won't end the post by stating "And that's it!", because this task is horrible, frustrating and endlessly time-consuming. But it works. I hope this post will help somebody get through the process costing only a limited amount of blood, sweat and tears.

Enjoy!