Change and Deleted Item Tracking within the Infragistics DataGrid

July 2, 2012

Now that I’m back developing production Line of Business (LOB) applications again, I wanted to share some techniques and challenges that I’ve overcome in our WPF UI.

Our company uses the Infragistics NetAdvantage for WPF product for our WPF UI. We have been very happy with the product, support response and updates. Currently we use the XamRibbon, and XamOutlookBar in our Prism shell; the XamDataChart in our Dashboard; and XamDataGrid in our data entry forms. Our application is in its infancy and as new requirements, features and capabilities are added we will be using more of the controls in the NetAdvantage for WPF full featured suite.

Introduction

For my first post, I thought I would cover an aspect of using the XamDataGrid (all data grids really) that is foundational to LOB applications.

What I’m referring to is tracking the users edits (inserts, updates and deletes) while working in a data grid and then providing the capability to utilize the same database connection to perform the updates, and optionally perform the updates as an atomic transaction.

There are use cases when a user changes data in a data grid, that those changes are immediately reflected back to the database.

Our scenario is one where the design requires that the user be able to make their edits and then commit all the changes all at once. An example of this would be a master-detail use case, when child rows are associated with a master record, e.g. customers, orders, order detail.

In this example, all other development concerns such as data validation, concurrency, actually reading from or writing to a database are not part of the example code; this enables the reader to focus on one technique for tracking inserts, updates, and deletes.

XamDataGrid Requirement

The Infragistics XamDataGrid requires that the data source implement IBindingList in order for the data grid to support adding rows.

Yes, there are techniques for dynamically adding data to your data source without having to do this, but I wanted to allow the data grid to perform its work in a natural way so our data source is derives from BindingList<T>.

Tracking Inserts, Updates and Deletes

When the user deletes a row in the XamDataGrid, the row is removed from the collection and is not longer visible in the UI.

This is where the below ChangeTrackingBindingList<T> comes into play. This class keeps track of the deleted rows by adding a deleted row to an internal collection and then exposing a method (GetDeletedItems) to return those deleted rows when required. If you look below, you’ll see I’ve overridden the RemoveItem method; the implementation adds the deleted row to the internal collection of deleted rows.

It also exposes a method (GetChangedItems) to return only those non-deleted rows that have been inserted or updated.

namespace GridEditing.Infrastructure {
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;

    /// <summary>
    /// Represents the ChangeTrackingBindingList that tracks changes and deleted items.
    /// </summary>
    /// <typeparam name="T">
    /// T: The type of object to provide change tracking binding list services for.
    /// </typeparam>
    public class ChangeTrackingBindingList<T> : BindingList<T> where T : ITrackDirtyEntity {

        IList<T> _deletedItems = new List<T>();

        /// <summary>
        /// Initializes a new instance of the <see cref="ChangeTrackingBindingList{T}"/> class.
        /// </summary>
        public ChangeTrackingBindingList() {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ChangeTrackingBindingList{T}"/> class.
        /// </summary>
        /// <param name="list">The list.</param>
        public ChangeTrackingBindingList(IList<T> list)
            : base(list) {
        }

        /// <summary>
        /// Gets all items in the collection.
        /// </summary>
        /// <returns>
        ///   <see cref="IEnumerable{T}"/> that contains all items from this collection; 
        ///   includes deleted and non-deleted items.
        /// </returns>
        public IEnumerable<T> GetAllItems() {
            return this.Union(_deletedItems).ToList();
        }

        /// <summary>
        /// Gets items that have been changed in the collection.
        /// </summary>
        /// <returns>
        ///   <see cref="IEnumerable{T}"/> that contains items that have been changed; 
        ///   does not include deleted items.
        /// </returns>
        public IEnumerable<T> GetChangedItems() {
            return this.Where(i => i.IsDirty).ToList();
        }

        /// <summary>
        /// Gets the deleted items.
        /// </summary>
        /// <returns>
        ///   <see cref="IEnumerable{T}"/> that contains all items deleted from this collection.
        /// </returns>
        public IEnumerable<T> GetDeletedItems() {
            return _deletedItems;
        }

        /// <summary>
        /// Clears the items.
        /// </summary>
        protected override void ClearItems() {
            base.ClearItems();
            _deletedItems = new List<T>();
        }

        /// <summary>
        /// Sets the item's MarkedAsDeleted property to <c>true</c>. 
        /// Adds the item to the DeletedItems collection. Removes item from list.
        /// </summary>
        /// <param name="index">The index.</param>
        protected override void RemoveItem(Int32 index) {
            var item = this[index];
            _deletedItems.Add(item);
            base.RemoveItem(index);
        }
    }
}

Consuming the ChangeTrackingBindingList<T>

The below MainWindowViewModel exposes the Customers collection. The collection is initialized and customers inserted in the constructor. (please do not populate your collections in your constructors, this is demo-only code)

You’ll notice that after loading the customers, I loop through the collection and set the IsDirty property to false. Your base class for your entity objects should handle this for you, so that when an object is populated from a database, the object is returned from the service layer in a non-dirty state to provide accurate tracking in the UI layer. The below example is over simplified on purpose to show how the view model will process the data once the user saves their changes.

The most important method below is the SaveExecute method that is invoked when the user clicks the Save button. The CanSaveExecute method determines if the collection has been changed or not. Any change to the collection will cause the Save button to be enabled.

Please Note: the code in the SaveExecute method would 99.9999% of the time actually be executing in a service layer. The service layer method would receive the ChangeTrackBindingList<T> as an argument and would use a data layer to process the changes.

Within the SaveExecute method we can see the workflow:

