Wednesday, 17 September 2014

ObservableCollection Example

ObservableCollection is a built in collection type that raises change notification if any element in the collection is changed or deleted or a new element is added to the collection. If we want to create a custom collection type that raises change, we need to use INotifyCollectionChanged.

Below is a simple example of using ObservableCollection:
private ObservableCollection<string> names = new ObservableCollection<string>() { "aaa", "bbb", "ccc" };

public MainWindow()
{
 InitializeComponent();
 
 listBox1.ItemsSource = names;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
 names.Add(textBox1.Text);
        names[0] = "ABC";
}
and on the view:
<ListBox x:Name="listBox1" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" />
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23"  TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Button Content="Add Name" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="100" Click="Button_Click"/>            

Thursday, 11 September 2014

Using INotifyPropertyChanged to Notify Value Change

Recently I start learning more on Windows development so will write more about this topic from now to the near future.

Among the first things that I have learned is how to use INotifyPropertyChanged to raise notification whenever a property value of a single object changes.

How to Implement The Interface
The steps of how to use this interface:
- first we need to inherit our class from this interface
- include the interface's PropertyChanged event property
- write a method to raise value change notification, i.e.; RaisePropertyChanged()
- call that method from each property that we would like it to have this feature
public class User : INotifyPropertyChanged
{
 private string _firstName;

 public string FirstName
 {
  get { return _firstName; }
  set { 
   _firstName = value; 

   // this is the old way to do
   //RaisePropertyChanged("FirstName"); 

   // this is now possible in C# 5 that we don't need to specify the property name
   RaisePropertyChanged();
  }
 }

 public string LastName { get; set; }

 public event PropertyChangedEventHandler PropertyChanged;

 /* // this is the old way to do
 private void RaisePropertyChanged(string propertyName)
 {
  if (this.PropertyChanged != null)
  {
   this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
 }*/

 // this is now possible in C# 5 that we don't need to specify the property name
 private void RaisePropertyChanged([CallerMemberName] string caller = "")
 {
  if (PropertyChanged != null)
  {
   PropertyChanged(this, new PropertyChangedEventArgs(caller));
  }
 }
}

Then on the view we specify the class instance as the data context. One simple way to do this is by initialising it in the view code behind constructor. Note that we are only using the simple way here, not a MVVM approach.
DataContext = user;

Then in our .xaml file we can bind the property(ies) to a control(s).
<StackPanel>
 <TextBlock Text="{Binding FirstName, Mode=OneTime}" HorizontalAlignment="Left"  TextWrapping="Wrap" VerticalAlignment="Top"/>
 <TextBlock Text="{Binding FirstName, Mode=OneWay}" HorizontalAlignment="Left"  TextWrapping="Wrap" VerticalAlignment="Top"/>
 <TextBlock Text="{Binding FirstName}" HorizontalAlignment="Left"  TextWrapping="Wrap" VerticalAlignment="Top"/>
 <TextBox Text="{Binding FirstName, Mode=TwoWay}" HorizontalAlignment="Left" Height="23"  TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
 <Button Content="Button" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="75"/>
</StackPanel>
In the example above, when we try to change the value in the textbox, the new value will be propagated to other controls after we move focus from the textbox. A button is included so that we could click the button after changing the textbox value or press 'tab' key to move the focus away from the textbox.


Binding Modes
Notice that the binding modes specify the direction the change flows:
- TwoWay - data change flows in both directions between source and target properties.
- OneWay - data change only flows from source to target property. This is commonly used for readonly controls.
- OneTime - data change only flows once from source to target property when the control is initialised
- OneWayToSource - the reverse of OneWay mode
- Default - use the default binding mode of the control. If a mode is not specified then the default value is used.
To avoid performance overhead, we should use the mode that is really needed. From the lightest to the heaviest are OneTime, OneWay and TwoWay.


Usage in Collection
If we have a collection of objects which class implements INotifyPropertyChanged then when one of its properties value changes, the change will propagate too. As long as the property raises changes (by calling a raise notification method) like our FirstName property calls RaisePropertyChanged() method, then it will propagate.

Below is a codes example of a collection of users in a List type that will notify change when one of its first names is changed:
<ListView Name="listView1">
 <ListView.ItemTemplate>
  <DataTemplate>
   <WrapPanel>
    <TextBlock Text="{Binding FirstName}" FontWeight="Bold" />
   </WrapPanel>
  </DataTemplate>
 </ListView.ItemTemplate>
</ListView>
<Button Content="Change User" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="100" Click="Button_Click"/>

private List<User> users = new List<User> { new User { FirstName = "first", LastName = "last" }, new User { FirstName = "second", LastName = "last2" } };

public MainWindow()
{
 InitializeComponent();

 listView1.ItemsSource = users;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
 users[0].FirstName = "CHANGED";
}

Friday, 15 August 2014

Bundling and Minification Feature in MVC

On this post we will see how to implement CSS and JavaScript files bundling and minification feature in MVC.

