Category Archives: .Net

Microsoft .Net Framework

Syncfusion’s latest datagrid

I’ve been looking forward to Syncfusion’s latest release of their Silverlight components (and it’s out today). In particular, their new SfDataGrid datagrid is reaching maturity so I decided to take it out for a quick spin, and verdict is out. Two thumbs up. Well done. Their API is intuitive and much improved from their original DataGrid. It is different, so don’t expect to be able to port over existing code easily, but there is considerably less code to port.

We’ll start off with a simple model

namespace SyncfusionGridDemo.ViewModels
{
    using System.ComponentModel.DataAnnotations;

    public class Customer
    {
        [Display(Name="Full Name")]
        [Required(ErrorMessage="{0} is required")]
        public string FullName { get; set; }

        [Range(18, 80)]
        public int Age { get; set; }
    }
}

As you can see there is not much to it, and we’ll create a viewmodel and host a collection of Customers.

namespace SyncfusionGridDemo.ViewModels
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;

    public class MainPageViewModel
    {
        private IList<Customer> _addedCustomers = new List<Customer>();
        private IList<Customer> _deletedCustomers = new List<Customer>();

        public MainPageViewModel()
        {
            Customers = new ObservableCollection<Customer>(new[]
            {
                new Customer { FullName = "Marcus Aurelius", Age=30 },
                new Customer { FullName = "Dana Fausbinder", Age=3 },
                new Customer { FullName = "Tomoko Cressida McManus", Age=54 },
            });
            Customers.CollectionChanged += Customers_CollectionChanged;
        }

        void Customers_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    // TODO these will need to be saved to the database
                    _deletedCustomers.RemoveRange((IEnumerable<Customer>)e.NewItems);
                    _addedCustomers.AddRange<Customer>((IEnumerable<Customer>)e.NewItems);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    _addedCustomers.RemoveRange((IEnumerable<Customer>)e.NewItems);
                    _deletedCustomers.AddRange<Customer>((IEnumerable<Customer>)e.NewItems);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    // TODO these will need to be saved to the database
                    _deletedCustomers.RemoveRange((IEnumerable<Customer>)e.OldItems);
                    _addedCustomers.RemoveRange((IEnumerable<Customer>)e.OldItems);
                    _addedCustomers.AddRange<Customer>((IEnumerable<Customer>)e.NewItems);
                    break;

            }

        }

        public ObservableCollection<Customer> Customers { get; set; }
    }

    public static class CollectionExtension
    {
        public static void AddRange<T>(this IList<T> coll, IEnumerable<T> items)
        {
            foreach (var item in items)
            {
                if (!coll.Contains(item))
                    coll.Add(item);
            }
        }

        public static void RemoveRange<T>(this IList<T> coll, IEnumerable<T> items)
        {
            foreach (var item in items)
            {
                if (coll.Contains(item))
                    coll.Remove(item);
            }
        }


    }
}

And now let’s bind to Syncfusion SfDataGrid


        <Grid:SfDataGrid 
            AllowEditing="True" 
            Grid.Row="1" 
            ItemsSource="{Binding Customers}" 
            x:Name="SampleGrid" 
            GridValidationMode="InEdit" 
            AddNewRowPosition="Top"/>

and the result is rather good for so little work.

Some minor criticism

The datagrid is not aware of IEditableObject interface. This interface supports BeginEdit(), EndEdit() and CancelEdit(). This allows the user to revert the record’s changes using the escape key.

Overall, the user experience is much improved. Thanks again for listening to my concerns.

Succeeding with Windows Phone Apps

Take aways:

  1. Add all screenshots
  2. Provide background image – or it will not get featured in the Store
  3. Description is super important especially the first few sentences

Make use of

  1. Live Tiles
  2. Lock Screen
  3. Toast Notification
  4. SkyDrive
  5. Wallet
  6. Caching
  7. Location Services

Live Tiles

  1. 159 x 169
  2. 336 x 336
  3. 691 x 336

There are three type of templates

  1. Flips to the back. So the most important info should be on the front
  2. Cycle template of 9 images – but don’t make user wait.
  3. Iconic template small icons
    1. 110×110 for small
    2. 202 x 202 for Medium.
    3. Wide uses the small icon

Effective Design-Time data with Silverlight

There were quite a few ways one can enable Silverlight design time data binding. Design time data binding provides the GUI designer with some sample values and this is particularly handy when laying out controls in Visual Studio.

Using d:DataContext and d:DesignInstance

<Grid x:Name="LayoutRoot" Background="White"
  d:DataContext="{d:DesignInstance
  Type=local:Customer}">
</Grid>

Note: You can also do this:

<Grid x:Name="LayoutRoot" Background="White"
  d:DataContext="{d:DesignInstance
  Type=local:Customer,
  CreateList=True}">