  • Deleted items are removed from the database.
  • Then the inserted or updated items are committed to the database.
  • The view model would then reload the inserted and changed data into the data grid. This reloading refreshing the timestamps that play the role in concurrency and identity columns are populated after an item is inserted and reloaded from the database.
namespace GridEditing {
  using System;
  using System.Diagnostics;
  using System.Linq;
  using System.Windows.Input;
  using GridEditing.Infrastructure;
  using GridEditing.Model;

  public class MainWindowViewModel : ObservableObject {
    ChangeTrackingBindingList<Customer> _customers;
    ICommand _saveCommand;
    Boolean _customersDirty;

    public ChangeTrackingBindingList<Customer> Customers {
      get { return _customers; }
      set {
        _customers = value;
        RaisePropertyChanged("Customers");
      }
    }

    public ICommand SaveCommand {
      get { return _saveCommand ?? (_saveCommand = new RelayCommand(SaveExecute, CanSaveExecute)); }
    }

    public MainWindowViewModel() {
      // load from the service layer
      var list = new ChangeTrackingBindingList<Customer>();
      list.Add(new Customer { FirstName = "Josh", LastName = "Smith", Id = 1 });
      list.Add(new Customer { FirstName = "Sacha", LastName = "Barber", Id = 2 });
      list.Add(new Customer { FirstName = "Brian", LastName = "Lagunas", Id = 3 });
      list.Add(new Customer { FirstName = "Karl", LastName = "Shifflett", Id = 4 });
      foreach (var customer in list) {
        customer.IsDirty = false;
      }
      this.Customers = list;
      this.Customers.ListChanged += (s, e) => _customersDirty = true;
    }

    Boolean CanSaveExecute() {
      return _customersDirty;
    }

