Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Wednesday, 08 May 2013

To make sure you’re running the correct version of a file – in my case IE10 was caching a xap file (Silverlight) as I was trying to debug what was going on.  Basically I wanted the SL app to display the version number of the dll it was running.

To go from

image

[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyVersion("1.0.0.0")]
//[assembly: AssemblyFileVersion("1.0.0.0")]

make this change to Properties\AssemblyInfo.cs

  • Major
  • Minor
  • Build – number of days since 1st Jan 2000
  • Revision – number of seconds since midnight/2

To:

image

Then the SL UI can read it:

private string GetAssemblyVersion()
        {
            var assemblyName = new AssemblyName(Application.Current.GetType().Assembly.FullName);

            if (assemblyName == null)
            {
                return string.Empty;
            }

            Version v = assemblyName.Version;

            if (v == null)
            {
                return string.Empty;
            }

            // calculate build date and time too
            int revision = v.Revision;
            var numSecsSinceMidnight = revision*2;
            TimeSpan t = TimeSpan.FromSeconds(numSecsSinceMidnight);

            // Summer time.
            t = t.Add(new TimeSpan(0, 1, 0, 0));

            string timeOfBuild = string.Format("{0:D2}:{1:D2}:{2:D2}",
                t.Hours,
                t.Minutes,
                t.Seconds);

            // Date of build
            int build = v.Build;
            DateTime buildDate = new DateTime(2000, 1, 1).Add(new TimeSpan(TimeSpan.TicksPerDay * build));
            string buildDateBritishFormat = buildDate.ToString("d-MMM-yy");

            var message = v + "   Build Date: " + buildDateBritishFormat + " " + timeOfBuild;

            return message;
        }

image

| | # 
# Friday, 22 March 2013

<TextBlock Grid.Row="3" Height="200" Text="No Accounts" HorizontalAlignment="Center"
                  Visibility="{Binding Path=ItemsSource.Count, ElementName=AccountItemsT31, Converter={StaticResource ListCountToVisibilityConverter}}" />

// If no data in incoming ItemsSource then set text box visibility to visible
    public class ListCountToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null || !(value is int))
                return Visibility.Collapsed;

            bool booInvert = false;
            if (parameter is string) bool.TryParse((string)parameter, out booInvert);

            if (booInvert) return ((int)value) <= 0 ? Visibility.Visible : Visibility.Collapsed;
            else
            {
                var x = ((int)value) > 0 ? Visibility.Collapsed : Visibility.Visible;

                return x;
            }
        }

        public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
    }

| | # 
# Wednesday, 20 March 2013

In web.config

<appSettings>

<add key="OverrideWindowsUser" value="qnrl\asdf" />

</appSettings>

In the aspx page:

    <param name="initParams" value="Client=<%= System.Configuration.ConfigurationManager.AppSettings["OverrideWindowsUser"] %>" />

Then in app.xaml.cs in Application_Startup:

OverrideWindowsUserName = e.InitParams["Client"];

Then in MainPage.xaml.cs

overrideWindowsUserName = (App.Current as App).OverrideWindowsUserName;

| | # 
# Thursday, 14 February 2013
( Silverlight | XAML )

A great tool where you can see what the changes are in XAML in real time.

http://xamlspy.com

| | # 
# Thursday, 10 January 2013

Eventvwr

1
Useful when debugging the WCF service. 

Run tests against service methods.

Useful when issue with edmx or something on the backend, and the wcf service doesn’t surface the error to the ui.

Run as non debug

Popup window can give better errors compared with debugger

Run Service directly in the Browser

image

Catching Debugging errors in VS2012

http://www.scottleckie.com/2010/04/code-4004-unhandled-error-in-silverlight-application/
I have plugged into app.xaml:

private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            // If the app is running outside of the debugger then report the exception using a ChildWindow control.
            if (!System.Diagnostics.Debugger.IsAttached)
            {
                // NOTE: This will allow the application to continue running after an exception has been thrown but not handled.
                // For production applications this error handling should be replaced with something that will report the error to the website and stop the application.
                e.Handled = true;
                ErrorWindow.CreateNew(e.ExceptionObject);
            }
            else
            // Even in debugger catch errors as sometimes badly managed
            // http://www.scottleckie.com/2010/04/code-4004-unhandled-error-in-silverlight-application/
            {
                e.Handled = true;
                ErrorWindow.CreateNew(e.ExceptionObject);
                //System.Diagnostics.Debug.WriteLine(e.ExceptionObject.ToString());
            }
        }

Fiddler

asdf

Include Service exception details:

http://social.msdn.microsoft.com/Forums/en/windowsazuretroubleshooting/thread/e26aaa88-672c-4888-b54d-6c29bb0329f4

| | # 
# Sunday, 23 December 2012

Heght =

  • Auto – take as much space as needed (can have scroll bar issues)
  • * – use all available height
| | # 
# Friday, 21 December 2012

       
In ContextMenuService:

http://silverlight.codeplex.com/workitem/6206

I wired up a right click event.  Then added in MenuItems manually, passing the user object as a Tag.

| | # 
# Thursday, 20 December 2012

“The main thing to remember is that, deep under the hoods, Silverlight has an advanced property system that keeps track of the various dependency properties used in an application.”

http://www.codeproject.com/Articles/42203/How-to-Implement-a-DependencyProperty

So can do a dependency property.. and also do events when it is changed (with commented out code below).  Probably cleaner sln but conceptually harder is to just bind here http://stackoverflow.com/questions/13957587/silverlight-strategy-passing-data-to-a-user-control

public partial class WidgetControl : UserControl
    {
        public WidgetControl()
        {
            InitializeComponent();
        }

        //public static readonly DependencyProperty CaptionProperty =  DependencyProperty.Register("Caption",typeof(string),typeof(WidgetControl),
        //                                                            new PropertyMetadata(string.Empty, OnCaptionPropertyChanged));
        public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(WidgetControl),null);


        //private static void OnCaptionPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        //{
        //    WidgetControl myUserControl = dependencyObject as WidgetControl;
        //    myUserControl.OnPropertyChanged("Caption");
        //    myUserControl.OnCaptionPropertyChanged(e);
        //}

        //private void OnCaptionPropertyChanged(DependencyPropertyChangedEventArgs e)
        //{
        //    txbCaption.Text = Caption;
        //}

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

        public string Caption
        {
            get { return (string)GetValue(CaptionProperty); }
            set { SetValue(CaptionProperty, value); }
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            txbCaption.Text = Caption;
        }

    }

 

and in WidgetControl.xaml:

<Grid x:Name="LayoutRoot" Background="White">
        <ItemsControl Foreground="Red">
            <TextBlock Foreground="Blue">
                1st line of text widgetcontrol
            </TextBlock>
            <TextBlock>
                2nd line of text
            </TextBlock>
            <TextBox Name="txbCaption" />
            <Button Content="in widget" Click="ButtonBase_OnClick" />
        </ItemsControl>
    </Grid>

then MainPage.xaml

<Grid x:Name="LayoutRoot">
        <!--<UserControls:WidgetControl Caption="test" />-->
        <ItemsControl>
            <UserControls:WidgetControl Name="wid" />
            <Button Click="ButtonBase_OnClick" Content="asdf" />
        </ItemsControl>
    </Grid>

and codebehind:

public partial class MainPage : UserControl
    {

        //public static readonly DependencyProperty WidgetStateProperty;

        public MainPage()
        {
            InitializeComponent();
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            wid.Caption = "hello world";
        }
    }

BusinessApplication4

| | # 
# Wednesday, 19 December 2012

wire up via:

LoadingRow="HomeGrid_OnLoadingRow"
        private void HomeGrid_OnLoadingRow(object sender, DataGridRowEventArgs e)
        {
            var t = e.Row.DataContext as Tab1PresentationModel;

            // alternate colours and custom bottom colour for totals
            // if don't do this we get phantom colouring of rows
            bool isRowEven = false;
            if (e.Row.GetIndex()%2 == 0)
                isRowEven = true;

            if (t.ApplicationName.Contains("Grand Totals"))
            {
                e.Row.Background = new SolidColorBrush(Colors.DarkGray);
            }
            else if (isRowEven)
            {
                // darker blue
                e.Row.Background = new SolidColorBrush(Color.FromArgb(255, 176, 196, 222));

            }
            else
            {
                // white ish
                e.Row.Background = new SolidColorBrush(Color.FromArgb(37, 233, 238, 244));
            }
        }
| | # 
# Wednesday, 12 December 2012

Getting RIA to have an overall context..

wiring up a global context… easier in codebehind.

http://stackoverflow.com/questions/2996686/using-ria-services-filterdescriptor-from-code-behind

Example of setting many properties in codebehind:

//public DomainDataSource accountsDataSourceT32;
            if (ddsSetup == false)
            {
                //accountsDataSourceT32 = new DomainDataSource();
                //accountsDataSourceT32.AutoLoad = true;
                //accountsDataSourceT32.QueryName = "xxxx";
                //accountsDataSourceT32.LoadSize = 30;
                //accountsDataSourceT32.PageSize = 30;
                AccountsDataSourceT32.DomainContext = uerDomainContext;

                //var p = new Parameter();
                //p.ParameterName = "xxLogin";
                //p.Value = ADLogin;

                //var p3 = new Parameter();
                //p3.ParameterName = "xxRID";
                //p3.Value = "AllUsers";

                //var pp = new Parameter();
                //pp.ParameterName = "xxAID";
                //pp.Value = "0";

                //accountsDataSourceT32.QueryParameters.Add(p);
                //accountsDataSourceT32.QueryParameters.Add(pp);
                //accountsDataSourceT32.QueryParameters.Add(p3);

                //accountsDataSourceT32.SortDescriptors.Add(new SortDescriptor("LastName", ListSortDirection.Ascending));

                //TextBlock txtFilterName = new TextBlock();
                //txtFilterName.Text = "xxx";

                //var f = new FilterDescriptor();
                //f.PropertyPath = "LastName";
                //f.Operator = FilterOperator.Contains;
                ////f.Operator = FilterOperator.IsEqualTo;
                ////f.Value = "xxxt";

                //Binding b = new Binding("Text") { ElementName = "TextBoxAccountSearchT32" };
                //BindingOperations.SetBinding(f, FilterDescriptor.ValueProperty, b);
                //accountsDataSourceT32.FilterDescriptors.Add(f);


                AccountsDataSourceT32.Load();
                ddsSetup = true;

                //this.Resources.Add("accountsDataSourceT32", accountsDataSourceT32);

                AccountItemsT32.ItemsSource = AccountsDataSourceT32.Data;
            }

