Sunday, June 25, 2017

WPF DataGrid Databinding using MVVM Pattern

Hello,

I've been developing WPF applications before but not having applied the MVVM design pattern and have been wanting to create a simple program that loads data into the DataGrid control. According to Wikipedia, the components of an MVVM pattern are:
Model
Model refers either to a domain model, which represents real state content (an object-oriented approach), or to the data access layer, which represents content (a data-centric approach).
View
As in the MVC and MVP patterns, the view is the structure, layout, and appearance of what a user sees on the screen.
View model
The view model is an abstraction of the view exposing public properties and commands. Instead of the controller of the MVC pattern, or the presenter of the MVP pattern, MVVM has a binder. In the view model, the binder mediates communication between the view and the data binder.The view model has been described as a state of the data in the model.
Binder
Declarative data and command-binding are implicit in the MVVM pattern. In the Microsoft solution stack, the binder is a markup language called XAML.
Given the explanations above, here's the code that applies a plain MVVM approach.
ViewModel (CustomerViewModel.cs)
The model used here is the Northwind Customer
public class CustomerViewModel : ViewModelBase
    {
        private ObservableCollection<Customer> _cusGridData;
        private NorthwindEntities _context;

        public CustomerViewModel()
        {
            _context = new NorthwindEntities();
            LoadInitialData();
        }

        private void LoadInitialData(){
            CustomerData = new ObservableCollection<Customer>(from c in _context.Customers select c);
        }

        public ObservableCollection<Customer> CustomerData
        {
            get 
            { 
                return _cusGridData; 
            }
            set
            {
                _cusGridData = value;
                OnPropertyChanged("CustomerData");
            }
        }
    }
View (XAML)
<Window x:Class="WPFMVVMDataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ViewModel="clr-namespace:WPFMVVMDataGrid"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <ViewModel:CustomerViewModel/>
    </Window.DataContext>
    <Grid>
        <DataGrid ItemsSource="{Binding Path=CustomerData}" x:Name="dgCustomer"
             AutoGenerateColumns="False"
             SelectionMode="Single"
             SelectionUnit="FullRow"
             GridLinesVisibility="Horizontal"
             CanUserDeleteRows="True"
             CanUserAddRows="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Width="SizeToCells" MinWidth="125" Binding="{Binding CustomerID}" />
                <DataGridTextColumn Header="Age" Width="SizeToCells" MinWidth="200" Binding="{Binding ContactName}"/>
                <DataGridTextColumn Header="Description" Width="SizeToCells" MinWidth="200" Binding="{Binding Address}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

For the details on how MVVM works see this thread WPF Having Trouble with binding a Datagrid control on load

Cheers! :-)

Monday, June 5, 2017

Disable button in AngularJS using ng-disabled on it's first page load in ASP.NET MVC

Hello,
One might notice that during page load of an ASP.NET MVC application, the button with ng-disabled attribute and have values such as $invalid or $dirty does not disable the button. Thus, this will enable the user to submit the form with empty values to the controller method. In order to disable the button on page load, add $pristine values in the ng-disabled attribute such as the code below.
Original Code
<input type="submit" id="btnAddEmployee" class="btn btn-primary" value="Save" ng-click="Save()" 
 ng-disabled="AddEmp.fname.$dirty && AddEmp.fname.$invalid
     || AddEmp.lname.$dirty && AddEmp.lname.$invalid
     || AddEmp.salary.$dirty && AddEmp.salary.$invalid" />
Modified code with $pristine
<input type="submit" id="btnAddEmployee" class="btn btn-primary" value="Save" ng-click="Save()" 
 ng-disabled="AddEmp.fname.$dirty && AddEmp.fname.$invalid || AddEmp.fname.$pristine
     || AddEmp.lname.$dirty && AddEmp.lname.$invalid || AddEmp.lname.$pristine
     || AddEmp.salary.$dirty && AddEmp.salary.$invalid || AddEmp.salary.$pristine" />

Saturday, June 3, 2017

$location.path() method not reloading new data in ASP.NET MVC Web API with AngularJS