    void SaveExecute() {
      // call the service layer, passing the DeleteMarkingBindingList<Customer>
      // the service layer will loop through each item, and either insert it, update it, delete it, 
      // or discard.
      // this is demo code only, but demonstrates the workflow

      foreach (var customer in this.Customers.GetDeletedItems()) {
        // if the Id property is zero then the service layer does not have to do anything
        // if the Id property is greater than zero, the service layer will delete the item.
        // simulate removing from the data base
        Debug.WriteLine(
          String.Format("Customer deleted: {0} {1}", customer.FirstName, customer.LastName));
      }

      foreach (var customer in this.Customers.GetChangedItems()) {
        if (customer.Id == 0) {
          // perform insert in service layer
          customer.Id = this.Customers.Max(c => c.Id) + 1;
          // simulate inserting into the data base
          Debug.WriteLine(
            String.Format("Customer inserted: {0} {1}", customer.FirstName, customer.LastName));
        } else {
          // perform update in service layer
          // simulate updating the data base
          Debug.WriteLine(
            String.Format("Customer updated: {0} {1}", customer.FirstName, customer.LastName));
        }
      }

      // reload the updated records from the database
      // simulate getting all records from the database

      _customersDirty = false;
    }
  }
}

Running the Application

When the application is initially spun up, the Save button will be disabled since no inserts, updates or deletes have taken place.

DisabledButton

After a row has been inserted, the Save button is enabled.

EnabledButton

To the initial data, the following changes have been made.

ChangesMade

When the Save button is clicked, notice the Debug output window. Each of the requested operations are performed; these operations are easily driven by the ChangeTrackingBindingList<T>.

DebugOutputWindow

After the Save is completed, the UI will be updated as below, the Id field has been populated and the Save button is disabled again.

UpdatedRecords

UI XAML – XamDataGrid Tips

The Infragistics XamDataGrid really makes it easy for developers to deliver a full-featured data grid editing experience. This example does not even scratch the surface of the many capabilities of the data grid. In future posts I’ll demonstrate some real-world scenarios with respect to the XamDataGrid’s UI capabilities, for now, let’s stick with tracking the users edits and updating the database.

Tips

1.  By default the XamDataGrid will set string properties to null if the user enters a blank or empty string in the data grid. This is not the behavior I want, instead I need an empty string. This is accomplished using a no-op converter.

Infragistics has made applying the no-op converter a snap by setting ValueToTextConverter property on the XamTextEditor using a style as I’ve done below. In the XamDataGridNullStringPreventionConverter’s Convert and ConvertBack methods I simply return value. The causes the XamDataGrid to set string properties to an empty string instead of the null value.

2.  Take a look down at the XamDataGrid.FieldSettings, you’ll notice CellClickAction has been set to EnterEditModeIfAllowed. The user no longer has to double click a cell to get into edit mode, simply clicking the cell, will put the cell in edit mode.

3.  Making an Id field read-only is straightforward. Have a look at the Id field in the XamDataGrid’s FieldLayout. By setting Id columns FieldSettings.AllowEdit to false, the cells are read-only.

<Window 
    xmlns:local="clr-namespace:GridEditing"
    xmlns:infrastructure="clr-namespace:GridEditing.Infrastructure"
    x:Class="GridEditing.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Data Grid Editing and Deleting" 
    Height="341" 
    Width="608" 
    ResizeMode="NoResize"
    xmlns:igDP="http://infragistics.com/DataPresenter" 
    xmlns:igEditors="http://infragistics.com/Editors">
  <Window.DataContext>
    <local:MainWindowViewModel />
  </Window.DataContext>
  <Window.Resources>
    <infrastructure:XamDataGridNullStringPreventionConverter 
      x:Key="XamDataGridNullStringPreventionConverter" />
  </Window.Resources>
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock Text="Infragistics Data Grid Editing and Deleting" Margin="11" FontSize="18" />
    <igDP:XamDataGrid 
      Grid.Row="1" Margin="11" 
      DataSource="{Binding Path=Customers}" IsNestedDataDisplayEnabled="False">
      <igDP:XamDataGrid.Resources>
        <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}" >
          <Setter Property="Margin" Value="0" />
        </Style>
        <!--this style is required to prevent null strings from being sent to the model-->
        <Style TargetType="{x:Type igEditors:XamTextEditor}" >
          <Setter 
            Property="ValueToTextConverter" 
            Value="{StaticResource XamDataGridNullStringPreventionConverter}" />
        </Style>
      </igDP:XamDataGrid.Resources>
      <igDP:XamDataGrid.FieldSettings>
        <igDP:FieldSettings CellClickAction="EnterEditModeIfAllowed" />
      </igDP:XamDataGrid.FieldSettings>
      <igDP:XamDataGrid.FieldLayoutSettings>
        <igDP:FieldLayoutSettings 
                    SupportDataErrorInfo="None"
                    DataErrorDisplayMode="None" 
                    AutoGenerateFields="False"
                    AddNewRecordLocation="OnBottom" 
                    AllowAddNew="True" 
                    AllowClipboardOperations="All" 
                    AllowDelete="True" 
                    ExpansionIndicatorDisplayMode="Never" />
      </igDP:XamDataGrid.FieldLayoutSettings>
      <igDP:XamDataGrid.FieldLayouts>
        <igDP:FieldLayout>
          <igDP:FieldLayout.SortedFields>
            <igDP:FieldSortDescription FieldName="Id" Direction="Ascending" />
          </igDP:FieldLayout.SortedFields>
          <igDP:Field Name="Id">
            <igDP:Field.Settings>
              <igDP:FieldSettings AllowEdit="False" />
            </igDP:Field.Settings>
          </igDP:Field>
          <igDP:Field Name="FirstName" Width="200" />
          <igDP:Field Name="LastName" Width="200" />
        </igDP:FieldLayout>
      </igDP:XamDataGrid.FieldLayouts>
    </igDP:XamDataGrid>

    <Button 
      Width="65" Margin="7" Grid.Row="2" Content="Save" 
      Command="{Binding Path=SaveCommand}" HorizontalAlignment="Right"/>

  </Grid>