However am finding the clearest way is to set in XAML everything except for the domaincontext.

| | # 
# Thursday, 06 December 2012

From my question on directly testing RIA Services calls.

http://stackoverflow.com/questions/13510361/ria-services-where-to-call-savechanges-from-a-test/13622463#13622463

http://social.msdn.microsoft.com/Forums/en-US/vstest/thread/5e991b0d-8061-4c4e-a17d-82b4abd58d6c

http://nuget.org/packages/SilverlightToolkit-Testing

Test runners:

Testing front end (eg bindings load)

http://vanderbiest.org/blog/#/Search

How To

Make a new Silverlight standard project.  No RIA link

NuGet search: silverlight testing  find: SilverlightToolkit-Testing

add ref ….libs\RIA Services\v1.0\Libraries\Silverlight\System.ServiceModel.DomainServices.Client

add ref to ClientApp (the SL app we’re testing)

using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using UER.ClientApp.Web.Services;


namespace UER.ClientApp.Tests
{
    [TestClass]
    public class SLTests : SilverlightTest
    {
        [TestMethod]
        public void simpletest_givennothing_1equals1()
        {
            Assert.AreEqual(1, 1);
        }

        [TestMethod]
        [Asynchronous]
        public void AsynchronousWCFCallWithGetStudentWCFCommand()
        {
            var target = new UERDomainContext();

            // Arrange
            EnqueueCallback(() => target.Load(target.GetAccountsQuery()));
            EnqueueConditional(() => !target.IsLoading);
            EnqueueCallback(() => Assert.IsTrue(target.Accounts.Any()));

            // Act
            EnqueueCallback(() => target.Accounts.First().Name = "NewValue");
            EnqueueCallback(() => target.SubmitChanges());

            //// Assert
            EnqueueConditional(() => !target.IsSubmitting);
            EnqueueCallback(() => Assert.IsFalse(target.HasChanges));
            EnqueueTestComplete();
        }
    }
}

Test runner is really not very usable at the top level (ie takes 20s to really run properly?)

image

Try R# and Agunit

Anything to do with databases just seems to saying:  Running… and never finishes.

However AGUnit doesn’t surface async calls currently: http://agunit.codeplex.com/discussions/405630

| | # 
# Wednesday, 21 November 2012

Chapter 3 – Databinding

  • good observablecollection, and setting up manual OnPropertyChanged events
  • Validation and DataAnnotations
  • Converters
  • Good use of Views to separate code

Chapter 4 – Architecture

  • MVVM
  • MVVM Lite
  • MEF
  • Structure and naming of App

Chapter 5 – RIA Services Data Access

  • Using with MVVM..view models
  • Validation
  • Factory / UOW patterns

Very good example application in here.. testable!p

  • Build script
  • Tests
  • Modular

Ch 6 – OOB

Ch7 – Testing

Ch8 –Error Control

  • Logging
  • EntLib
  • Exception Handling
  • PostSharp AOP

Ch11 – Security

  • Signing assemblies
  • Certs

 

image

Got final version working changing the connection string in Server.Web

| | # 
# Thursday, 15 November 2012

I’m trying to do something like RemoveAccountFromRole

Can do it with an Invoke method call on RIA, however it doesn’t refresh the data on the front end:

Although the Invoke attribute is optional, to be considered an invoke method a
method shouldn’t take entities as a parameter or return an entity, IEnumerable, or
IQueryable of entities as a result.

Conventions

Get, Insert, Update, Delete

Testing a domainservice:

https://msdnrss.thecoderblogs.com/2011/08/unit-testing-a-wcf-ria-domainservice-part-3-the-domainservicetesthost/

Getting the correct context to work on so INotifyPropertyChanged works.

Update a single entity

Update Multiple

Forcing a Rebind

couldn’t get this to work..

            // Force rebind - doesn't work             //BindingExpression bindExp = AccountItemsT32.GetBindingExpression(ListBox.ItemsSourceProperty);             //Binding bind = bindExp.ParentBinding;             //AccountItemsT32.SetBinding(ListBox.ItemsSourceProperty, bind);             //AccountItemsT32.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateSource();
 

Eager Loading

http://blogs.msdn.com/b/alexj/archive/2009/06/02/tip-22-how-to-make-include-really-include.aspx – workaround for joins and includes

Reload DomainContext

http://stackoverflow.com/questions/3899721/silverlight-4-ria-update-item-in-domaindatasource-only-updates-after-refresh

| | # 
# Tuesday, 06 November 2012

http://varunpuranik.wordpress.com/2011/06/29/wcf-ria-services-support-for-ef-4-1-and-ef-code-first/ – interesting manual code

image

Doing an edmx

TestDBEntities.. Default Code Gen strategies

image

Trying Identity on Person table with test rig code.

None – value of the property is set in the application and persisted to the database.  Default for most of the properties

StoreGeneratedPattern="Identity" simply tells EF that the value will be generated DB-side on insert, and that it shouldn't supply a value in insert statements.  This is used by default for all PK’s using IDENTITY setting.

Computed – the value of the property is et in the db during each persistence.  This setting is by default used for properties mapped to columns with TIMESTAMP or ROWVERSION.

None

http://www.mindscapehq.com/documentation/lightspeed/Controlling-the-Database-Mapping/Identity-Generation

image

http://www.ladislavmrnka.com/2011/03/the-bug-in-storegeneratedpattern-fixed-in-vs-2010-sp1/ – Bug in EF fixed in 2010 SP1

http://stackoverflow.com/questions/13251136/ef-with-keytable-sequence-style-pk – Question on SO regarding this.

| | # 
# Monday, 05 November 2012

Silverlight Toolkit AutoCompleteBox – a control that provides suggested items for a TextBox

| | # 
// Suppress Silverlight right-click menu for clicks on ListBoxItem elements
            //AccountItemsT32.MouseRightButtonDown += delegate(object sender, MouseButtonEventArgs e)
            //{
            //    e.Handled = true;
            //};

            // Add the Mouse Right click Event Handler to disable all S/L right click.
            this.MouseRightButtonDown += (s, e) =>
            {
                e.Handled = true;
            };

Using delegate and anonymous delegate syntax

| | # 
# Friday, 02 November 2012

image

Actually this is a WPF app – but does something similar.  http://www.zagstudio.com/blog/488#.UJFk58VLNvA
Drags from databound ItemsControl to databound ItemControl.. this is from Feb 2008 so possibly easier.

Currently I want to drag from an ItemsControl to a StackPanel… (a listbox can contain a stackpanel**)

http://www.codeproject.com/Articles/43614/Drag-and-Drop-in-WPF -

SL5 Toolkit

image
Drag and Drop using a ListBox, and the SL5 Toolkit:  Also reordering of the listboxes
http://www.codeproject.com/Articles/81105/How-to-Drag-and-Drop-between-ListBox-using-Silverl

<StackPanel Orientation="Horizontal" Margin="10" Grid.Row="1">
            <toolKit:ListBoxDragDropTarget AllowDrop="True">
                <ListBox x:Name="customerListBoxMain" Height="200" Width="200" DisplayMemberPath="Name">
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical"/>
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                </ListBox>
            </toolKit:ListBoxDragDropTarget>

Very simple, however just for use with a listbox.

ListBox derives from ItemsControl

http://msdn.microsoft.com/en-us/magazine/ff714594.aspx – Charles Petzold on SL3/4 Fluid UI drag and drop.

Potential agnostic to canvas:
http://stackoverflow.com/questions/8802231/drag-and-drop-functionality-for-canvas-in-silverlight-5

Telerik have a DragAndDrop which allows dragging from any element, to any other element

Dragging in SL3

http://joel.neubeck.net/2009/07/silverlight-3-drag-behavior/

image
Converts to a bitmap then can drag.

http://msdn.microsoft.com/en-us/library/cc189066(v=vs.95).aspx – can dnd objects around (a rectangle)

Dragging in SL4

http://www.codeproject.com/Articles/75479/Silverlight-4-Drag-and-Drop-File-Manager – File system and MVVM

image
http://www.codeproject.com/Articles/211641/Silverlight-Drag-and-Drop-for-Business-Application

http://stackoverflow.com/questions/5560919/silverlight-4-listboxdragdroptarget-drop-onto-listboxitem – good source

Have got a person dragging on from the left… to a role on the right, and have got an event firing when the person lets go of the drag

image

<Grid x:Name="LayoutRoot" Background="White">
        <TextBlock Margin="20,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Text="Silverlight Business Drag and Drop" FontSize="16"></TextBlock>
        <Grid x:Name="DragDropRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="40,40,0,0">

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50*" />
                <ColumnDefinition Width="50*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="30" />
                <RowDefinition Height="*" />
                <RowDefinition Height="30" />
            </Grid.RowDefinitions>

            <TextBlock Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center">Header 1</TextBlock>
            <toolKit:ListBoxDragDropTarget AllowDrop="True" Grid.Column="0" Grid.Row="1">
                <ListBox x:Name="AListBox" Height="200" Width="200" ItemsSource="{Binding PeopleList}" DisplayMemberPath="Name" >
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical"/>
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                </ListBox>
            </toolKit:ListBoxDragDropTarget>

            <TextBlock Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center">Header 2</TextBlock>
            <toolKit:ListBoxDragDropTarget AllowDrop="True" Grid.Column="1" Grid.Row="1" Drop="ToBoxDragDropTarget_Drop">
                <ListBox x:Name="BListBox" Height="200" Width="200" ItemsSource="{Binding RoleList}" DisplayMemberPath="RoleName">
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical"/>
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                </ListBox>
            </toolKit:ListBoxDragDropTarget>

            <TextBlock x:Name="UpdateText" Grid.Row="2"/>
        </Grid>
    </Grid>