</Grid>

Using d:DesignData

<StackPanel
  d:DataContext="{d:DesignData
  Source=./DesignData/SampleCustomer.xaml}">

Note: the Build action should be DesignData or DesignDataWithDesignTimeCreatableTypes

Using d:DesignSource (for CollectionViewSource)

If your model binds to a CollectionViewSource, you can set it in conjunction with DesignInstance.

<CollectionViewSource x:Key="CustomerViewSource"
  d:DesignSource="{d:DesignInstance
  local:Customer, CreateList=True}" /> 

MEF, Caliburn and loading xap files

This the following modification to MefBootstrapper allows us to load XAPs at runtime, and register the types with Caliburn.Micro so that it can locate the correct view for a given view model.

using Caliburn.Micro;

namespace SlCaliburnTest
{
    using Extensions;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.ComponentModel.Composition.Primitives;
    using System.ComponentModel.Composition.ReflectionModel;
    using System.Linq;
    using System.Threading.Tasks;

    public class MefBootstrapper : Bootstrapper<IShell>
    {
        private CompositionContainer container;

        protected override void Configure()
        {
            container = CompositionHost.Initialize(
                new AggregateCatalog(
                    AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
                    )
                );

            var batch = new CompositionBatch();

            batch.AddExportedValue<IWindowManager>(new WindowManager());
            batch.AddExportedValue<IEventAggregator>(new EventAggregator());
            batch.AddExportedValue(container);

            container.Compose(batch);
        }

        protected override object GetInstance(Type serviceType, string key)
        {
            string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
            var exports = container.GetExportedValues<object>(contract);

            if (exports.Count() > 0)
                return exports.First();

            throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
        }

        protected override IEnumerable<object> GetAllInstances(Type serviceType)
        {
            return container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
        }

        protected override void BuildUp(object instance)
        {
            container.SatisfyImportsOnce(instance);
        }

        #region Xap

        public async Task<bool> AddXap(Uri uri)
        {
            var catalog = (container.Catalog as AggregateCatalog);
            DeploymentCatalog deploymentCatalog;
            lock (catalog.Catalogs)
            {
                if (catalog.Catalogs.Any(c => (c is DeploymentCatalog && (c as DeploymentCatalog).Uri == uri)))
                    return false;

                deploymentCatalog = new DeploymentCatalog(uri);
                deploymentCatalog.Changing += (s, e) =>
                {
                    // It is necessary to Update AssemblySource before deploymentCatalog Changed is fired.
                    // 1. deploymentCatalog.Changed even triggers Recomposition, 
                    // 2. Recomposition triggers ViewLocator to load the View
                    // 3. ViewLocator uses AssemblySource to find the assembly the view belongs to.
                    UpdateAssemblySource(e.AddedDefinitions);
                };
                catalog.Catalogs.Add(deploymentCatalog);
            }            
            var downloadSuccess = await deploymentCatalog.Download();
            return downloadSuccess;
        }

        private void UpdateAssemblySource(IEnumerable<ComposablePartDefinition> parts)
        {
            var assemblies = from assembly in 
                                  (from p in parts
                                   select ReflectionModelServices.GetPartType(p).Value.Assembly)
                              where !AssemblySource.Instance.Contains(assembly)
                              select assembly;                             
            foreach (var assembly in assemblies.Distinct())
            {
                AssemblySource.Instance.Add(assembly);
            }
        }

        #endregion
    }
}

Syncfusion DataGrid – prevent automatic sorting after edit

There are two ways to prevent a Syncfusion DataGrid control from reordering your grid after you modify an item.

  1. Disable sorting after edits
    dataGrid1.ModelLoaded += (sender, eventArgs) =>
    {
        dataGrid1.Model.TableProperties.SortingOptions = 
            Syncfusion.Windows.Data.SortingOptions.DisableSortingOnEdit;
    };
    
  2. Change the ActivateCurrentCellBehavior to SetCurrent
            <s:GridDataControl ItemsSource="{Binding EquipmentParts}" 
                               AllowEdit="True"
                               ShowAddNewRow="True"
                               x:Name="dataGrid1"
                               NotifyPropertyChanges="True"
                               IsGroupsExpanded="True"
                               ShowFilters="True"
                               ShowRowHeader="True"             
                               AutoPopulateColumns="False" 
                               ActivateCurrentCellBehavior="SetCurrent"   />
    

Elmah Logging Full Stack Trace of WCF DomainServiceFault

Problem

By default, only a partial stack trace is logged to Elmah when a WCF Exception occurs. This is not helpful when trying to troubleshoot problems.

Reason

Elmah logs exception.ToString() – which in the case of a DomainServiceFault, only contains partial stack trace.

Solution