</Window>

Download

After downloading change the extension from .zip.DOC to .zip. This is a requirement of WordPress.

Download Demo Application (25K)

Requirements

To run the demo application, you’ll need to get the Infragistics NetAdvantage for WPF. A demo version is available here.

Close

There are business frameworks like CSLA that have trackable objects and handle the above scenarios I’ve shown. Currently, I prefer to the simplest solution possible and use the above for tracking user changes within the XamDataGrid.

You can see the amount of very simple code to enable this scenario is small, easy to understand and implement.

Have a great day,

Just a grain of sand on the worlds beaches.


Coding Signing Internal Applications and a Gotcha

April 16, 2012

This blog post explains one way to code sign your internal applications along with their installers. Code signing your applications and installers provide a UAC friendly user experience during installation, uninstall, and when your legacy applications may need to run with administrative privileges (more about admin privileges below).

UAC Friendly Installation Experience

The below image pictures a user friendly UAC dialog, complete with Program name, Verified publisher. If you internal applications are not code signed, the user will get a warning dialog, with a bizarre program name, and Verified publisher set to unknown.

I don’t know about you, but I would rather condition my users to see UAC friendly dialogs, rather than the warning dialog. Next thing you know, they have “accidently” approved a UAC warning that could cause you a big problem.

InstallationUAC

If you are signing applications that are not internal to your organization, the content surrounding certificates and the guidance surrounding signtool.exe may violate your organizations code signing rules or procedures.

This blog post is about code signing internal applications that will be used within your organization.

Code Signing Certificate

The first order of business is to get a code signing certificate installed on machines that will build your internal applications. You can see from the below image, that my certificate server gmcx-Security-CA has issued a code signing certificate and that I have imported that certificate into the “Personal” Store under the “Certificates” folder.

To be honest, creating a code signing certificate that did not have my name on it, instead had our organization’s name is was bit of a PIA and required creating a certificate template on the certificate server that allowed me to do this. I found this TechNet article very helpful:

http://technet.microsoft.com/en-us/library/cc731705(v=ws.10).aspx

Certificate Manager

After you create the certificate, export it and import it on all machines under the users “Personal” store as above.

For example, I have this certificate installed on our two developer machines and on the build server.

Configuring the Solution (executable projects)

There are several ways to configure actions that take place during MSBuilds. I have chosen the “batch file” method because it is very easy to implement and debug. You could leverage one of two out-of-the-box build Tasks or create your own build task, but I chose “batch files” for the above reasons.

Notice that I have checked these batch files into source control. This ensures that all machines can build the solution correctly.

ProjectBatchFiles

AfterBuildTasksDebug.bat

If your scenario requires code signing the debug build, the below batch file uses the signtool.exe program to code sign the .exe program. You “could” also pass in command line parameters to the batch file that would include the folder name of the target along with the target name.  I’ve kept this simple to make it easier to understand all the pieces.

Notice that I didn’t have to specify a certificate, password, etc.  This is because I only have one code signing certificate installed on my machine.  The “/a” switch instructs signtool to automatically pick the code signing certificate from my “Personal” store.

@echo on

call “C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat”

call signtool sign /a “C:\Projects\GMC\Src\GMC\bin\Debug\GMC.exe”

AfterBuildTasksRelease.bat and the Gotcha

Now time for a nasty gotcha. This little beast cost me about 2 hours trying to figure out why, every time I did a Release build using the Setup project to build and create the install package that the .exe the installer installed was not longer signed.

Read this thread on the Windows Dev Center for full details:

Setup project strips digital signature from exe target

Now that you have read the above thread, you’ll fully understand why when creating a release build, you must code sign the .exe under the \obj and \bin folders.

The signtool… commands sign my .exe. Let me call out one additional signtool switch you need to mind when signing your .exe.

You should also specify the “/t” switch. This will time stamp your .exe so the user knows when the .exe was built.

@echo on

call “C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat”