</UserControl>

then code behind.  Project is called SilverlightBusinessDragDrop.

| | # 
# Thursday, 01 November 2012

http://blogs.msdn.com/b/kaevans/archive/2010/04/24/listboxes-in-silverlight.aspx – Selection changed events

http://www.dotnetcurry.com/ShowArticle.aspx?ID=676 – PagedCollection using a callback for ListBox

http://stackoverflow.com/questions/7953956/multi-column-listbox – multi column using the toolkit WrapPanel

MultiSelect in a listbox – SelectionMode = Extended

http://www.codeproject.com/Articles/404827/Rubberband-Behavior-for-WPF-ListBox – Rubber band behaviour

| | # 
# Wednesday, 24 October 2012

image
http://blogs.msdn.com/b/kylemc/archive/2011/08/18/unit-testing-a-wcf-ria-domainservice-part-1-the-idomainservicefactory.aspx

http://cockneycoder.wordpress.com/2011/07/08/creating-a-testable-wcf-ria-domain-service-part-2/

NuGet – RIAServides.UnitTesting

http://skysigal.xact-solutions.com/Blog/tabid/427/Default.aspx?QuestionID=769&AFMID=2121 – set copylocal to true to get TestDriven.NET working?

image
Issue with the TestInitialize method not running before every test!  Even using the MSTEST Runner in VS2012.