The solution is to wrap the exception in another one so that we can override ToString().

''' File: ElmahWcfExtensions
''' Usage: Decorate the DomainService with ServiceErrorBehavior and ServiceBehavior(IncludeExceptionDetailInFaults:=True)
''' Example:
'''    <ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults:=True)>
'''    <RequiresAuthentication()> _
'''    <EnableClientAccess()> _
'''    <ServiceErrorBehaviour(GetType(HttpErrorHandler))>
'''    Public Class SamDomainService

Option Compare Binary
Option Infer On
Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ServiceModel
Imports System.ServiceModel.Description
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Channels

Namespace Web

    ''' <summary>
    ''' Your handler to actually tell ELMAH about the problem.
    ''' </summary>
    Public Class HttpErrorHandler
        Implements IErrorHandler

        Public Sub ProvideFault([error] As Exception, version As MessageVersion, ByRef fault As Message) Implements IErrorHandler.ProvideFault
            If [error] IsNot Nothing Then
                ' Notify ELMAH of the exception.
                If System.Web.HttpContext.Current Is Nothing Then
                    Dim elmahCon As Elmah.ErrorLog = Elmah.ErrorLog.GetDefault(Nothing)
                    elmahCon.Log(New Elmah.Error([error]))
                Else
                    Elmah.ErrorSignal.FromCurrentContext().Raise(ServiceFault.From([error]), System.Web.HttpContext.Current)
                End If
            End If
        End Sub

        Public Function HandleError([error] As Exception) As Boolean Implements IErrorHandler.HandleError
            Return False
        End Function

    End Class

    ''' <summary>
    ''' So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
    ''' ...and errors reported to ELMAH
    ''' </summary>
    Public Class ServiceErrorBehaviourAttribute
        Inherits Attribute
        Implements IServiceBehavior
        Private errorHandlerType As Type

        Public Sub New(errorHandlerType As Type)
            Me.errorHandlerType = errorHandlerType
        End Sub

        Public Sub Validate(description As ServiceDescription, serviceHostBase As ServiceHostBase) Implements IServiceBehavior.Validate

        End Sub

        Public Sub AddBindingParameters(description As ServiceDescription, serviceHostBase As ServiceHostBase, endpoints As Collection(Of ServiceEndpoint), parameters As BindingParameterCollection) Implements IServiceBehavior.AddBindingParameters
        End Sub

        Public Sub ApplyDispatchBehavior(description As ServiceDescription, serviceHostBase As ServiceHostBase) Implements IServiceBehavior.ApplyDispatchBehavior

            Dim errorHandler As IErrorHandler
            errorHandler = DirectCast(Activator.CreateInstance(errorHandlerType), IErrorHandler)
            For Each channelDispatcherBase As ChannelDispatcherBase In serviceHostBase.ChannelDispatchers
                Dim channelDispatcher As ChannelDispatcher = TryCast(channelDispatcherBase, ChannelDispatcher)
                channelDispatcher.ErrorHandlers.Add(errorHandler)
            Next
        End Sub

    End Class

    ''' <summary>
    ''' ServiceFault wrapper so that the entire stack trace is logged.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class ServiceFault
        Inherits FaultException

        Friend _faultException As Exception
        Private Sub New(faultException As Exception)
            _faultException = faultException
        End Sub

        Public Shared Function From(faultException As Exception) As FaultException
            Return New ServiceFault(faultException)
        End Function

        Public Overrides ReadOnly Property Message As String
            Get
                Return _faultException.Message
            End Get
        End Property

        Public Overrides Property Source As String
            Get
                Return _faultException.Source
            End Get
            Set(value As String)
                MyBase.Source = value
            End Set
        End Property

        Public Overrides Function ToString() As String
            Dim faultExc As FaultException(Of DomainServiceFault) =
                TryCast(_faultException, FaultException(Of DomainServiceFault))

            If faultExc Is Nothing Then
                Return _faultException.StackTrace()
            Else
                ' DomainServiceFault stores its stacktrace in a 
                ' different location
                Return faultExc.Detail.StackTrace()
            End If
        End Function

    End Class
End Namespace

Silverlight Tiled Image Brush

HTML has repeat-x and repeat-y for years but Silverlight hasn’t managed to catch up. It’s elder sibling, WPF, has an ImageBrush which supports TileMode such as Tile, FlipX, FlipXY, FlipY.

This is rather handy if you want textured UI which is now common through out the web.

<!-- wpf only, this is not supported in Silverlight -->
<ListBox>
  <ListBox.Background>
     <ImageBrush ImageSource="grey_wash_wall.png" 
        TileMode="Tile" 
        Stretch="None" 
        ViewportUnits="Absolute" 
         Viewport="0,0,350,259"/>
      </ListBox.Background>
</ListBox>        

With a bit of help from existing code on pixel shaders (see references below), I managed to hone the code down to something that looks like the following:

<!-- wpf only, this is not supported in Silverlight -->
<ListBox Tile:Tile.Mode="Tile">
  <ListBox.Background>
     <ImageBrush ImageSource="grey_wash_wall.png" />
  </ListBox.Background>
</ListBox>        

There are a lot of assumptions going here. The attached property Tile:Mode walks down the visual tree and finds an element which has the background set to the same background as specified on the control. Since the ImageBrush doesn’t tile, we insert an Image into the visual tree. This image has a Tiled ShaderEffect attached and voila! Faked TiledImageBrush.

Caveats

If your template binds the Background to a Rectangle, this can be problematic as the the pixel shader will not clip properly.

Source

You can grab the code at https://github.com/teyc/SilverlightTiledImageBrush.

References

http://silverscratch.blogspot.com.au/2010/09/tiled-image-brush-for-silverlight.html

LightSwitch Extensions Made Easy VS2012

Lightswitch Extensions Made Easy by Jan Van der Haegen addresses some of the major pain points in developing LightSwitch Extensions. This extension tightens the edit-debug cycle. If you are in the business of developing shells, you owe a closer look at what Jan has done and use it in your workflow. It is a brilliant implementation.

Prerequisites

  1. Microsoft Visual Studio Premium
  2. Microsoft Visual Studio SDK (install via Tools/Extensions and Updates)
  3. Microsoft Lightswitch Extensions (install via Tools/Extensions and Updates)

Step 1: Installing the extension

The Lightswitch Extensions Made Easy provides a prebuilt extension that will load your custom classes via MEF. This means for most time, you will only need to build your dll, and not having to rebuild and reinstall an extension each time.

In Visual Studio 2012, under the Tools menu, select Extensions and Updates then in the Online category, search for “Lightswitch Extensions Made Easy”

ls-01

Step 2: Enabling the extension in your Lightswitch project

Select the Lightswitch project, and in the Properties context menu, enable the Lightswitch Extensions Made Easy project.

ls-02

Step 3: Set the shell

In the General Properties tab, select Edit Client Properties. Then set the Shell and Theme to “EasyShell” and “EasyTheme

ls-03

Step 4: Switch to File View in Solution Explorer

If you are a seasoned visual studio developer, you are probably wondering where are your normal project files. LightSwitch has hidden these away. This can be enabled in the Solution Explorer (see diagram).

ls-04

Step 5: Create a Lightswitch Extensions Project

Open an existing Lightswitch project, create your new Lightswitch Extensions Project and add it to your existing solution. This adds seven projects. Don’t get worried as you need to be only concerned with the Lspkg one:

  1. LightSwitchExtension1.Client
  2. LightSwitchExtension1.Client.Design
  3. LightSwitchExtension1.Common
  4. LightSwitchExtension1.Design
  5. LightSwitchExtension1.Lspkg
  6. LightSwitchExtension1.Server
  7. LightSwitchExtension1.Vsix

Step 6: Add a Shell item

Select the LightSwitchExtension1.Lspkg project, and Add New Item. Select “Shell”. This will add a shell xaml to your LightSwitchExtension1.Client project.

Step 7: Set the shell’s access to public

Change the shell’s access modifier from internal to public. This will enable EasyShell to load your code.

namespace LightSwitchExtension1.Presentation.Shells.Components
{
    [Export(typeof(IShell))]
    [Shell(DockableShell.ShellId)]
    <del>internal</del> public class DockableShell : IShell
    {
    }

Step 8: Reference the LightswitchExtension1.Client project

In the Lightswitch project, add a reference to the LightswitchExtension1.Client project.

Add an EasyShellExporter class to the Lightswitch project’s Client subproject

namespace LightswitchTest
{
    using ExtensionsMadeEasy.ClientAPI.Shell;
    using LightSwitchExtension1.Presentation.Shells.Components;
    
    public class DockableShellExporter: EasyShellExporter<DockableShell>
    {

    }
}

Step 9: Design the shell

Refer to MSDN’s Creating Shell Extension Walkthrough. In particular, look at the second listing at Define a Shell.

In particular, you should observe that the sample shell contains the following items:

<ListBox x:Name="CommandPanel" 
  ShellHelpers:ComponentViewModelService.ViewModelName="Default.CommandsViewModel"
  ItemsSource="{Binding ShellCommands}" />

<controls:TreeView x:Name="ScreenTree"
   ShellHelpers:ComponentViewModelService.ViewModelName="Default.NavigationViewModel"
   ItemsSource="{Binding NavigationItems}" />

<!-- The individual TabItem         -->
<!-- controls are created in code.  -->
<controls:TabControl x:Name="ScreenArea" />