call signtool sign /a /t http://timestamp.comodoca.com/authenticode
   “C:\Projects\GMC\Src\GMC\obj\Release\GMC.exe”

call signtool sign /a /t http://timestamp.comodoca.com/authenticode
   “C:\Projects\GMC\Src\GMC\bin\Release\GMC.exe”


Configuring Visual Studio 2010 to Use the above Batch Files During a Build

BuildEvents

  • Open the Build Events dialog from the .exe project’s properties tab.
  • Change the “Run the post-build event” option to “When the build updates the project output.”
  • Enter the above text in the “Post-build event command line” text box.

This will run one of the two batch files based on the configuration, Debug or Release.

Building the Solution

Like many of you, I don’t build my Release builds within Visual Studio.  Some use a build server, others build them from the command line to allow other tasks to be accomplished.

Below is a fragment of a batch file that I use when building a release build.  The devenv… command rebuilds my solution. Notice the “/rebuild” switch instead of the “/build” switch.

The signtool… command signs my .msi installer that the Setup project built. Let me call out two additional signtool switches you need to mind.

It is important that you specify the “/d” switch for your .msi installers. If you scroll back up to the top of this blog post and view the UAC image, you’ll notice the Program name matches the text in the below “/d” switch. If you don’t specify this, your user will see some bizarre text.

You should also specify the “/t” switch. This will time stamp your installer so the user knows when the installer was built.

@echo on

call “C:\Program Files\Microsoft Visual Studio 10.0\VC\vcvarsall.bat”

devenv /rebuild Release /project GMC_Setup C:\Projects\GMC\Gmc.sln

echo .
echo .
pause

signtool sign /a /d “GMC for Office 2010 Setup” /t http://timestamp.comodoca.com/authenticode
   C:\Projects\GMC\Src\GMC_Setup\Release\GMCForOffice2010_Setup.msi

… additional tasks

Legacy Applications Running on Windows 7 and Above

My company has a legacy Windows Forms application that was written during the days of Windows XP.  My company like many other enterprises never installed Windows Vista.  Recently we installed Windows 7 on our enterprise desktops.

Well the legacy enterprise applications I’ve inherited do things are are not UAC friendly.  For example, writing to the \Program Files folder and other tasks that are now under Windows 7 considered taboo.

Being a good Enterprise Administrator and Developer, I want all my clients running Windows 7 with UAC set to the Default setting and for my users to learn about the UAC feature and its benefits; this will provide them a safer computing environment here at work and at home.

Microsoft has documented UAC here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa511445.aspx  

Microsoft and bloggers have documented a number of strategies for dealing with UAC and legacy applications.  Turning UAC off or limiting its capabilities should not be considered a good option.

I was not willing to take on the risk of modifying our legacy applications, so I run my few enterprise applications with an embedded application manifest that tells the operating system this application requires administrator privileges to execute. All of our users are administrators on their local computer.

Example Application Manifest

Notice the the below application manifest that the “requestExecutionLevel” is “requireAdministrator.”

<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<assembly xmlns=”urn:schemas-microsoft-com:asm.v1″ manifestVersion=”1.0″>
  <assemblyIdentity version=”1.0.0.0″ processorArchitecture=”X86″ name=”GMC” type=”win32″/>
  <trustInfo xmlns=”urn:schemas-microsoft-com:asm.v3″>
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level=”requireAdministrator”/>
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

To embed the above application manifest you need to use the mt.exe program. I placed the below command at the top of my two batch files, AfterBuildTasksDebug.bat and AfterBuildTasksRelease.bat.

You’ll need to edit the paths and .exe name as well as the manifest name.

call “C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\mt.exe” -manifest
   “C:\Projects\GMC\Src\GMC\GMC.exe.manifest”
   -outputresource:”C:\Projects\GMC\Src\GMC\bin\Debug\GMC.exe;#1″

Close

For those of you that have the need or desire to code sign your internal enterprise applications, I hope this blog post will help you avoid the long learning curve.

Have a great day,

Just a grain of sand on the worlds beaches.


IE9 Pinned Site Jump List Items Not Displaying Consistently Across Computers

May 29, 2011

Those following my blog know that I’ve been working on the Microsoft patterns & practices Web Guidance team and we are using Project Silk as the basis for delivering our web guidance.