Looks like AgUnit is good (maybe with R# test runner too).

Options for testing:

  • Test against real DB, maybe with modified connection string
  • Use mocking framework
  • Use dependency injection to allow service code to be passed external dependencies

Latest Version of WCF RIA Servies is V1.0SP2 is 16th August 2012.. (now is Oct 2012) http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=28357

http://code.msdn.microsoft.com/site/search?f[0].Type=Technology&f[0].Value=WCF%20RIA%20Services&f[1].Type=Affiliation&f[1].Value=Microsoft   RIA Samples

 

http://code.msdn.microsoft.com/Repository-Pattern-Demo-fece07ed – Repo pattern demo unit testing.

Silverlight Unit Test adapter…take out of VS – can only run 1 test at a time…

Microsoft.VisualStudio.QualityTools.Common

.UnitTestFramework… was v.10 … want v.11

need System.ServiceModel.DomainServices.Server

Okay so can test with MockEmployeeRepo.

StatLight – automated SL Testing Tool.

Unit Testing EmployeeService against Live Database

In UnitTest project:

Error    1    The type 'System.ServiceModel.DomainServices.EntityFramework.LinqToEntitiesDomainService`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.ServiceModel.DomainServices.EntityFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.    E:\Dev\Brown\RiaExample\RiaExample.Web.Tests\EmployeeServiceTests.cs    25    13    RiaExample.Web.Tests

C:\Program Files (x86)\Microsoft SDKs\RIA Services\v1.0\Libraries\Server

Error    2    The type 'System.Data.Objects.DataClasses.EntityObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.    E:\Dev\Brown\RiaExample\RiaExample.Web.Tests\EmployeeServiceTests.cs    27    13    RiaExample.Web.Tests

DomainService.Query

Remove NuGet Package

Uninstall-Package NUnit

MSTest

Add ref:  Microsoft.VisualStudio.QualityTools.UnitTestFramework

Ctrl + R, Ctrl + D   - run debug tests

Ctrl+R, Ctrl+T   - Run all tests in current context

image

How to get results showing of not debug?

Removing Unused Refs

SL Web Project and SL Project – doesn’t work well this tool.
Unit testing project worked okay.

image
Using debug, then detach all.

Unit Testing

Code Snippet
  1. using Microsoft.ServiceModel.DomainServices.Server.UnitTesting;
  2. using Microsoft.VisualStudio.TestTools.UnitTesting;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.ComponentModel.DataAnnotations;
  6. using System.Linq;
  7. using System.Security.Principal;
  8. using UnitTestingSample.Web.External;
  9. using UnitTestingSample.Web.Repository;
  10. using UnitTestingSample.Web.Repository.Test;
  11.  
  12. namespace UnitTestingSample.Web.Services.Test
  13. {
  14.     [TestClass]
  15.     public class BookClubDomainServiceTest
  16.     {
  17.         private static readonly IPrincipal authenticatedUser = new GenericPrincipal(new GenericIdentity("User"), new string[0]);
  18.  
  19.         private MockLibraryService _libraryService;
  20.         private FakeApprovalSystem _approvalSystem;
  21.         private FakeUnitOfWork _unitOfWork;
  22.         private MockBookRepository _bookRepository;
  23.  
  24.         private DomainServiceTestHost<BookClubDomainService> _domainServiceTestHost;
  25.  
  26.         // This isn't being called before each test
  27.         [TestInitialize]
  28.         public void TestInitialize()
  29.         {
  30.             _libraryService = new MockLibraryService();
  31.             _approvalSystem = new FakeApprovalSystem();
  32.             _unitOfWork = new FakeUnitOfWork();
  33.             _bookRepository = new MockBookRepository();
  34.  
  35.             _domainServiceTestHost = new DomainServiceTestHost<BookClubDomainService>(CreateDomainService);
  36.         }
  37.  
  38.         // DaveM put this in to force Test Initialize
  39.         public BookClubDomainServiceTest()
  40.         {
  41.             TestInitialize();
  42.         }
  43.  
  44.         private BookClubDomainService CreateDomainService()
  45.         {
  46.             return new BookClubDomainService(
  47.                     this._unitOfWork,
  48.                     this._bookRepository,
  49.                     this._libraryService,
  50.                     this._approvalSystem);
  51.         }
  52.  
  53.         [TestMethod]
  54.         public void asdf()
  55.         {
  56.             Assert.AreEqual(1, 1);
  57.         }
  58.  
  59.         [TestMethod]
  60.         [Description("Tests that the GetBooks query returns all the books")]
  61.         public void GetBooks_ReturnsAllBooks()
  62.         {
  63.             _domainServiceTestHost = new DomainServiceTestHost<BookClubDomainService>(CreateDomainService);
  64.  
  65.             IEnumerable<Book> books = _domainServiceTestHost.Query(ds => ds.GetBooks());
  66.  
  67.             Assert.AreEqual(this._bookRepository.GetBooksWithCategories().Count(), books.Count(),"Operation should return all books");
  68.         }
  69.  
  70.         [TestMethod]
  71.         [Description("Tests that the GetBooks query includes a category for each book")]
  72.         public void GetBooks_BooksIncludeCategories()
  73.         {
  74.             IEnumerable<Book> books = this._domainServiceTestHost.Query(ds => ds.GetBooks());
  75.  
  76.             Assert.IsTrue(books.All(b => b.Category != null),
  77.                 "Operation should return books with categories");
  78.         }
  79.  
  80.         [TestMethod]
  81.         [Description("Tests that the GetBooks query orders books by BookID")]
  82.         public void GetBooks_OrderedByBookID()
  83.         {
  84.             IEnumerable<Book> books = this._domainServiceTestHost.Query(ds => ds.GetBooks());
  85.  
  86.             Assert.IsTrue(books.OrderBy(b => b.BookID).SequenceEqual(books),
  87.                 "Operation should return books ordered by BookID");
  88.         }
  89.  
  90.         [TestMethod]
  91.         [Description("Tests that the GetBooksForCategory query returns all the books in a specific category")]
  92.         public void GetBooksForCategory_ReturnsBooksInCategory()
  93.         {
  94.             int categoryId = this._bookRepository.GetTable<Category>().First().CategoryID;
  95.  
  96.             IEnumerable<Book> books = this._domainServiceTestHost.Query(ds => ds.GetBooksForCategory(categoryId));
  97.  
  98.             Assert.AreEqual(this._bookRepository.GetEntities().Count(b => b.CategoryID == categoryId), books.Count(),
  99.                 "Operation should return all books for category");
  100.         }
  101.  
  102.         [TestMethod]
  103.         [Description("Tests that the GetBooksForCategory query orders books by BookID")]
  104.         public void GetBooksForCategory_OrderedByBookID()
  105.         {
  106.             int categoryId = this._bookRepository.GetTable<Category>().First().CategoryID;
  107.  
  108.             IEnumerable<Book> books = this._domainServiceTestHost.Query(ds => ds.GetBooksForCategory(categoryId));
  109.  
  110.             Assert.IsTrue(books.OrderBy(b => b.BookID).SequenceEqual(books),
  111.                 "Operation should return books ordered by BookID");
  112.         }
  113.  
  114.         [TestMethod]
  115.         [Description("Tests that PersistChangeSet saves the unit of work")]
  116.         public void PersistChangeSet_SavesUnitOfWork()
  117.         {
  118.             Book original = this._bookRepository.GetEntities().First();
  119.             Book book = new Book
  120.             {
  121.                 AddedDate = original.AddedDate,
  122.                 ASIN = original.ASIN,
  123.                 Author = original.Author,
  124.                 BookID = original.BookID,
  125.                 Category = original.Category,
  126.                 CategoryID = original.CategoryID,
  127.                 Description = original.Description + ": This books is great!",
  128.                 PublishDate = original.PublishDate,
  129.                 Title = original.Title,
  130.             };
  131.  
  132.             this._domainServiceTestHost.Update(book, original);
  133.  
  134.             Assert.AreEqual(1, this._unitOfWork.SaveCount,
  135.                 "Unit of work should be saved");
  136.         }
  137.  
  138.         [TestMethod]
  139.         [Description("Tests that the InsertBook operation inserts a new book")]
  140.         public void InsertBook_InsertsNewBook()
  141.         {
  142.             int categoryId = this._bookRepository.GetTable<Category>().First().CategoryID;
  143.  
  144.             Book book = new Book
  145.             {
  146.                 ASIN = "1234567890",
  147.                 Author = "Author",
  148.                 CategoryID = categoryId,
  149.                 Description = "Description",
  150.                 PublishDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
  151.                 Title = "Title",
  152.             };
  153.  
  154.             this._domainServiceTestHost.Insert(book);
  155.  
  156.             Assert.IsTrue(book.BookID > 0,
  157.                 "New book should have a valid BookID");
  158.  
  159.             Book addedBook = this._bookRepository.GetEntities().Single(b => b.BookID == book.BookID);
  160.  
  161.             Assert.IsNotNull(addedBook,
  162.                 "Operation should insert book");
  163.         }
  164.  
  165.         [TestMethod]
  166.         [Description("Tests that the InsertBook operation sets the AddedDate on the new book")]
  167.         public void InsertBook_SetsAddedDate()
  168.         {
  169.             int categoryId = this._bookRepository.GetTable<Category>().First().CategoryID;
  170.  
  171.             Book book = new Book
  172.             {
  173.                 ASIN = "1234567890",
  174.                 Author = "Author",
  175.                 CategoryID = categoryId,
  176.                 Description = "Description",
  177.                 PublishDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
  178.                 Title = "Title",
  179.             };
  180.  
  181.             DateTime currentTime = DateTime.UtcNow;
  182.  
  183.             this._domainServiceTestHost.Insert(book);
  184.  
  185.             Assert.IsTrue(book.AddedDate >= currentTime,
  186.                 "Operation should set the added date");
  187.         }
  188.  
  189.         [TestMethod]
  190.         [Description("Tests that the InsertBook operation requests approval for a books with an invalid ASIN")]
  191.         public void InsertBook_RequestsApprovalForInvalidASIN()
  192.         {
  193.             int categoryId = this._bookRepository.GetTable<Category>().First().CategoryID;
  194.  
  195.             Book book = new Book
  196.             {
  197.                 ASIN = "1234567890",
  198.                 Author = "Author",
  199.                 CategoryID = categoryId,
  200.                 Description = "Description",
  201.                 PublishDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
  202.                 Title = "Title",
  203.             };
  204.  
  205.             this._domainServiceTestHost.Insert(book);
  206.  
  207.             Assert.AreEqual(book.ASIN, this._libraryService.Asin,
  208.                 "The ASIN on the MockLibraryService should match the book");
  209.             Assert.AreEqual(book.Author, this._approvalSystem.Author,
  210.                 "Operation should request approval for book with invalid ASINs by author");
  211.             Assert.AreEqual(book.Title, this._approvalSystem.Title,
  212.                 "Operation should request approval for book with invalid ASINs by title");
  213.             Assert.AreEqual(book.PublishDate, this._approvalSystem.PublishDate,
  214.                 "Operation should request approval for book with invalid ASINs by publish date");
  215.         }
  216.  
  217.         [TestMethod]
  218.         [Description("Tests that the InsertBook operation requests approval for a book with that has not yet been published")]
  219.         public void InsertBook_RequestsApprovalForUnpublishedBook()
  220.         {
  221.             int categoryId = this._bookRepository.GetTable<Category>().First().CategoryID;
  222.  
  223.             Book book = new Book
  224.             {
  225.                 ASIN = "1234567890",
  226.                 Author = "Author",
  227.                 CategoryID = categoryId,
  228.                 Description = "Description",
  229.                 PublishDate = DateTime.MaxValue,
  230.                 Title = "Title",
  231.             };
  232.  
  233.             this._libraryService.AsinToMatch = book.ASIN;
  234.  
  235.             this._domainServiceTestHost.Insert(book);
  236.  
  237.             Assert.AreEqual(book.ASIN, this._libraryService.Asin,
  238.                 "The ASIN on the MockLibraryService should match the book");
  239.             Assert.AreEqual(book.ASIN, this._approvalSystem.Asin,
  240.                 "Operation should request approval for book not yet published");
  241.         }
  242.  
  243.         [TestMethod]
  244.         [Description("Tests that the UpdateBook operation updates the book")]
  245.         public void UpdateBook_UpdatesBook()
  246.         {
  247.             Book original = this._bookRepository.GetEntities().First();
  248.             Book book = new Book
  249.             {
  250.                 AddedDate = original.AddedDate,
  251.                 ASIN = original.ASIN,
  252.                 Author = original.Author,
  253.                 BookID = original.BookID,
  254.                 Category = original.Category,
  255.                 CategoryID = original.CategoryID,
  256.                 Description = original.Description + ": This books is great!",
  257.                 PublishDate = original.PublishDate,
  258.                 Title = original.Title,
  259.             };
  260.  
  261.             this._domainServiceTestHost.Update(book, original);
  262.  
  263.             Assert.AreEqual(this._bookRepository.GetEntities().First().Description, book.Description,
  264.                 "Operation should update book");
  265.         }
  266.  
  267.         [TestMethod]
  268.         [Description("Tests that the UpdateBook operation returns validation errors when passed an invalid book")]
  269.         public void UpdateBook_SetsValidationErrors()
  270.         {
  271.             Book original = this._bookRepository.GetEntities().First();
  272.             Book book = new Book
  273.             {
  274.                 AddedDate = original.AddedDate,
  275.                 ASIN = "Invalid!",
  276.                 Author = original.Author,
  277.                 BookID = original.BookID,
  278.                 Category = original.Category,
  279.                 CategoryID = original.CategoryID,
  280.                 Description = original.Description,
  281.                 PublishDate = original.PublishDate,
  282.                 Title = original.Title,
  283.             };
  284.  
  285.             IList<ValidationResult> validationErrors;
  286.             bool success = this._domainServiceTestHost.TryUpdate(book, original, out validationErrors);
  287.  
  288.             Assert.IsFalse(success,
  289.                 "Operation should have validation errors");
  290.             Assert.AreEqual(1, validationErrors.Count,
  291.                 "Operation should return validation errors");
  292.             Assert.IsTrue(validationErrors[0].MemberNames.Single() == "ASIN",
  293.                 "Operation should return a validation error for 'ASIN'");
  294.         }
  295.  
  296.         [TestMethod]
  297.         [Description("Tests that the AddNewEdition operation updates the book")]
  298.         public void AddNewEdition_UpdatesBook()
  299.         {
  300.             Book original = this._bookRepository.GetEntities().First();
  301.             Book book = new Book
  302.             {
  303.                 AddedDate = original.AddedDate,
  304.                 ASIN = original.ASIN,
  305.                 Author = original.Author,
  306.                 BookID = original.BookID,
  307.                 Category = original.Category,
  308.                 CategoryID = original.CategoryID,
  309.                 Description = original.Description + ": V2",
  310.                 PublishDate = original.PublishDate,
  311.                 Title = original.Title,
  312.             };
  313.  
  314.             this._domainServiceTestHost.Update(ds => ds.AddNewEdition(book), original);
  315.  
  316.             Assert.AreEqual(this._bookRepository.GetEntities().First().Description, book.Description,
  317.                 "Operation should update book");
  318.         }
  319.  
  320.         [TestMethod]
  321.         [Description("Tests that the AddNewEdition operation updates the AddedDate on the book")]
  322.         public void AddNewEdition_UpdatesAddedDate()
  323.         {
  324.             Book original = this._bookRepository.GetEntities().First();
  325.             Book book = new Book
  326.             {
  327.                 AddedDate = original.AddedDate,
  328.                 ASIN = original.ASIN,
  329.                 Author = original.Author,
  330.                 BookID = original.BookID,
  331.                 Category = original.Category,
  332.                 CategoryID = original.CategoryID,
  333.                 Description = original.Description + ": V2",
  334.                 PublishDate = original.PublishDate,
  335.                 Title = original.Title,
  336.             };
  337.  
  338.             DateTime currentTime = DateTime.UtcNow;
  339.  
  340.             this._domainServiceTestHost.Update(ds => ds.AddNewEdition(book), original);
  341.  
  342.             Assert.IsTrue(book.AddedDate >= currentTime,
  343.                 "Operation should update the added date");
  344.         }
  345.  
  346.         [TestMethod]
  347.         [Description("Tests that the DeleteBook operation deletes the book")]
  348.         public void DeleteBook_DeletesBook()
  349.         {
  350.             this._domainServiceTestHost =
  351.                 new DomainServiceTestHost<BookClubDomainService>(this.CreateDomainService, BookClubDomainServiceTest.authenticatedUser);
  352.  
  353.             Book book = this._bookRepository.GetEntities().Last();
  354.  
  355.             this._domainServiceTestHost.Delete(book);
  356.  
  357.             Book deletedBook = this._bookRepository.GetEntities().FirstOrDefault(b => b.BookID == book.BookID);
  358.  
  359.             Assert.IsNull(deletedBook,
  360.                 "Operation should delete book");
  361.         }
  362.  
  363.         [TestMethod]
  364.         [Description("Tests that the DeleteBook operation throws an UnauthorizedAccessException when not authenticated")]
  365.         public void DeleteBook_RequiresAuthentication()
  366.         {
  367.             Book book = this._bookRepository.GetEntities().Last();
  368.  
  369.             UnauthorizedAccessException exception = null;
  370.             try
  371.             {
  372.                 this._domainServiceTestHost.Delete(book);
  373.             }
  374.             catch (UnauthorizedAccessException ex)
  375.             {
  376.                 exception = ex;
  377.             }
  378.  
  379.             Assert.IsNotNull(exception,
  380.                 "Operation should require authentication");
  381.         }
  382.  
  383.         [TestMethod]
  384.         [Description("Tests that the GetLatestActivity operation returns the AddedDate of the newest book")]
  385.         public void GetLatestActivity_ReturnsNewestAddedDate()
  386.         {
  387.             DateTime latestActivity = this._bookRepository.GetEntities().Max(b => b.AddedDate);
  388.  
  389.             DateTime result = this._domainServiceTestHost.Invoke(ds => ds.GetLatestActivity());
  390.  
  391.             Assert.AreEqual(latestActivity, result,
  392.                 "Operation should return the most recent added date");
  393.         }
  394.  
  395.         #region Nested Classes
  396.  
  397.         private class MockLibraryService : ILibraryService
  398.         {
  399.             public string AsinToMatch { get; set; }
  400.  
  401.             public string Asin { get; private set; }
  402.  
  403.             public bool IsAsinValid(string asin)
  404.             {
  405.                 this.Asin = asin;
  406.                 return (this.AsinToMatch == asin);
  407.             }
  408.         }
  409.  
  410.         private class FakeApprovalSystem : IApprovalSystem
  411.         {
  412.             public string Author { get; private set; }
  413.             public string Title { get; private set; }
  414.             public DateTime PublishDate { get; private set; }
  415.             public string Asin { get; private set; }
  416.  
  417.             public void RequestApproval(string author, string title, DateTime publishDate)
  418.             {
  419.                 this.Author = author;
  420.                 this.Title = title;
  421.                 this.PublishDate = publishDate;
  422.                 this.Asin = null;
  423.             }
  424.  
  425.             public void RequestApproval(string asin)
  426.             {
  427.                 this.Author = null;
  428.                 this.Title = null;
  429.                 this.PublishDate = DateTime.MinValue;
  430.                 this.Asin = asin;
  431.             }
  432.         }
  433.  
  434.         private class MockBookRepository : MockRepository<Book>, IBookRepository
  435.         {
  436.             public MockBookRepository()
  437.             {
  438.                 this.GetTable<Category>().AddRange(new[]
  439.                 {
  440.                     new Category
  441.                     {
  442.                         CategoryID = 1,
  443.                         CategoryName = "One",
  444.                     },
  445.                     new Category
  446.                     {
  447.                         CategoryID = 2,
  448.                         CategoryName = "Two",
  449.                     },
  450.                 });
  451.  
  452.                 this.GetTable<Book>().AddRange(new []
  453.                 {
  454.                     new Book
  455.                     {
  456.                         AddedDate = DateTime.UtcNow,
  457.                         ASIN = "1234567890",
  458.                         Author = "Author",
  459.                         BookID = 1,
  460.                         Category = this.GetTable<Category>().First(),
  461.                         CategoryID = this.GetTable<Category>().First().CategoryID,
  462.                         Description = "Description",
  463.                         PublishDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
  464.                         Title = "Title 1",
  465.                     },
  466.                     new Book
  467.                     {
  468.                         AddedDate = DateTime.UtcNow,
  469.                         ASIN = "2234567890",
  470.                         Author = "Author",
  471.                         BookID = 2,
  472.                         Category = this.GetTable<Category>().First(),
  473.                         CategoryID = this.GetTable<Category>().First().CategoryID,
  474.                         Description = "Description",
  475.                         PublishDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
  476.                         Title = "Title 2",
  477.                     },
  478.                     new Book
  479.                     {
  480.                         AddedDate = DateTime.UtcNow,
  481.                         ASIN = "3234567890",
  482.                         Author = "Author",
  483.                         BookID = 3,
  484.                         Category = this.GetTable<Category>().Skip(1).First(),
  485.                         CategoryID = this.GetTable<Category>().Skip(1).First().CategoryID,
  486.                         Description = "Description",
  487.                         PublishDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
  488.                         Title = "Title 3",
  489.                     },
  490.                 });
  491.             }
  492.  
  493.             public IQueryable<Book> GetBooksWithCategories()
  494.             {
  495.                 return this.GetEntities();
  496.             }
  497.  
  498.             public override void Insert(Book entity)
  499.             {
  500.                 base.Insert(entity);
  501.                 entity.BookID = this.GetTable<Book>().IndexOf(entity) + 1;
  502.             }
  503.         }
  504.  
  505.         private class FakeUnitOfWork : IUnitOfWork
  506.         {
  507.             public int SaveCount { get; set; }
  508.  
  509.             public void Save()
  510.             {
  511.                 this.SaveCount++;
  512.             }
  513.         }
  514.  
  515.         #endregion
  516.     }
  517. }

Good amount of unit tests on the Service and the Repository.

  • Simple returning data
  • Data with null category style issues
  • Ordering
  • Updates actually work (although he is unit testing so not totally provable)
  • Inserts work
  • Business logic – approval
  • Validation and Authorization
| | # 
# Tuesday, 23 October 2012

Going to use Command Pattern instead of Event Handlers as it makes the ViewModel more easily testable

Can use DomainCollectionView which allows us to still have the goodness of Sorting, Paging, Filering, Grouping while having a ViewModel.

image
RIA Services Toolkit shows up in Add/Remove programs
http://www.microsoft.com/en-us/download/details.aspx?id=26939

Sept 2011 was the latest (in Oct 2012)

Fixing Login Refresh Problem

sdf

Sorting Paging and Goruping

DomainDataSource is great as it allows this.. Now DomainCollectionView provides the same type of functionality to your MVVM apps.

Command Pattern

image

 

using Microsoft.Windows.Data.DomainServices;
using RiaExample.Web;
using RiaExample.Web.Services;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.ServiceModel.DomainServices.Client.ApplicationServices;
using System.Windows.Data;

namespace RiaExample.ViewModels
{
    public class EmployeeViewModel : INotifyPropertyChanged
    {
        private EmployeeContext _context = new EmployeeContext();

        private DomainCollectionView<Employee> _view;
        private DomainCollectionViewLoader<Employee> _loader;
        private EntityList<Employee> _source;

        public EmployeeViewModel()
        {
            _source = new EntityList<Employee>(_context.Employees);
            _loader = new DomainCollectionViewLoader<Employee>(LoadEmployees, OnEmployeesLoaded);

            _view = new DomainCollectionView<Employee>(_loader, _source);

            // check to see if we're logged in when this is created
            //if (WebContext.Current.User.IsAuthenticated)
            //{
                CanLoad = true;
                RefreshData();
            //}

            WebContext.Current.Authentication.LoggedIn += new EventHandler<AuthenticationEventArgs>(Authentication_LoggedIn);
            WebContext.Current.Authentication.LoggedOut += new EventHandler<AuthenticationEventArgs>(Authentication_LoggedOut);
           _context.PropertyChanged += new PropertyChangedEventHandler(OnContextPropertyChanged);

            // did you know you could also write the property changed wireup like this?
            //   _context.PropertyChanged += OnContextPropertyChanged;
            // see the sidebar in the text for more information
        }

        void OnContextPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "HasChanges")
                SubmitChangesCommand.OnCanExecuteChanged();
        }



        private Employee _selectedEmployee;
        public Employee SelectedEmployee
        {
            get { return _selectedEmployee; }
            set
            {
                _selectedEmployee = value;
                NotifyPropertyChanged("SelectedEmployee");
                AddVacationBonusCommand.OnCanExecuteChanged();
            }
        }

        private void RefreshData()
        {
            using (_view.DeferRefresh())
            {
                _view.SortDescriptions.Clear();
                _view.SortDescriptions.Add(new SortDescription("Title", ListSortDirection.Ascending));
                _view.SortDescriptions.Add(new SortDescription("HireDate", ListSortDirection.Ascending));

                _view.GroupDescriptions.Clear();
                _view.GroupDescriptions.Add(new PropertyGroupDescription("Title"));

                _view.PageSize = 20;
                //_view.SetTotalItemCount(-1);
                _view.MoveToFirstPage();
            }
        }


        private bool _canLoad = false;
        public bool CanLoad
        {
            get { return _canLoad; }
            set
            {
                _canLoad = value;
                NotifyPropertyChanged("CanLoad");
                NotifyCanFilterChanged();
            }
        }


        private LoadOperation<Employee> LoadEmployees()
        {
            var query = _context.GetEmployeesQuery();

            if (!string.IsNullOrWhiteSpace(FilterString))
            {
                query = query.Where(e => e.Title.Contains(FilterString));
            }

            //return _context.Load<Employee>(query);
            //return _context.Load<Employee>(query.SortBy(_view));
            return _context.Load<Employee>(query.SortAndPageBy(_view));
        }

        private void OnEmployeesLoaded(LoadOperation<Employee> op)
        {
            if (op.HasError)
            {
                // should inspect .Error to see if permissions or something else
                Debug.WriteLine(op.Error.ToString());
                op.MarkErrorAsHandled();
            }
            else if (!op.IsCanceled)
            {
                _source.Source = op.Entities;

                _view.SetTotalItemCount(op.TotalEntityCount);

                if (op.TotalEntityCount > 0)
                {
                    SelectedEmployee = op.Entities.First<Employee>();
                }
            }
        }

        public ICollectionView Employees
        {
            get { return _view; }
        }





        void Authentication_LoggedOut(object sender, AuthenticationEventArgs e)
        {
            CanLoad = false;
        }

        void Authentication_LoggedIn(object sender, AuthenticationEventArgs e)
        {
            CanLoad = true;
            RefreshData();
        }


        private ViewModelCommand _submitChangesCommand = null;
        public ViewModelCommand SubmitChangesCommand
        {
            get
            {
                if (_submitChangesCommand == null)
                {
                    _submitChangesCommand = new ViewModelCommand
                    (
                        p => SubmitChanges(),
                        p => CanSubmitChanges
                    );
                }
                return _submitChangesCommand;
            }
        }
        public bool CanSubmitChanges
        {
            get
            {
                return WebContext.Current.User.IsInRole("Manager") &&
                    _context.HasChanges;
            }
        }

        public void SubmitChanges()
        {
            _context.SubmitChanges();
        }





        private ViewModelCommand _addVacationBonusCommand = null;
        public ViewModelCommand AddVacationBonusCommand
        {
            get
            {
                if (_addVacationBonusCommand == null)
                {
                    _addVacationBonusCommand = new ViewModelCommand
                    (
                        p => AddVacationBonus(),
                        p => CanAddVacationBonus
                    );
                }
                return _addVacationBonusCommand;
            }
        }

        public bool CanAddVacationBonus
        {
            get
            {
                return SelectedEmployee != null;
            }
        }

        public void AddVacationBonus()
        {
            if (SelectedEmployee != null)
            {
                //DateTime hireDate = new DateTime(2002, 05, 16);
                DateTime hireDate = SelectedEmployee.HireDate;

                var invokeOp = _context.CalculateVacationBonus(
                                hireDate, OnCalculateBonusInvokeCompleted,
                                SelectedEmployee);
            }
        }

        private void OnCalculateBonusInvokeCompleted(InvokeOperation<int> invokeOp)
        {
            if (invokeOp.HasError)
            {
                invokeOp.MarkErrorAsHandled();
            }
            else
            {
                Employee emp = invokeOp.UserState as Employee;
                if (emp != null)
                {
                    emp.VacationHours += (short)invokeOp.Value;
                }
            }
        }




        private ViewModelCommand _filterCommand = null;
        public ViewModelCommand FilterCommand
        {
            get
            {
                if (_filterCommand == null)
                {
                    _filterCommand = new ViewModelCommand
                    (
                        p => ApplyFilter(),
                        p => CanFilter
                    );
                }
                return _filterCommand;
            }
        }

        public bool CanFilter
        {
            get
            {
                return CanLoad &&
                    !String.IsNullOrEmpty(FilterString);
            }
        }

        public void ApplyFilter()
        {
            RefreshData();
        }

        private string _filterString;
        public string FilterString
        {
            get { return _filterString; }
            set
            {
                _filterString = value;
                NotifyPropertyChanged("FilterString");
                NotifyCanFilterChanged();
            }
        }

        protected void NotifyCanFilterChanged()
        {
            NotifyPropertyChanged("CanFilter");
            FilterCommand.OnCanExecuteChanged();
        }





        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Wiring up code is in EmployeeViewModel:

| | # 

Exposing data to other clients through endpoints

/RiaExample-Web-Services-EmployeeService.svc">/RiaExample-Web-Services-EmployeeService.svc">/RiaExample-Web-Services-EmployeeService.svc">/RiaExample-Web-Services-EmployeeService.svc">/RiaExample-Web-Services-EmployeeService.svc">http://localhost:<port>/RiaExample-Web-Services-EmployeeService.svc

Exposing an OData Endpoint

/RiaExample-Web-Services-EmployeeService.svc/OData">/RiaExample-Web-Services-EmployeeService.svc/OData">/RiaExample-Web-Services-EmployeeService.svc/OData">/RiaExample-Web-Services-EmployeeService.svc/OData">/RiaExample-Web-Services-EmployeeService.svc/OData">http://localhost:<port>/RiaExample-Web-Services-EmployeeService.svc/OData

image
http://localhost:53287/RiaExample-Web-Services-EmployeeService.svc/OData/$metadata – to look at metadata

http://.../RiaExample-Web-Services-EmployeeService.svc/OData/ContactSet
image
Use chrome instead.

set download limit via:

http://.../RiaExample-Web-Services-EmployeeService.svc/OData/EmployeeSet – to access root entities.. append Set.

image

Currently accessing a single entity by ID isn’t supported.

image
Needs Excel2010 to run.

image
Built into Excel2013 need to enable it – File, Options, AddIns, Manage, Com

image
http://localhost:53287/RiaExample-Web-Services-EmployeeService.svc/OData/EmployeeSet

Exposing a JSON Endpoint

Microsoft.ServiceModel.DomainServices.Hosting

C:\Program Files (x86)\Microsoft SDKs\RIA Services\v1.0\Toolkit\Libraries\Server

adding a reference to the dll needed for json in the Web Project

http://www.microsoft.com/en-us/download/details.aspx?id=26939 – WCF RIA Services…need this installed.

Add in web.config:

<add name="JSON"  type="Microsoft.ServiceModel.DomainServices.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

image
Convention is Get<EntityName>s
http://localhost:53287/RiaExample-Web-Services-EmployeeService.svc/JSON/GetEmployees

image
Receiving JSON

Exposing a SOAP Endpoint

image

Unlike JSON, SOAP endpoints ends up working right at the root level too.

http://localhost:53287/RiaExample-Web-Services-EmployeeService.svc

image
No SOAP

image
SOAP turned on in Web.Config.

WCF RIA Services has built in support for SL and JS…but for other clients OData, JSON and SOAP.

Authentication and Authorisation

  • Authentication – identifying a user
  • Authorisation – Granting a user access

Forms based authentication and Windows auth

Can’t seem to get Windows Auth working properly – just says authenticating and doesn’t come up with my domain/username

http://stackoverflow.com/questions/2679187/silverlight-ria-services-auth-active-directory?rq=1 -

image

Authorisation:

Doing manager role.

image
Using Project, ASP NET Configuration

Dave is a Manager
Bob is a Registered User

image
Apnnotating the service.

image
When get an authorisation exception.  Must handle this gracefully

image

Can easily handle on the client too eg to display/hide visibility of elements, however must always secure on the server too.

image
Display or hide the Submit button based on role.  Want this to run somewhere when a user logs in or out

Presentation Models

Contact and Employee are tied, yet conceptually the same..

  • Expose the contact info as first-class fields of a logical employee entity
  • Limit the other fields that are returned to the client

image
An aggregate Employee class that contains fields from both Employee and Contact

image
Fewer fields in this aggregate.

Update

image
Manual plumbing land – highly recommended to build tests around this.

image
Inserting

This allows us to benefit from WCF RIA with the benefit of decoupling

  • Validation flow

Business Logic in Entities

image
\Models\Shared\Employee.shared.cs

Not recommended if using data outside of Employee class

Domain service or properties on the entity are great place to put logic you want accessible to the client or server, but only executed on the server.

Anything with .shared.cs is copied to the client on build.

image
Not a great debugging experience.

http://www.scottleckie.com/2010/04/code-4004-unhandled-error-in-silverlight-application/

image
Trick was to let SL know we are handling validation:

image

<riaControls:DomainDataSource x:Name="DataSource" AutoLoad="True" QueryName="GetEmployees" FilterOperator="And" PageSize="15" LoadSize="30"
                                      SubmittedChanges="machineDomainDataSource_SubmittedChanges">

image
Other way to get more of a clue is to debug, then detach all (from debug menu)

| | # 
# Monday, 22 October 2012

image

Can see query method.  Also if there are errors, can see them.

http://10rem.net/blog/2011/04/13/silverlight-5-debugging-bindings-with-xaml-breakpoints – Conditional breakpoints

| | # 

image

Generated a POCO datastore.. and made his own domain service.

Very clear with no edmx..

Also does an authentication example.

2.  Making Domain service business rules

Client Side caching

4. Validation Summary

custom validation – in the domain service using ValidationResult / ValidationException

eg CampaignValidator class with a static member…

.shared.cs validator… purely client side validation.!

**USe fiddler

Unit Testing

SLUT – SilverLight Unit Testing

WCF RIA test project – disable generated code.

OData – OPen Data Proocol

| | # 
# Saturday, 20 October 2012
  • Auto creation of CRUD methods for entities
  • Auto generation and sync of service methods and their client side proxies
  • Validation rules / arbitrary business logic methods that are shared
  • ASP.NET Security

image
UI Tooltips, validation requires no trip to server.  Child window spins round from login.

image
Default membership provider uses a db for developers as default.

image

Text values help in ApplicationStrings resource file

image
Wiring it up

Exposing Data with the Domain Service

AdventureWorksEntities.edmx

image
The template creates the INCORRECT edmx file for RIA

image
Correct – default code gen strategy

image
Top level Visual C# already installed

image

2 classes created in the services folder:

  • EmployeeServics.
  • EmployeeService.metadata.cs

Conventions

Query

LINQ to Entities and EF

image

Query methods fall into three primary buckets:
■ Methods returning a single concrete instance of an entity
■ Methods returning a collection or enumerable of zero or more entities
■ Methods returning an IQueryable of the entity

Composed Queries

Can have the Grid bound to GetSalariedEmployees then it can do sorting/paging/filtering on that query.. but all done on the SQL Server

PreSorted data on server:

public IQueryable<Employee> GetEmployeesSorted()
{
return from Employee emp in ObjectContext.Employees
orderby emp.Title, emp.HireDate
select emp;
}


and use it like this on the client:
EmployeeContext context = new EmployeeContext();
EntityQuery<Employee> query =
from emp in context.GetEmployeesSortedQuery()
where emp.SalariedFlag == true
select emp;

2 steps happen together on the server.

Insert, Update, and Delete Methods

update, coppies…

Invoke

Perform a calculation or return a piece of data eg CalculateVacationBonus which returns an int.

Used where we don’t need:

  • Change tracking
  • Deferred execution

Shouldn’t be used to load data

Using Domain Service from Silverlight

  • Connect via code
  • Connect via XAML (easiest)

image

image

image

image
This client side LINQ will be executed on the SQL Server.

DomainDataSource Control

image
No code in code behind.  Had to add a reference to System.Windows.Controls.DomainServices

Filtering, Sorting, Grouping and Paging

One of the most compelling reasons to use DomainDataSource!

image
Filters on each letter pressed

FilterDescriptors – in our case we are using Contains.  Can use this descriptors to create any query

Sorting

image

<riaControls:DomainDataSource.SortDescriptors>
<riaControls:SortDescriptor Direction="Ascending"
PropertyPath="Title" />
<riaControls:SortDescriptor Direction="Ascending"
PropertyPath="HireDate" />
</riaControls:DomainDataSource.SortDescriptors>

Note how the grid knows what has been sorted (arrows) by default.

image
Sorting was done on the SQL Server.

Grouping

<riaControls:DomainDataSource.GroupDescriptors>
<riaControls:GroupDescriptor PropertyPath="Title" />
</riaControls:DomainDataSource.GroupDescriptors>

image

Paging

  • Preload everything and allow scrolling
  • Infinite scroll that performs lazy fetching
  • Data paging

 

  • PageSize 15
  • LoadSize 30
  • DataPager control

this would make every other page hit the database

image

 

Updating Data

Using the DataForm UI

image

<sdk:DataGrid x:Name="EmployeeGrid" ItemsSource="{Binding Data, ElementName=DataSource}" Grid.Column="0" Margin="5,38,5,5" />

            <dataForm:DataForm Grid.Column="1" Margin="5 40 0 40"
                ItemsSource="{Binding Data, ElementName=DataSource}"
                CurrentItem="{Binding SelectedItem,ElementName=EmployeeGrid, Mode=TwoWay}" />

Note how binding it TwoWay for current navigation so can use either view to navigate through data.

image
Save changes button.  It is greyed out until there are actual changes which means you have to click to anothe box before you can click on Submit

<Button x:Name="SubmitChanges"
                Grid.Column="1" Margin="5"
                HorizontalAlignment="Right"
                VerticalAlignment="Top"
                Height="25" Width="120"
                Command="{Binding SubmitChangesCommand, ElementName=DataSource}"
                Content="Submit Changes" />

Calling an Invoke Operation from the Client

asd

image
Calling ‘server side’ logic to calculate the vacation bonus.

image
Server side logic in EmloyeeService.  Notice the method takes only 1 paramter, but we’re calling it with 3 above – a callback and a Data.  The Data in this case is an Employee, which we need to use in the callback to update the object (VacationHours)

The entity is then marked as HasChanges=true, so then it is eligible for SubmitChanges call ie Submit button goes ungrey.

ToolTips and Validation

image
Tooltip on BirthDate now works

image
Editing the server side EmployeeService.metadata.cs

image

image
EmployeeService.metadata.cs, Employee, EmployeeMetaData nested class

| | # 
( MVVM | Silverlight )

Continued Ch33

Have seen how to pull code out of the code-behind and into ViewModel, and then out of the ViewModel into Services.

  • less brittle
  • testable
  • reuasblep

Ways for XAML elements to invoke methods in the ViewModel:

  • ICommand – traditional and supported in most MVVM toolkits
  • CallMethodAction – introduced in Expression Blend 4

Commands and CallMethodAction are a great way to separate the View from ViewModel, keeping the contract at just a binding statement or name of a method.

ICommand

More Vacation button disabled by default

image

image
AddVacationBonusCommand is a property on EmployeeListViewModel

CallMethodAction

Introduced with Expression Blend4 – an easy and designer friendly way to wire any event from any control to a method.

Installed Expression Blend Preview for Silverlight 5.

reference Microsoft.Expression.Interactions, System.Windows.Interactivity

image
Easy way to wire up a button click whilst not being tightly coupled.

View Specific Entities

eg not using Employee object all the way to the UI.  If employee changes in the db, then have to change the UI.

So update all client side places that once used Employee to use EmployeeViewModel.

image
Just surfacing the required data to the UI using EmployeeViewModel class which the EmployeeListViewModel uses

Interfaces, IoC and ViewModel Locators

EmployeeList View is tightly coupled to EmployeeListViewModel

image

Similarly the EmployeeListViewModel is tightly coupled to the EmployeeDataService and EmployeeVacationBonusService.

  • can be useful to not have this if want to swap out datastore

Leave for now and see what can do with testing without this..

Testing

image
Need to set the correct aspx as start page otherwise it will try to run the test project.

http://silverlight.codeplex.com/releases/view/78435 – Silverlight 5 Toolkit

Silverlight Unit Testing Framework..didn’t install the templates into VS2012

http://visualstudiogallery.msdn.microsoft.com/caca1e81-becb-41e4-9110-bc247f3f400b?SRC=Home

C:\Program Files (x86)\Microsoft SDKs\Silverlight\v5.0\Toolkit\dec11\Testing  - DLLs are here

image
Got this working on already existing templates

image

Testing the EmployeeListViewModel

image

Using NUnit

http://www.frenk.com/2011/11/silverlight-unit-testing-with-nunit-yes-you-can-without-hacks/

Test 'MvvmApplication.NUnitTests.EmployeeListViewModelTests.SelectedEmployeeCanBeSetAndRetrieved' failed: System.IO.FileNotFoundException : Could not load file or assembly 'System.Windows, Version=5.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' or one of its dependencies. The system cannot find the file specified.
    at MvvmApplication.ViewModels.EmployeeListViewModel..ctor()
    Class1.cs(20,0): at MvvmApplication.NUnitTests.EmployeeListViewModelTests.SelectedEmployeeCanBeSetAndRetrieved()

Could use SilverUnit which doesn’t have these issues.

http://stackoverflow.com/questions/10891403/silverlight-5-and-nunit – had to add in System.Windows into the Unit Testing project from C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v5.0

image

I added in a normal project reference for MvvmApplication.Core as got version conflicts when just adding the dll from debug (however I get a warning doing it this way)

Async Testing

Added in System.ServiceModel into the Nunit project.

The SilverlightTest base class supplies the critical EnqueueTestComple method, that tells the test framework that the method is complete and can release it from its holding pattern created by the async attribute.

**can’t easily create a new unit test project.

image

Copied old test project across, then wired up the .Web project to include the newly copied project.

So can now do tests with TestDriven.NET on the ViewModels, and the SL Test Runner on Async.

 

http://code.google.com/p/nunit-silverlight/ – unofficial port of unit for SL …Nov 2010.  SL4

http://agunit.codeplex.com/ – R# plugin to allow unit test to run… supports:  MS Test Framework for SL Toolkit, NUnit-Silverlight, xUnitContrib-Silverlight… quite up to date 2012.

http://blogs.msdn.com/b/bharry/archive/2012/07/09/coded-ui-testing-support-for-silverlight.aspx – coded UI support for SL 5.

| | # 
# Thursday, 18 October 2012
( MVVM | Silverlight )

Ch33 in Silverlight 5 in Action book.

Testing is one of the main drivers behind MVVM

  • New project – Silverlight Navigation Application

image
Issue with blurry fonts in IE10

 

image
Database is slightly different from one in book

This one was from SQLExpress2008.  http://msftdbprodsamples.codeplex.com/releases/view/4004  this is the database schema that is used in the book (SQL2005 version)

image

image
The correct schema

Webservice

image

A regular Silverlight-enabled WCF service: a SOAP web service built using WCF

image
Locking the port too.

image
Added a new EmployeeList page and wired it into the navigation.  Now doing a child window called EmployeeDetail.

image
TextBlocks (labels) and TextBox’s (inputs) with TwoWay binding.

Typical Code Behind Solution

image

image
Should be like this (default code gen)

image
But was this (no code gen)

image

Page Caching is turned on.

image

image

image
Child window popping up when press edit.  We don’t clone the Employee here, so cancel doesn’t work if we change a value.. it automatically updates the underlying object, but doesn’t update the database.

image
In EmployeeList when edit button is pressed, we make a new EmployeeDetail View as pass it the Employee.  When the Employee property of the View is set, we set the DataContext to use that employee too.

  • Filling a list from a service call
  • Passing information from 1 view to another

MVVM Version

The most popular pattern for SL and WPF.

  • testable
  • code reuse
  • elimates many of the binding problems

The View uses Binding and Messages (actions or commands) to communicate with the ViewModel

image
Base ViewModel.  INotifyPropertyChanged is required when other classes may be bound to your class.

image
Codebehind in the XAML makes a EmployeeListViewModel then calls the LoadEmployees method on it.
Also sets up an event which fires when loading is complete so loading window disappears

Single Responsibility

image
Driving out into a separate class Vacation bonus logic away from the ViewModel.  However this depends on Employee.

image
ViewModel

image
Better version of vacation as no dependency

image
Calling code in EmployeeListViewModel

Data Access and Service Calls

Abstracting service/data access calls away from the ViewModel

image

However lots of EventHandler code in DataService, ViewModel and Code Behind.

| | # 
# Wednesday, 17 October 2012
  • Exception based validation capabilities are not the way to go.
  • IDataErrorInfo and INotifyDataErrorInfo are the ways forward (SL4)
  • DataAnnotations are geared to work with DataGrid and DataForm

source code is missing for this chapter

| | # 
  • DataGrid (SL2) is most often used
  • DataForm (SL3)..like a grid rotated 90degrees

image

<Grid x:Name="LayoutRoot" Margin="15">
    <data:DataGrid x:Name="myDataGrid" />
</Grid>

AutoGenerateColumns property default to true.

image
DataGrid can support millions of rows of data. – UI Virtualisation

Customising the Rows

image

image
Using a template to show details when selected.

Can use HeadersVisibility="All" property to show vertical ‘header’ too.

DataGrid Sorting

<data:DataGridTextColumn Binding="{Binding Name, Mode=OneWay}" Header="Name" SortMemberPath="Name"/>

 

DataForm

Can be thought of as a single row grid turned on its side.  Can do similar things:

  • Readonly or editable
  • Infer column names

image

image
Validation coming via DataAnnotations.  ‘VCR’ controls ie CommandButtons which includes Add, Cancel, Commit, Del, Edit, Navigation or None.  Controls are inferred from type.

image

<UserControl.Resources>
       <local:PeopleRepository x:Key="repository" />
   </UserControl.Resources>

   <Grid x:Name="LayoutRoot" Margin="30">
       <toolkit:DataForm DataContext="{StaticResource repository}"
                         CommandButtonsVisibility="All"
                         ItemsSource="{Binding People}"       
                         CurrentIndex="0">
       </toolkit:DataForm>
   </Grid>

One of the easiest things to do is to supplyl and ObservableCollection<T> to the ItemsSource property of the DataForm.

| | # 

Binding is a powerful way to create a connection between the UI and source of data

Can create a binding using two different approaches:

  • Dynamically create a binding at runtime
  • Specify a binding at design time

1) RunTime