1. Add files
First, we need to add the files inside RegisterBundles() method of App_Start\BundleConfig.cs class. Make sure that our web project has installed Microsoft.AspNet.Web.Optimization library. If not then we can use NuGet to install it.

1.1. Adding CSS files
We use StyleBundle class to add the CSS files. First we specify the bundle name and the relative path where it is going to be generated from. Then we add the intended files to it using relative path url.
StyleBundle cssBundle = new StyleBundle("~/Styles/bundledcss");
cssBundle.Include(
 "~/Styles/mystylesheet1.css",
 "~/Styles/mystylesheet2.css",
 . . .
 );
bundles.Add(cssBundle);

1.2. Adding JavaScript files
This time we use ScriptBundle class. The process is similar as adding CSS files above.
ScriptBundle scriptsBundle = new ScriptBundle("~/Scripts/bundlescripts"); 
scriptsBundle.Include(
 "~/Scripts/myscript1.js",
 "~/Scripts/myscript2.js",
 . . .
);
bundles.Add(scriptsBundle);
We can also use -{version} syntax when including a file. For example; ~/Scripts/jquery-{version}.js
When using this, the '.min' version will be used in release mode and normal version will be used in debug mode. The '-vsdoc' version for IntelliSense will be ignored.

In addition, wildcard character '*', can be used as well when including files to include all matching files.


2. If using Debug mode, set BundleTable.EnableOptimizations
If we want to see bundling and minification in action in debugging mode ('compilation debug="true"' is set in web.config file) then we need to set
BundleTable.EnableOptimizations = true;
otherwise each file will be called individually like before.

In my development environment, I set up a release and a debug build configurations with 'compilation debug="true"' in my web.config. In the Build section of the project properties, the debug build configuration has 'Define DEBUG constant' checked. Then I do
#if !DEBUG
BundleTable.EnableOptimizations = true;
#endif
so that I could have the bundling and minification work when I use release build configuration and off when using debug build configuration.

Below are the complete codes from the steps above.
public class BundleConfig
{
 public static void RegisterBundles(BundleCollection bundles)
 {
  StyleBundle cssBundle = new StyleBundle("~/Styles/bundledcss");
  cssBundle.Include(
   "~/Styles/mystylesheet1.css",
   "~/Styles/mystylesheet2.css",
   . . .
   );
  bundles.Add(cssBundle);

  ScriptBundle scriptsBundle = new ScriptBundle("~/Scripts/bundledscripts"); 
  scriptsBundle.Include(
   "~/Scripts/myscript1.js",
   "~/Scripts/myscript2.js",
   . . .
  );
  bundles.Add(scriptsBundle);

  #if !DEBUG
  BundleTable.EnableOptimizations = true;
  #endif
 }
}

3. Include that method in Application_Start() in Global.asax.cs
protected void Application_Start()
{
 . . .
 BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
 . . .
}

4. Render the bundle on the view
We render the styles bundle with Styles.Render() method and JavaScript files bundle with Scripts.Render() method, passing the same bundle name and path as when it was created.
@Styles.Render("~/Styles/bundledcss")

@Scripts.Render("~/Scripts/bundledscripts")


Files ordering
The optimisation library uses some predefined rules for ordering the files that we include. If we found that our site breaks because of the files were ordered differently from the ones we specify then we need to do a little tweak to override the default ordering. To do this, we need to implement a custom class inherited from IBundleOrderer, then just simply return the files as they are in its OrderFiles() method.
public class AsListedOrderer : IBundleOrderer
{
 public IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
 {
  return files;
 }
}
Then set the custom orderer in our bundle. For example:
public class BundleConfig
{
 public static void RegisterBundles(BundleCollection bundles)
 {
  ScriptBundle scriptsBundle = new ScriptBundle("~/Scripts/bundledscripts"); 
  scriptsBundle.Orderer = new AsListedOrderer();
  scriptsBundle.Include(
   . . .
  );
  . . .
 }
}


What about the minification?
When we are using StyleBundle or ScriptBundle type to create a bundle, the minification feature is already included in it. However if there is a syntax error in one of our files then the minification might not be applied and we could see the warning when we open the bundle uri on a browser to see the content.

If for a reason, we do not want to apply minification in our bundle, then we could use Bundle type instead. In fact, StyleBundle and ScriptBundle types inherit from Bundle type.


Bundle versioning
When the library creates a bundle, it will add calculated hash result of the files content as a querystring. For example; "/Scripts/bundledscripts?v=8mW7h5gn2CgW9MkumYwMSzClMgRORVfdSNBsizgxyoU1"
So if we make a change in our files, the generated hash value will be different. This is another good benefit for us so that we do not need to worry about our content being cached by browsers thus the latest changes will always be rendered.

Friday, 8 August 2014

Some Selenium Code Examples

Below are some Selenium code examples:
var driver = new FirefoxDriver();