One of the early project work items was to demonstrate IE9 windows shell integration or pinned sites. Project Silk has a nice pinned sites experience that includes static and dynamic jump list items as well as dynamic notification icons.

The dynamic jump list items and notification icons are driven by the number of overdue maintenance reminders the currently logged in user needs to attend to.

Our team had a lingering problem with the dynamic jump lists; they were not displaying consistently across team member computers. As you can imagine, this was a source of frustration since the feature is actually cool and requires very little in the way of code to implement.

I got up early this morning and started writing the Application Notifications chapter which includes our implementation of IE9 pinned sites. I’ve not been able to see the dynamic jump list items on my laptop or home computers. I spent about an hour debugging our JavaScript, hoping to find something wrong. No such luck.

Others on the Internet have reported similar problems with solutions ranging from disabling all shell extensions, to clearing out the jump list folders. (Not something I want to recommend to users of Project Silk.)

Turns out, the displaying of jump list items is tied to a Taskbar and Start Menu Properties dialog setting, “Store and display recently opened items in the Start menu and the taskbar.”

Required Configuration for Jump List Items to Display

If you’re like me and don’t want Windows adding items to an already busy start menu, you turn off both of the below options. However, for jump lists to work, you’ll need to enable the second option.

RequiredConfiguration

Not sure why jump list item displaying is tied to this setting, will have to inquire about this.

BadConfiguration

Close

You can follow Project Silk, provide feedback on the code and book chapters here.

Have a great day,

Just a grain of sand on the worlds beaches.


In the Box – MVVM Training

November 7, 2010

Updated 12 Nov 2010

InTheBox

What is In the Box?

In the Box is a high quality, multi-media training that is consumed within Visual Studio 2010.  Content is navigated and delivered using a next generation computer based training (CBT) experience, the Visual Studio 2010 Feature Extension.

In the Box, is a brand name for a series of CBT Feature Extensions I’ll release that are listed in the Visual Studio 2010 Add New Project dialog; see below image.  This release is MVVM Training, the next will be Prism Training.

In the Box features:

  • Visual Studio 2010 Feature Extension
  • Content delivered as text, code, images, diagrams, video, or hyperlinks to the Internet
  • Hierarchical navigation tool window for content navigation
  • Content is viewed inside Visual Studio 2010 tool windows
  • No additional downloads or dependencies; all content is in the box.  (except online videos)
  • Installed and updated from the Visual Studio Gallery
  • Managed (disabled or uninstalled) using Visual Studio Extensions Manager (see bottom of this page)
  • Authored using Microsoft Word and the Instant Feature Builder

What is in this release of In the Box?

Please watch this video as it will answer most of your questions.

This installment of In the Box contains in-depth MVVM Training that includes an eleven assembly example solution with projects targeting developers at different levels of experience

Who is the target audience?

  • If you have never used MVVM before, this training is for you. 
  • If you have been using MVVM for a while and want to learn more, this training is for you. 
  • If you are an expert, you will enjoy the MVVM Technical Description and MVVM Scenarios content.

What are the requirements to install In the Box?

Visual Studio 2010 Professional, Premium, or Ultimate.

Expression Blend 4 WPF SDK – Free download (see below comment on SDK) (Note: this is installed with Blend also)

For those developers using Visual Studio 2010 Express or Visual Studio 2008, you can use the links in the below download section to download a .mht version of the content along with the sample solution source.  The .mht file can be viewed in your browser by double clicking the file in Windows Explorer.

Please note: I have not tested this solution with the Express version.

Windows XP and Windows Server 2003 Users

In order to run Feature Builder on either XP or Server 2003 you must create an environment variable named LocalAppData (set by default on Windows Vista and Windows 7).

How to Add LOCALAPPDATA variable in Windows XP:

  • Right-click on the My Computer icon and choose Properties
  • Click Advanced
  • Click Environment Variables
  • Under User variables section, click New
  • In the Variable name: field, type LOCALAPPDATA
  • In the Variable value: field, type %USERPROFILE%\Local Settings\Application Data

How do I install In the Box?

Click on this Visual Studio Gallery Link and install from there.

After I install it, how do I get started?

Open Visual Studio 2010; File, New Project, Visual C#, In the Box, MVVMTraining.

NewProject

Videos

In the Box – MVVM Training Introduction video

You can view the above video using the web browser plug in, or you can download and watch an HD version of the video.  To download the HD version of the video, locate the, “About this video” section (lower right side of web page) and join Vimeo; it’s free and very quick to join.