image

<Grid x:Name="LayoutRoot" Background="White">
       <TextBox x:Name="myTextBox"></TextBox>
   </Grid>

2) Design time (more often used)

image

TImeOfDay is a property of the DateTime class, just like Date and Now.

image

image

image

image
A simpler example showing binding to a dateTime object.

http://stackoverflow.com/questions/2430664/current-date-in-silverlight-xaml-textblock – getting the time updating… couldn’t get it to work.

Binding Mode

  • OneTime – any changes made to the source wont be automatically sent to the target
  • OneWay – default.  Can automatically receive changes from a source property
  • TwoWay – two way eg CRUD data

Binding  has a:

  • Source
  • Target – typically a UI element

Binding to a Property

Can bind to any CLR property

image
If this was TwoWay binding we would see the Name end if fffff.

To update the target, must create a change-notification handler which must implement INotifyPropertyChanged

Binding to an Object

If want to bind multiple properties to a UI then it becomes tedious (as shown in commented out DataContexts below).  So we can use the DataContext property on a parent.

image
DataContext set on the parent Grid in code

image
Tool friendly way of setting DataContext in XAML.  No code behind DataContext

image
Object is instantiated in XAML.  Remember to create a parameterless constructor on emoticon

To reference the object in XAML via code:

image
Name my UserControl – eg Example