Hello,
I was trying to integrate AngularJS into a simple ASP.NET MVC Web API application with Save functionality. Basically, when you have finished posting data the next logic will be to redirect the user to the display all page. However, I stumbled into an issue in which the $location service does not reload data.
According to the docs,the $location service allows you to change only the URL; it does not allow you to reload the page. So after placing breakpoints in the Api Controller, I noticed that the GetAll() method is called first next is the Save() method. The solution to this dilemma is to transfer the $location.path() method inside the success function so that the Save() method in the Api Controller is executed first.
Code With Issue: $location.path() is outside the success function.
 $scope.Add = function () {
  $http({ method: "POST", data: $scope.employee, url: "/api/employees" })
  .then(function (response) {
   $scope.employees = response.data;
   $scope.employee = {
    "FirstName": "",
    "LastName": "",
    "Age": "",
    "Salary": ""
   };   
  });
  $location.path('/allemployees'); 
}
Fix: $location.path() is inside the success function.
$scope.Add = function () {
  $http({ method: "POST", data: $scope.employee, url: "/api/employees" })
  .then(function (response) {
   $scope.employees = response.data;
   $scope.employee = {
    "FirstName": "",
    "LastName": "",
    "Age": "",
    "Salary": ""
   };
   $location.path('/allemployees'); 
  });  
}

Cheers! :-)

Wednesday, May 17, 2017

Adding ASP.NET 5 Templates to VS 2015

Good day!
One might notice that the ASP.NET 5 templates are not visible when creating a new Web Application Project in Visual Studio 2015 given that this is a fresh installation of the software. So to add the ASP.NET 5 Templates, download the ASP.NET 5 run-time tools Microsoft ASP.NET and Web Tools 2015 (RC) – Visual Studio 2015 and proceed with the setup. Restart your machine afterwards.
That's it.. :-)

This version of Visual Studio requires the April 2014 update to Windows 8.1 (VS 2015)

Hello,
Now that I've got the time to install Visual Studio 2015 Enterprise on my laptop with Windows 8.1 Operating System I decided to give it a go. That's when the moment I opened the installer file, an issue pops out of the screen with the description "This version of Visual Studio requires the April 2014 update to Windows 8.1 and Windows Server 2012 R2 known as KB2919355".
The solution to this issue can easily be found at stackoverflow. But missing the links of the packages needed to resolve the problem. A step by step example is presented below.
1. Download update package 2919442 and install update to your pc. This is the pre-requisite update of package 2919355
   x86
   x64
2. Download update package 2919355 and install update to your pc.
   x86
   x64
3. After those updates have been installed, restart the computer for the updates to take effect.
Cheers! :-)

Monday, May 1, 2017

How to Post JSON data with WebRequest in .NET

Hello,
There was a question on how to post a JSON data using the WebRequest class given that using Ajax, the post data would look like this.
data: '{ "age": "78", "weight": "51" }'
In .NET, you need to store the JSON data into a string object and escape those double quotes before passing it to the WebRequest object.
C#.NET
string postData = "{ \"age\": \"78\", \"weight\": \"51\" }";
VB.NET
Dim postData As String = "{ ""age"": ""78"", ""weight"": ""51"" }"

Cheers! :-)

Wednesday, April 12, 2017

Sorting of <li> elements using jQuery sort() not working (refresh page only) in ASP.NET

Given the simple sorting code below which changes the order of <li> elements to ascending order and assuming that the text content of each li elements are numbers.
$(function () {
 $('#sortList').click(function (e) {
  // Select all the li items
  var numbersList = $('#numbersList li');
  
  numbersList.sort(function (a, b) {
   return parseInt($(a).text(), 10) > parseInt($(a).text(), 10);
  }).appendTo(numbersList.parent());
 });
});
The code should work only to find out that the page will only refresh after the button click. And then the re-arranging of the elements are discarded. The simple fix to this issue is to add the preventDefault() to prevent the button's default behavior that is to post back.
$(function () {
 $('#sortList').click(function (e) {
         //add preventDefault() to reflect the changes after sorting
  e.preventDefault();
  // Select all the li items
  var numbersList = $('#numbersList li');
  
  numbersList.sort(function (a, b) {
   return parseInt($(a).text(), 10) > parseInt($(a).text(), 10);
  }).appendTo(numbersList.parent());
 });
});
Fiddle: Sort Unordered list items