Vimeo

Downloads

In the Box – MVVM Training on the Visual Studio Gallery

Visual Studio Express and Visual Studio 2008 Developers download the written content and sample application from my:

SkyDrive click here to download.

Note the link is to a folder; you will want to download both .zip files in the folder.

Expression Blend 4 SDK Requirement

I received a report from a developer having a problem with two references to the Expression Blend 4 SDK in two of the included projects.

I thought for awhile about including just these two DLL’s, but thought that would be a disservice, only providing two DLL’s.  I have opted to add the Expression Blend 4 SDK as a requirement because a high percentage of developers already have the SDK installed by Blend or by downloading it.

Have a great day,

Just a grain of sand on the worlds beaches.


Visual Studio 2010 WPF Trace Settings Default Is Incorrect

June 24, 2010

A few weeks ago I found that after setting the attached property PresentationTraceSources.TraceLevel=High on a binding, I was not getting the expected verbose output.

You can see an obvious error in the Path property name. 

<TextBlock 
    Text="{Binding diag:PresentationTraceSources.TraceLevel=High,  
            Path=XCustomerID}" />

Using the above in WPF 3.5 SP1 would result in many messages being outputted in the Debugger Output Window.

However, in Visual Studio 2010 WPF 4.0 I was only seeing the below single binding error:

System.Windows.Data Error: 40 : BindingExpression path error: ‘XCustomerID’ property not found on ‘object’ ”ListCollectionView’ (HashCode=55179487)’. BindingExpression:Path=XCustomerID; DataItem=’ListCollectionView’ (HashCode=55179487); target element is ‘TextBlock’ (Name=’CustomerIDTextBlock’); target property is ‘Text’ (type ‘String’)

The reason the expected messages are not being outputted is because the installation default setting of the WPF Trace Settings is “Error” and not “Warning.”  When set to “Error”, no “Warning” messages will be outputted.

To enable the PresentationTraceSources.TraceLevel messages to be seen, you need to change your Tools, Options, Debugging, Output Window, WPF Trace Settings, Data Binding value to Warning as I’ve done in the below image.

ToolsOptionsDataBinding

Have a great day writing your applications!,

Just a grain of sand on the worlds beaches.


Fast and Easy Navigation in WPF or Silverlight Applications in Visual Studio 2010

March 30, 2010

In Visual Studio 2010, the Navigate To command is CTRL+,  (comma).

If you have any text selected in any editor and press  CTRL+,  that text is automatically added to the Search Terms field and the Navigate To dialog immediately presents a list of objects in your solution that match the search.  Pressing CTRL+, without text selected opens the Navigate To dialog without pre-setting the search text or the results listing.

In the below image, I have highlighted a type’s name in the XAML Editor, pressed CTRL+, and presto, I can easily navigate to objects that match the search string.

ControlComma

For large WPF projects, CTRL+, will save you so much time fishing around in the Solution Explorer.

Final note, this feature works in all editors such as the VB and C# code editors, XAML Editor, etc.

Have a great day!

Just a grain of sand on the worlds beaches.


Visual Studio 2010 – Visual Basic New Feature – NonSerialized Events

November 17, 2009

A long time feature request has been added to Visual Basic 10 that ships with Visual Studio 2010; decorating an Event as NonSerialized.

In prior versions of Visual Basic developers had to implement a Custom Event or another workaround when their types needed to expose an Event and they had to be Serializable.  C# had this capability, now Visual Basic does too!

A very common scenario is a class that implements INotifyPropertyChanged and must also be Serializable. 

Visual Basic developers can now decorate the Event with the NonSerialized attribute.  The compiler does the rest for you.

Imports System.ComponentModel

<Serializable()>
Public Class Customer
    Implements INotifyPropertyChanged

#Region " INotifyPropertyChanged Serializable "

    'New VB 10 feature!
    <NonSerialized()>
    Public Event PropertyChanged(
                  ByVal sender As Object,
                  ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
                  Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Protected Sub OnPropertyChanged(ByVal strPropertyName As String)
        If Me.PropertyChangedEvent IsNot Nothing Then
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(strPropertyName))
        End If
    End Sub

#End Region

End Class

Have a great day,

Just a grain of sand on the worlds beaches.


Follow

Get every new post delivered to your Inbox.

Join 248 other followers