image
Then use .Resources to get at the XAML created object. (see EmoticonExample)

Binding to a UI Element

image
Counts the number of characters written.

Use ElementBinding (SL3)..allows us to bind properties of one framework element to another.

  • StackPanel
  • TextBlock – label
  • TextBox – called tweetText
  • TextBlock – bound to tweetText.Text.Length

<Grid x:Name="LayoutRoot" Background="White">
      <StackPanel Orientation="Vertical" Margin="50">
          <TextBlock Text="Tweet (max 140 characters)" />
          <TextBox x:Name="tweetText"  MaxLength="140" Text="Right now I'm writing a book" />
          <StackPanel Orientation="Horizontal">
              <TextBlock Text="{Binding Text.Length, ElementName=tweetText}" />
              <TextBlock Text="/" />
              <TextBlock Text="{Binding MaxLength, ElementName=tweetText}" />
          </StackPanel>
      </StackPanel>
</Grid>

Relative Source Binding

Should be used sparingling as hard to debug.  Here we are binding an element to itself.

public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private string _pageTitle = "Silverlight 5 in Action";
        public string PageTitle
        {
            get { return _pageTitle; }
            set { _pageTitle = value; }
        }

    }

<UserControl x:Class="RelativeSourceExample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="400"
             DataContext="{Binding RelativeSource={RelativeSource Self}}" Margin="0,-3,0,3">
    <Grid x:Name="LayoutRoot"
          Background="White">
        <TextBlock Name="myTextBlock" Text="{Binding PageTitle}" />
    </Grid>