// select an option on a dropdown list by its text
new SelectElement(driver.FindElement(By.Id("lstStatus"))).SelectByText("Active");
// another example
driver.FindElements(By.CssSelector("#dvSelectListItems li")).Where(elem => elem.Text.Trim() == "some text").FirstOrDefault().Click();

// get text from a table in its second row and second column
driver.FindElement(By.CssSelector("#tbSearchResults tr:nth-child(2) td:nth-child(2)")).Text

// check whether an element is displayed
driver.FindElement(By.CssSelector("div.accordionContent")).Displayed == false

// fill an input field with text
driver.FindElement(By.Id("Name")).SendKeys("Fullname");

// get a td element that has a particular title attribute value
driver.FindElement(By.CssSelector("td[title='a title']"));

// trick to do hover on a menu
Actions actions = new Actions(driver);
var profileMenu = driver.FindElement(By.LinkText("Profiles"));
actions.MoveToElement(profileMenu);
actions.Click();
actions.Perform(); 

// wait for maximum ten seconds until an element is displayed
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(d => d.FindElement(By.Id("divDashContainer")).Displayed);

// navigate to an url
driver.Navigate().GoToUrl("some url");

Monday, 21 July 2014

TFS 2013 - Limiting Users List in User DropDown

Below is an example of how to limit users in a user selection dropdown:
<field name="Assigned To" refname="System.AssignedTo" type="String" syncnamechanges="true" reportable="dimension">
   <!-- show users that are part of the team only -->
   <validuser group="[Project]\Contributors" />

   <!-- below is another way to do that
   <allowedvalues expanditems="true">
      <listitem value="[Project]\Contributors" />
   </allowedvalues> -->

   <default from="currentuser" />   <!-- this one to have the logged on user to be automatically selected by default -->
</field>

Thursday, 17 July 2014

Modifying and Creating Work Item Type in TFS 2013

To modify a work item type in TFS 2013, we need to these steps:
- export the work item type xml file to our machines
- modify that file
- then import back the modified xml file to the TFS server

To create a new work item type, we need to:
- create a new work item type xml file
- import the new xml file to TFS server

We use Visual Studio Command Prompt to do this.

To export work item type, run this command:
witadmin exportwitd /collection:[team project collection URI] /p:[project_name] /n:[work item type name] /f:[destination file]
examples:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE>witadmin exportwitd 
/collection:"http://myTFSserver/tfs/DefaultCollection" /p:MyProject /n:Bug /f:C:\Users\me\Desktop\bug.xml

C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE>witadmin exportwitd 
/collection:"http://myTFSserver/tfs/DefaultCollection" /p:MyProject /n:"Product Backlog Item" /f:c:\Users\me\Desktop\pib.xml

To import work item type, run this command:
witadmin importwitd /collection:[team project collection URI] /p:[project_name] /f:[source file]
example:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE>witadmin importwitd 
/collection:"http://myTFSserver/tfs/DefaultCollection" /p:MyProject /f:c:\Users\me\Desktop\task.xml

To delete work item type:
witadmin destroywitd /collection:[team project collection URI] /p:[project_name] /n:[work item type name]
example:
witadmin destroywitd /collection:"http://myTFSserver/tfs/DefaultCollection" /p:"My Project" /n:"Impediment"

To rename work item type:
witadmin renamewitd /collection:[team project collection URI] /p:[project_name] /n:[existing work item type name] 
/new:[new work item type name]
example:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE>witadmin renamewitd 
/collection:"http://myTFSserver/tfs/DefaultCollection" /"My Project" /n:"Product Backlog Item" /new:"Enhancement"
Are you sure you want to rename the work item type Product Backlog Item to the new name of Enhancement? (Yes/No) Yes
The work item type was renamed. 

To export process configuration:
witadmin exportprocessconfig /collection:[team project collection URI] /p:[project_name] /f:[destination file]
example:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE>witadmin exportprocessconfig 
/collection:"http://myTFSserver/tfs/DefaultCollection" /p:MyProject /f:c:/Users\me\Desktop\ProcessConfiguration.xml

To import process configuration:
witadmin importprocessconfig /collection:[team project collection URI] /p:[project_name] /f:[source file]
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE>witadmin importprocessconfig  
/collection:"http://myTFSserver/tfs/DefaultCollection" /p:MyProject /f:c:/Users\me\Desktop\ProcessConfiguration.xml


Reference:
MSDN: Import, export, and manage work item types [witadmin]

Thursday, 26 June 2014

Watching Attribute Value with $observe

Below is an example of how to watch for an attribute's value and do something every time it has changed. To do this we would use $observe function.

<!-- origin markup in the view -->
enter a colour: <input class="observe-test" data-ng-model="inputValue" title="{{inputValue}}"/> 
<br />
value typed: <span></span>

// directive codes
myApp.directive('observeTest', function () {
    return {
        restrict: 'C',
        link: function (scope, element, attrs) {
            attrs.$observe('title', function (newValue) {
              attrs.$set('style', 'color:' + newValue);
              element.parent().find('span').text(newValue);
            })
        }
    }
});

See the example in Plunker