Saturday, April 8, 2017

$.getJSON() not loading JSON file within Visual Studio Project in ASP.NET WebForms

Hi,
I was trying to load a JSON file located within my Visual Studio project using $.getJSON(), however the code below doesn't work as expected.
$.getJSON('/Assets/misc/employee.json', function (data) {
 alert('processing!');
})
.done(function (r) {
 alert(r.message);
})
.fail(function (s) {
 alert('oops the file is missing!');
});
After investigating for a few hours, I tested the local path of the JSON file such as http://localhost:3766/Assets/misc/employee.json and the result was an exception "HTTP Error 404.3 - Not Found The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.".
I remember the solution in one of my ASP.NET project was to set the MimeMap in the web.config inside the system.webServer element. After setting the MimeMap for json files, I can now load local JSON files using $.getJSON().
<system.webServer>
 <staticContent>
   <mimeMap fileExtension=".json" mimeType="application/json" />
 </staticContent>
</system.webServer>

:-)

Friday, April 7, 2017

Visual Studio showing only "Attach" and no Debug options in ASP.NET Project

Hello,
Last night my computer shuts down unexpectedly due to power outage and when I opened an ASP.NET project this morning, it only shows "Attach" in the debug options. Running to different browsers such as Google Chrome, Firefox and Internet Explorer were missing.
After a few search, I encountered a solution which is to set again the ASP.NET Project as StartUp Project by right clicking the project and selecting the option Set as StartUp Project.
That's it.. :-)

Tuesday, March 21, 2017

Set an Html.RadioButtonFor() helper as default Checked

Good day!
Given that you have to set a radio button as default checked in razor view, a code to do that is presented below using conditional ternary operator. However, there is an issue with the code shown below. Even if you set the checked property with empty string, it will still render as checked during run-time.
@foreach (var answer in item.Answers)
{
 <p>
  @Html.RadioButtonFor(m => answer.ID, true,
     new
     {
      @disabled = "true",
      @Name = item.ID,
      @checked = (answer.IsCorrect) ? "checked" : ""
     })@answer.AnswerText
 </p>
}           
To ignore that issue, there are several ways to fix that. First one is to use if statement in the view itself.
@foreach (var answer in item.Answers)
{
 <p>
  @if (answer.IsCorrectAnswer)
  {
   @Html.RadioButtonFor(m => answer.ID, true,
     new
     {
      @disabled = "true",
      @Name = item.ID,
      @checked = "true"
     })@answer.AnswerText

  }
  else
  {

   @Html.RadioButtonFor(m => answer.ID, false,
     new
     {
      @disabled = "true",
      @Name = item.ID,
     })@answer.AnswerText
  }
 </p>
}
And another one is to create a custom RadioButton helper.
public static MvcHtmlString RadioButtonFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, 
 Expression<Func<TModel, TValue>> expression, object value, object htmlAttributes, bool checkedState)
{
 var htmlAttributeDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

 TagBuilder tagbuilder = new TagBuilder("input");
 tagbuilder.Attributes.Add("value", value.ToString());
 tagbuilder.Attributes.Add("type", "radio");
 tagbuilder.Attributes.Add("id", ExpressionHelper.GetExpressionText(expression));

 if (checkedState)
 {
  tagbuilder.Attributes.Add("checked", "checked");
 }

 foreach (var item in htmlAttributeDictionary)
 {
  tagbuilder.Attributes.Add(item.Key, item.Value.ToString());
 }

 return MvcHtmlString.Create(tagbuilder.ToString(TagRenderMode.Normal));
}
Usage of custom HtmlHelper
@Html.RadioButtonFor(m => answer.ID, (answer.IsCorrectAnswer) ? true : false, new
{
 @disabled = "true",
 @Name = String.Format("Question_{0}", item.ID),
}, answer.IsCorrectAnswer)@answer.Text

Cheers! :-)