</UserControl>

Binding to an Indexed Element

image

image

Binding using a string Key

Using a Dictionary<string, Emoticon> and referencing the string in the binding:

<UserControl x:Class="EmoticonExample.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             xmlns:local="clr-namespace:EmoticonExample"
             d:DesignHeight="300"
             d:DesignWidth="400">

    <UserControl.Resources>
        <local:Repository x:Key="repository" />
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot"
          DataContext="{StaticResource repository}">
        <StackPanel Width="100" HorizontalAlignment="Center">
            <Image Source="{Binding Emoticons[Smiley].Icon}" Stretch="None" />
            <TextBlock Text="{Binding Emoticons[Smiley].Name}" />
        </StackPanel>
    </Grid>
image

Binding to an Entire Collection

myListBox.ItemsSource – can be used to bind any collection that supports IEnumerable

image

Binding to Dynamic Properties

Stronly typed return values from services on the net its not always possible to have classes defined at compile time, so can use ICustomTypeProvider and Refelection to help.

| | # 

image
Ch25 – Creating images

Ch28 – pop-ups, windows and full screen apps.

Ch29 – Navigation template

| | # 
# Tuesday, 16 October 2012
  • Canvas
  • StackPanel
  • WrapPanel – eg Windows explorer which wraps images
  • Grid (most commonly used)..like HTML table.. also default for UserControl.. need to know number of rows and cols in advance.  Can easily resize (not rescale) content

TextBox – a control

RichTextBox – contains bold, drop downs etc..  a control

TextBlock – not a control…it is a UIElement

 

Button – a control?

 

ListBox

ComboBox

 

XAML Resources

  • Styles
  • Control Templates

Ch15. Customer Markup Extensions (SL5)

Type Converters

| | # 

XAML is a declarative language that enables you to create and initialise .NET objects in XML

Routed Events and event bubbling – allow events to be handled be each level above

Commands – allows us to remove the event handler from the code behind.  It is wired up from the XAML as Command=”{Binding SaveCommand}”
commands also support auto disabling of the controls if the command can’t run.. via implicit binding to ICommand.CanExecute

| | # 

XAML is a representation of CLR objects.  Each tag has an equivalent CLR object behind it.

image

DataTemplates – chunck of XAML used to format each item in the list.

image
ListBox with content taking up full width of ListBox without horizontal scrolling.
Then an ItemTemplate with a DataTemplate and a Grid.
autosized first column and full width second column

Bind an image element to the Image Property of Tweet

Bind a TextBlock to the Message Property of Tweet

image
Observable collection.  Bindings.  Async network call.  Callback event, lambda and linq.

image
Binding our IObservable collection of Tweets to the ListBox TweetList.ItemsSource

image
Publish to live to check it works.  In fact had to go down to .NET4.  Could have put .NET4.5 on the Win2008R2 server:  http://msdn.microsoft.com/en-us/library/5a4x27ek.aspx

| | # 
# Friday, 05 October 2012
( MVVM | Silverlight )

http://msdn.microsoft.com/en-us/library/gg430857(v=pandp.40).aspx

image
The app takes data, then writes out to Output window when press submit

image
Wiring the Questionnaire View into the MainPage.xaml

In the View:

View – xaml
ViewModel – What the view binds towards a particular view(display)
Model – bottom

| | # 

http://www.youtube.com/watch?v=QWELU7v5GxA&feature=related

History

SL 1.0 (WPF Everywhere, JavaScript with Benefits) in 2007
SL 2.0 (CLR, DLR, DeepZoom) in 2008
SL 3.0 (2D/3D perspective eg tilt, GPU, Element Binding, Out of Browser…eg disconnected versions) in 2009
SL 4.0 (WebCam and mic, html inside SL, MEF – discoverability, WCF RIA, COM, Chrome support) in 2010
SL 5.0 in 2011

| | # 
# Thursday, 04 October 2012

http://www.dotnetrocks.com/default.aspx?showNum=737  - 2012

http://www.dotnetrocks.com/default.aspx?showNum=687 – SL and HTML5 2011

http://www.dotnetrocks.com/default.aspx?showNum=684 – SL5 Pete Brown

 

http://www.dnrtv.com/default.aspx?showNum=198 – SL5 demo

 

Pluralsight – great RIA Services, Unit Testing video http://pluralsight.com/training/courses/TableOfContents?courseName=silverlight-ria-services-advanced-topics&highlight=yacine-khammal_riasvc-m5*6!yacine-khammal_riasvc-m8*6#riasvc-m5

 

http://xamlspy.com/learn/introduction 

http://archive.msdn.microsoft.com/wcfbinaryinspector – WCF Binary inspector for Fiddler

http://www.lhotka.net/Default.aspx

 

http://www.microsoft.com/en-us/download/details.aspx?id=28357 – WCF RIA Services V1.0 SP2.. 16/8/2012

 

http://code.msdn.microsoft.com/silverlight/How-to-open-a-WCF-RIA-171139fb  - WCF RIA exposed to HTML5/jquery   - 2011

http://code.msdn.microsoft.com/Getting-Started-WCF-RIA-1469cbe2 – Getting Started WCF RIA Services

 

http://channel9.msdn.com/Shows/SilverlightTV/Silverlight-TV-79-Data-Binding-Debugging  Data Binding Debugging in SL5
  Binding on expressions in XAML..anything through the binding statement

http://channel9.msdn.com/Shows/SilverlightTV/Silverlight-TV-41-Top-Tips-for-WCF-RIA-Services  - Deep dive for RIA Services

http://code.msdn.microsoft.com/silverlight/Getting-Started-WCF-RIA-1469cbe2 – Getting started simple with SL and WCF RIA

HTML5 / Knockout

http://css.dzone.com/articles/upshotjs-knockoutjs-html5

| | # 

http://channel9.msdn.com/Blogs/mtaulty/Prism--Silverlight-Part-4-The-Unity-Bootstrapper

 

http://www.dotnetrocks.com/default.aspx?showNum=737  - 2012

http://www.dotnetrocks.com/default.aspx?showNum=687 – SL and HTML5 2011

http://www.dotnetrocks.com/default.aspx?showNum=684 – SL5 Pete Brown

 

http://www.dnrtv.com/default.aspx?showNum=198 – SL5 demo

 

Pluralsight – great RIA Services, Unit Testing video http://pluralsight.com/training/courses/TableOfContents?courseName=silverlight-ria-services-advanced-topics&highlight=yacine-khammal_riasvc-m5*6!yacine-khammal_riasvc-m8*6#riasvc-m5

 

http://xamlspy.com/learn/introduction 

http://archive.msdn.microsoft.com/wcfbinaryinspector – WCF Binary inspector for Fiddler

http://www.lhotka.net/Default.aspx

 

http://www.microsoft.com/en-us/download/details.aspx?id=28357 – WCF RIA Services V1.0 SP2.. 16/8/2012

 

http://code.msdn.microsoft.com/silverlight/How-to-open-a-WCF-RIA-171139fb  - WCF RIA exposed to HTML5/jquery   - 2011

http://code.msdn.microsoft.com/Getting-Started-WCF-RIA-1469cbe2 – Getting Started WCF RIA Services

 

http://channel9.msdn.com/Shows/SilverlightTV/Silverlight-TV-79-Data-Binding-Debugging  Data Binding Debugging in SL5
  Binding on expressions in XAML..anything through the binding statement

http://channel9.msdn.com/Shows/SilverlightTV/Silverlight-TV-41-Top-Tips-for-WCF-RIA-Services  - Deep dive for RIA Services

http://code.msdn.microsoft.com/silverlight/Getting-Started-WCF-RIA-1469cbe2 – Getting started simple with SL and WCF RIA

HTML5 / Knockout

http://css.dzone.com/articles/upshotjs-knockoutjs-html5

| | # 
# Thursday, 27 September 2012

http://chinookdatabase.codeplex.com/ – installed database in .\SQLEXPRESS

image
From Silverlight, Create Silverlight Business Application

User.shared.cs – shared code!

Create EF Model in Web

Chinook.edmx

image
Did EF get the FK associations?

Domain Service

image
adding domain service to WebApp

http://support.microsoft.com/kb/2745294  - Workaround to get away from DbContext default back to ObjectContext

image

image
and then Entity Framework Profiler:

image
Initialising the profiler in the Domain Service.. could have been anywhere.

image

Adding System.Windows.Controls.DomainServices to the SL project

Add a namespace reference in XAML called ds

Add DomainDataSource – allow us to bind to our domain data context

Add my: namespace…MusicStoreManager.Web

**Got up to pagination at 28:28

Pagination of Data

image
Each sort spits out a different query

image
SQL is top30 etc.. not hand crafted.

image
Seemed to be working, then I got this error.

image
Just forcing an orderby before a skip.

In RIA Services – often can be dealing with Data in memory ie if we go back to the page 1.. wont hit the database again.

| | #