Showing posts with label Silverlight. Show all posts
Showing posts with label Silverlight. Show all posts

Friday, July 15, 2011

Easily Disable Row Selection for a Silverlight DataGrid

This technique actually prevents the row from being selected and prevents an unwanted cell from being selected. The visual effect is that the row or cell in that row never appears to be selected.

I assume you know how to load you DataGrid with data, etc. In my example, I only have one column of data. The trick to this solution is almost all in code behind. Also, this all assumes that you have set IsReadOnly="True" either in the XAML or the code behind.

 

In this example my DataGrid is named dgAnnouncements. I handle the SelectionChanged event as show in the method below.

private void dgAnnouncements_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    dgAnnouncements.SelectedItem = null;
}

The above gets us most of the way there, however you will notice that the cell itself can still be selected. To handle this we have to do a trick.

In the XAML for the DataGrid you will need to add an invisible column at position 0 so that we can select it whenever someone tries to select another cell that they can see.

Here is an example of the XAML for the DataGrid.

<sdk:DataGrid x:Name="dgAnnouncements"
ItemsSource="{Binding Data, ElementName=dsAnnouncements}"
AutoGenerateColumns="False"
IsReadOnly="True"
CurrentCellChanged="DataGrid_CurrentCellChanged"
SelectionChanged="dgAnnouncements_SelectionChanged">

    <sdk:DataGrid.Columns>
        <sdk:DataGridTextColumn Binding="{Binding Path=Nothing}" MinWidth="0" MaxWidth="0" />
        <sdk:DataGridTextColumn Binding="{Binding Path=Title}"  />
    </sdk:DataGrid.Columns>
</sdk:DataGrid>

Here is the code behind to redirect the current cell to our invisible cell.

private void DataGrid_CurrentCellChanged(object sender, EventArgs e)
{
    if (dgAnnouncements.CurrentColumn != null)
    {
        dgAnnouncements.CurrentColumn = dgAnnouncements.Columns[0];
    }
}

Thursday, July 14, 2011

Creating your own MessageBox in Silverlight

The MessageBox built into Silverlight is nice enough to use for simple OK, Cancel scenarios, but sometimes I want to change the text of the buttons in the MessageBox. For example, I may want Yes, No instead of OK, Cancel or maybe completely different text like Finished Now, Finish Later. The syntax of the MessageBox is simple enough so I decided to mirror it as closely as I could. This makes it as painless as possible to change from a MessageBox to my message box. The biggest difference in usage that I couldn’t figure out how to get around is that the MessageBox is a blocking call, but the UI thread still continues to render. When I tried to do the same, the UI thread did not continue to render. I looked at the code for MessageBox and it appears to be calling a Windows native MessageBox that is most likely different for OS that Silverlight is implemented on. So, I decided that in the Silverlight manor I would use asynchronous calls (event handlers) instead of a blocking call. When I use delegates the code is similar to using MessageBox.

Okay, enough description I think. Here is source code for my version of MessageBox called MessageBox2

Download Source Code for Control

MessageBox2.xaml.cs   MessageBox2.xaml

Usage

You’ll notice I have 3 Show() methods instead of the standard 2 that MessageBox has. The reason is that I added one so that you can specify the text of OK and Cancel buttons. You’ll notice that I don’t return a MessageBoxResult and instead return the MessageBox itself.  Below is how you would use the MessageBox versus MessageBox2.

MessageBox

MessageBoxResult result = MessageBox.Show("This is a choice test", "Some caption", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
    DoSomethingUsefulHere();
}
else if (result == MessageBoxResult.Cancel)
{
    DoSomethingUsefulHere();
}

MessageBox2

var msgBox2 = MessageBox2.Show("This is a choice test", "Some caption", MessageBoxButton.OKCancel, "Yes", "No");
msgBox2.OKButton.Click += delegate(object sender2, RoutedEventArgs e2) { DoSomethingUsefulHere(); };
msgBox2.CancelButton.Click += delegate(object sender2, RoutedEventArgs e2) { DoSomethingUsefulHere(); };

You could also use the Closed event and check the DialogResult to see if it was accepted or cancelled. Also, notice I changed the OK button to Yes and the Cancel button to No.

Wednesday, June 15, 2011

Compiler error with VS2010 SP1 and SL 4 with WCF RIA Services and Entity Framework 4

Did you have a VS2010 project (before installing VS2010 SP1 or RIA Service Pack 1) that used Silverlight 4 and WCF RIA Services and Entity Framework 4 (EF4) and now that VS2010 Service Pack 1 is installed (or maybe some other framework) your Silverlight Project no longer compiles. Chances are if you are using RIA Services you may have created files that you want to share (called Shared Code)on the Server and the SL Client. This is done in RIA by using the .shared.cs file extension on a filename.

After I installed either VS2010 SP1 or RIA Services SP1 and then I tried to compile my project and got a compiler error similar to:

error CS0102: The type 'MyApp.Model.MyClassHere' already contains a definition for 'MyPropertyHere'

I learned that this may be a RIA Services SP1 regression bug from this forum. The beta had issues also.

It appears that this MAY be fixed now, but I’m not sure since I don’t have an issue exactly like what they had. I only have the issue if I have to shared files and one the classes (in one of the files) has a property or method that has a return type that is the other class type. If I get rid of that dependency and just return the object type instead then it compiles fine. While returning the type object, I have to cast every time I use it and that is silly and kind of a pain / ugly.

I hope that helps someone. If anyone else has this issue I’d love to know about it.

Wednesday, May 4, 2011

Why aren’t my ForeignKeys being loaded on my Custom Dynamic Data page?

This is one entry in a series of blog entries:

If you look at Part I and Part II, you may have noticed that the Product Category is a textfield when it should be a Drop Down List of the Product Categories. If this were a page that was in the DynamicData\CustomPages directory then you would not be having this problem. The reason we are having this problem is because we are calling EnableDynamicData() on our FormView which is great to get basic dynamic data functionality, but it doesn’t know how to load all the metadata for the Product entity. If you debug you will see that the ProductCategory DynamicControl column is not of type MetaForeignKeyColumn. After futher debugging you will see that much of the other metadata from the model is actually missing as well. Thankfully, the fix is very easy.

Change from:

protected void Page_Init(object sender, EventArgs e)
{
     FormView1.EnableDynamicData(typeof(MyDynamicDataExample.Models.Product));
}

to this:

protected void Page_Init(object sender, EventArgs e)
{
    // to get all the goodness like foreign-keys, etc we need to tell it to use our model
    FormView1.SetMetaTable(Global.DefaultModel.GetTable(typeof(MyDynamicDataExample.Models.Product)));
}

Also, from what I can tell the AutoLoadForeignKeys=”true” attribute of the DynamicDataManager has no bearing on whether the Drop Down List is populated or not.

You may have also noticed that the ProductCategory field when in ReadOnly mode shows a link with an number showing instead of the nice text description of the product category.  Luckily, this is an easy fix as well. In the AWDomainService.cs find we need to change the GetProducts() method to include the ProductCategory navigation property. This will cause the SQL that is generated to bring in the ProductCategory table.

Change from:

public IQueryable<Product> GetProducts()
{
    return this.ObjectContext.Products.OrderBy(o => o.Name);
}

to this:

public IQueryable<Product> GetProducts()
{
    return this.ObjectContext.Products.Include("ProductCategory").OrderBy(o => o.Name);
}

The change above will do the trick. However, if you are using this Domain Service with a Silverlight Client, you should also update the AWDomainService.metadata.cs such that the ProductCategory property on the ProductMetadata class has the Include() attribute. If you don’t have both of these Silverlight will not populate the ComboBox (assuming that is what you are using in Silverlight).

Change from:

[Display(Name = "Product Category")]
public ProductCategory ProductCategory { get; set; }

to this:

[Include()]
[Display(Name = "Product Category")]
public ProductCategory ProductCategory { get; set; }

You can download the complete source here.

Tuesday, April 26, 2011

AzGroups 8th Annual Scott Guthrie Event

Things to check out:

NUGET

(pronounced NEWGET) – it is built into VS2010 (Visual Studio 2010) and makes finding, downloading, and installing libraries (open source included) into your project. It even does some configuration in the config files, etc. Pretty awesome. You can get it here.

elmah

It is an error logging facility that is completely pluggable that can added to a running ASP.NET web application without re-compilation or deployment. When an exception occurs it logs it, but allows you decide where to log it to such as a database, RSS, email, etc. It also records A LOT of VERY useful information for determining what happened.  See here for more details.

IIS Express

Can be used side-by-side with the built in web server (Cassini) in VS2010. It launches fast just like the web server built into VS2010, but doesn’t require you setup virtual directories, etc like you do with IIS (full version). You now get best of both worlds. It now let’s you develop using the IIS 7.x feature-set. It is now as easy to use as the web server built into VS2010. It doesn’t require admin account. You don’t have to change any code or the way you work to take advantage of it. See Scott’s blog for more details.

Web Matrix

You should still continue to use Visual Studio for professional work, but Web Matrix project are great for hobby, family sites, etc. It has been totally reworked to be a task based tool. It makes publishing very easy. If the site gets more complex the project can be opened up in Visual Studio.

SQL Server Compact Edition 4

It is great for ASP.NET development. It is light weight and free. It is an embedded database (no SQL Server required) so it is in the binaries (bin directory) that you can xcopy to your server. You can use Standard SQL Server syntax so anything that supports the ADONET provider model (such as LINQ and EF) will work. You are also licensed to redistribute it. All this means you can now deploy this in a medium trust ASP.NET shared web hosting such as DiscountASP, GoDaddy, etc. This means you don’t have to pay for the SQL database. It integrates into VS2010 (coming soon). It is different from previous version because it is safe to use with multi-threaded environments (such as ASP.NET). and no longer blocked from being used with ASP.NET. The catch is that it is for light-usage production (4GB or less for datafile) usage scenarios and it does NOT support stored procedures. For high-volume usage usage, you’ll probably want to use SQL Server Express (which is still free), SQL Server, or SQL Azure. Also, since stored procs are not supported the ASP.NET Membership is not supported (though they will be shipping new providers so that they do). The only change to your code when you migrate is your configuration string. See Scott’s blog for more details.

 

Portable Library Project

It is a special kind of project in VS2010 that only allows code that will work on particular targets. In particular, the targets are Silverlight and Silverlight for Window Phone 7. Intellisense only lets you see Intellisense on methods, properties, classes, namespaces, etc that are compatible with both. The most I could find on it was here.

Silverlight 5

Great stuff coming with Silverlight 5. Better DataBinding support for MVVM. Improved Printing and Text. Finally there will be a 64-Bit version of Silverlight. 3D Modeling that use Hardware acceleration. 3D and 2D can be used together. Breakpoints on XAML Bindings.

MVC 3

I am really impressed with MVC3. I am very tempted to try a project with MVC3. It takes advantage of HMTL 5 including Data validation, round corners, etc.

MVC Basics

The basic idea is that a url is mapped to a controller and method on that controller. That method makes calls to the model where most of the business logic resides, and then typically returns a view which is responsible for rendering the response (page). It maps url to action methods on controller class. In general the best practice with MVC is to have skinny controllers and fat models. Default method is called Index() and is called when no action is specified. Can pass entities as parameters to methods; just need to map them. Default parameters can be used as well. (i.e. int num = 5). ASP.NET MVC forces separation, while ASP.NET Forms does not.

Routing

When determining which rule matches it starts with the one that was added first. It then proceeds down the list until one matches. Routing is used to map urls to controllers and actions, but it is also used to generate urls in the application.

Glimpse

It is a an open source tool that allows you to diagnose what is happening on the server, but from the client. It is very useful when trying to figure out what happened once your request made it to the server. For example, what route was executed. It is basically Fiddler for the server.

For more information see here.

Razor

It is a View Engine for MVC. For more info see ScottGu’s blog. Razor files are .cshtml. Tags start with @ and it automatically figures out where code ends and content begins. Content and code can be intermingled. A layout page is basically like a master page in ASP.NET Forms. You can use traditional parameters or Named parameters. Use Custom helpers for custom rendering; refactoring in a way.

MVCScaffolding package

It is a code generator for MVC; a smart one at that. Highly recommended so you don’t have to write so much code to do CRUD UIs. Use NuGet Package Manager to get and install it.

Entity Framework 4.1

Great code first support. You can use POCO objects, make changes and the database just updates. It is so cool. This behavior is optional, but very nice. You can setup database initialization code to populate some basic data when the database is dropped.

Modernizr

A great tool that allows you to take advantage of HTML 5 when it is available and downgrade when it is not. An example of this is round corners. Very nice tool that can be used in most any ASP.NET project. http://www.modernizr.com/

Windows Phone 7

Later this year there will be a new release called Mango. It is a very exciting release as it will bring the Windows Phone 7 much closer to the competition as far as its offering. To get started with Windows Phone 7 development go here. Everything that is developed for Windows 7 Phone falls into two categories: Silverlight or XNA. XNA is for games (also used for XBOX), and Silverlight is for everything else. You can import some XNA libraries (such as audio) into Silverlight. Tombstoning is basically storing state to appear like the application never quit when in fact it did. It basically works by providing a state bag that most anything can be written/read to when different events such as (navigate to and from are called). It works much like Viewstate does in ASP.NET except it is not automatic. So more specifically it works like adding and retrieving stuff to/from viewstate in ASP.NET. The cost is $99 per year to put your application (or as many as you want except not more than 15 free ones) in the Marketplace. You can register to developer unlock your Windows Phone 7. Visual Studio 2010 comes with an emulator, but the one that will be in the mango release is sooo much better because it simulates things like sensors. The talk was given by Jeff Wilcox.

Tips on Windows Phone 7 development

Change splashscreen (an image) to all black if you app launches immediately. That way it is perceived as faster and cleaner. If your app takes a few seconds to load then put in a custom splashscreen (change the image) to give a more professional look. Add scrollviewer or list so that scrolling will always be available if something doesn’t fit on the screen. Use the metro look and feel styles, don’t hard code styles. If things don’t align as expected, then use 12px margins. Promote your app by creating a site for it. Prompt a user for review of your app after you think they have used it for a while. Statistically most apps are only used once and never used again. Use Watson to collect crash information, bugs, etc. Use Google Analytics to track page navigation within your app. Keep your main dll as small as possible since the entire thing is checked before loading into memory. Delay load pages / dlls on an as needed basis to help accomplish this. This also helps with startup times. Use a tombstoning helper. Use caching whenever possible.

Windows Azure – by Scott Guthrie and Mark Russinovich

Windows Azure is a great technology that needs some work with regards to deployment speed, and in general ease of use, but it is extremely well architected for scaling your application in a very elastic way. It allows you to worry about your app and not the infrastructure it is running it. It is Microsofts offering of cloud computing. The idea is that if you need 100 servers for an event you have them. Then after the event you don’t need them. With traditional models you would have to have servers ready to go at all times and pay for that much power. Since Microsoft has a giant server farm called Windows Azure and a middle tier between you and the server OS you only pay for what you use for the length of time you use it. Everything is continually monitored for 99.? uptime.

Mark went into all the details or the architecture. He convinced me it is very complex and robust, but not so fun to listen to a discussion about it. way too much details for my interest level. However, here as some of the things I found interesting. SQL is actually much slower than the way Windows Azure does it. They actually have everything as read only. Once it is read the objects are de-serialized and used. If they need to update, they are written back to the cloud as serialized objects. This takes only a trillionth of a second instead thousandths of a second that SQL takes. This allows them to scale fast. Their belief is that in the next 10 years or so this will scenario will be common more so than the relational database. Currently options in Azure are SQL, Blobs, and Queries. I believe SQL Azure is part of Windows Azure.

Some Barriers / solutions to get over before cloud computing will be accepted are: Trust of proprietary data being outsourced; loss of control; confidence (ISO and other certifications will help); Private clouds may be an alternative; license to run in own data center may help also.

Wednesday, February 9, 2011

Setting default values in Entity Framework when using Silverlight

I found myself amazed at how difficult it is to set default values for a property in the Entity Framework (even version 4) when used with Silverlight. Ideally I could use the DefaultValue attribute in the metadata class for my model. The problem is that Silverlight doesn’t use it. It seems to work ok in my tests that don’t use Silverlight if I remember correctly. But that only partially helps. I explored putting the value in the constructor for the entity that has the property I want to set the default value on, but that fires every time the object is created. This means that it was created even when displaying the results of a query, which is not the event I was hoping for. I want the default value to be used when a new entity is created, but just the object instantiated.

Then I ran across this post. It talks about creating a partial class on the client-side (Silverlight) and using the partial method called OnCreated(). The forum seems to say that you can define the OnCreated() partial method in the partial entity class that is on the server-side, but that method is not defined on the server-side that I can tell. So, the partial keyword doesn’t work in that context. The server-side object has a .shared.cs instead of just .cs extension so the file will be copied to the client-side. The problem is that the code has to work on the client and the server side. As noted before, the OnCreated method only exists on the client-side.

The solution is actually quite simple. I just had to explicitly define a partial class on the client-side even though I already have one on the server-side and is shared. This allows me to leverage the OnCreated partial method on the client that will fire when the entity is created, not just instantiated, and still keep my shared partial class that is on the server and client side.

I haven’t tried it, but by doing like Kyle recommends I should be able to use the DefaultValue attribute in the metadata and have it carry over to the client-side by calling the utility method that reads the DefaultValue attribute from the model when the OnCreated method is called.

So, here is an example, of what I am trying to explain.

In this example (to keep with the example on the forum) my entity is called Entity1

In my Silverlight project, I define a file called Entity1.cs. It would contain:

public partial class Entity1
    {
        partial void OnCreated()
        {
            DefaultValueUtility.InitializeDefaultValues(this);
        }
    }

NOTE: I could also just set the property directly instead of pulling the data from the model.

I can, but don’t have to have a file called Entity1.shared.cs on my server-side that will can contain whatever I want it to. It will be copied to the client-side as well. Then it will be merged with the Entity1.cs and the generated Entity1 file from the model itself on the client side because they are all partial classes.

Here is the code for the DefaultValueUtility call above. You will want to put this code somewhere in your Silverlight project.

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace DefaultSetter
{
    public static class DefaultValueUtility
    {
        public static void InitializeDefaultValues(object entity)
        {
            PropertyInfo[] properties = entity.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                MethodInfo propertySetter = property.GetSetMethod();
                if (propertySetter != null)
                {
                    DefaultValueAttribute defaultValueAttribute = (DefaultValueAttribute)
                        property.GetCustomAttributes(typeof(DefaultValueAttribute), true).FirstOrDefault();

                    if (defaultValueAttribute != null)
                    {
                        object defaultValue = 
                            Convert.ChangeType(defaultValueAttribute.Value, property.PropertyType, CultureInfo.InvariantCulture);

                        propertySetter.Invoke(entity, new object[] { defaultValue });
                    }
                }
            }
        }
    }
}

Thursday, November 11, 2010

Getting Current User information in Silverlight 4

Let’s assume for a Silverlight application. You may be wondering where to find out who the current user is. In ASP.NET there is a User property on the Page object (also other places such as the HttpContext.Current), but where is that in Silverlight 4 (not in early versions that I am aware of). The answer is the WebContext.

I think the WebContext was introduced in Silverlight 4.You The WebContext is created in the constructor of the App class that is in the App.xaml.cs file. If it isn’t you may be using a different type of Silverlight 4 project than the Silverlight Business Application or Silverlight Navigation Application. If you app doesn’t have this, I am assuming you can add it. Just create on of these projects and copy what is done there.

Among other things, the WebContext has a User property. This gives you what acts like what you may expect if you are accustomed to ASP.NET. For example, it has a Roles property to see what roles the user in. It has a IsUserInRole() method to see if a user is in a particular role. It has a Name property that gives you the username.

The WebContext is accessible from code by using WebContext and is also added to the Application Resources in the Application_Startup method which makes it accessible via XAML. To show the current username using XAML you would do something like the following:

<TextBlock x:Name="CurrentUser" Text="{Binding Current.User.Name, Source={StaticResource WebContext}}" />

Using XAML is really great because as Current.User changes from null to some value when the user logs in or Windows Authentication logs them in automatically, the TextBlock will be notified and display the change.

. The same is NOT true if you use code that you may write in ASP.NET to set the value. For example:

Assume you XAML is now defined like this:

<TextBlock x:Name="CurrentUser" />

You might be tempted to write the following line of code

CurrentUser.Text = WebContext.Current.User.Name;

The problem is that WebContext.Current.User may be null initially AND the biggest problem is that you won’t be able to pick up the Name since it may NOT be set yet. Really what we want is to using Bindings which notify the other side of the binding when the value changes. This means that initially we would get no username, but as soon as it is loaded we would be notified that there is a new value and we can show it.

The code is a little more complex than above, but not really too bad. Basically, we are trying to do what we did in XAML in the first example, but do it in code. Here is all you have to do:

CurrentUser.SetBinding(TextBlock.TextProperty, WebContext.Current.CreateOneWayBinding("User.Name"));

Now we the CurrentUser textblock will always display the current value of WebContext.Current.User.Name even as it changes.

Friday, June 11, 2010

ComboBox Solutions for Silverlight 3 and Silverlight 4

Silverlight 3 ComboBox Solutions

Proper Way to bind ComboBoxes to Associated Entities / Foreign Keys? Look about half way down for a post by ScottNZ on 8/13/2010 for the good idea.

Silverlight 3 ComboBox Control This solution works well I think and is even compatible with Silverlight 4. The one enhancement I would make to it for SL4 is use the SelectedValue and SelectedValuePath instead of SelectedObject. If you use SelectedValue and SelectedValuePath then the DataForm (DataField really) knows how to make it appear with a red box around it if you mark the foreign key property (if you are using RIA) as Required and there is nothing selected. Very nice. The error message is lame, but still better than nothing.

Silverlight ComboBox control and data binding by Rockford Lhotka Basically gives source code on how to make the SL3 ComboBox work much like the SL4 ComboBox. I have not tried it, but he is good so I’m sure it works, and it is a good example of how to extend a Silverlight control.

Just Geeks: A better way of using the ComboBox on a DataForm in Silverlight 3 – I wrote this one. Not too much different that most solutions above or at least some combination of them. I do go into what to do for POCO entities.

Just Geeks: Using a ComboBox on a DataForm for Silverlight 3 – I wrote this one also. It was my first attempt at using a ComboBoxes. The biggest take away from it is that you can populate the ComboBox in the ContentLoaded event of the DataForm.

Silverlight 4 ComboBox Solutions

NOTE: These won’t work in Silverlight 3 because SL4 added the SelectedValue and SelectedValuePath properties that work with the EF ForeignKey support.

Binding to Silverlight ComboBox and Using SelectedValue, SelectedValuePath, and DisplayMemberPath This one is actually good but assumes you know how to populate your ComboBoxes. I recommend using resources.

Silverlight 4 Rought Notes: SelectedValue It does a pretty good job of showing how to use the new SelectedValue, SelectedValuePath, etc. It uses locally defined data in example so it you’ll have to make the leap on how this is done in real code.

Monday, May 17, 2010

Unit Testing Asynchronous calls in Visual Studio 2010

I am simply amazed how much effort I had to go through to figure out how to test asynchronous calls in Visual Studio 2010 (VS2010). In the end, I was able to figure it out with the help of some blogs that I read.

VS2010 ships with integrated Unit Testing which I would like to take advantage of. I am writing a Silverlight application that calls a Windows Workflow Foundation service that I implemented using the WCF Workflow Service Application. I really like it, but I want to be able to unit test the workflow service.

The only way I found to test a WCF Workflow Service Application that I could find was to add a Service Reference to my Unit Test project. This is good for me because that is how Silverlight will call it. The problem is that the WCF Workflow Service Application can’t be called synchronously. So, we have to call it Asynchronously. The problem is that the Unit Test framework used in VS2010 does not support Asynchronous calls in  a Unit Test. Well, it runs, but doesn’t wait for the response to the Async call, so the test is pretty worthless.

Now that you know what I am trying to do, here is what I found as solutions.

Option 1: Simulate Synchronous call using an Asynchronous call

Here is a class I created to simplify the process of make an asynchronous call appear to be synchronous.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MyApp.Tests
{
public class AsyncTest
{

// max number of milliseconds to wait for an asynchronous call
int timeout = -1;

public AsyncTest()
{
// if debugging, make it a much larger like infinity
if (System.Diagnostics.Debugger.IsAttached)
{
timeout = -1; // infinity (wait for ever)
}
else
{
timeout = 20 * 1000; // 10 seconds
}
}

public AsyncTest(int timeout)
{
this.timeout = timeout;
}

// we'll use this to make the current thread wait until our asynchrous call finishes
ManualResetEvent block = new ManualResetEvent(false);

// we'll use this to flag if/when our async call finishes
bool isAsyncDone = false;

public void Done()
{
isAsyncDone = true; // flag that we are done (do NOT do this after calling block.Set() this will cause race conditions!!!!)
block.Set(); // tell the calling / this thread that it can continue now.
}

public void Wait()
{
block.WaitOne(timeout, false); // wait until block.Set() is called or the timeout expires (which ever comes).
Assert.IsTrue(isAsyncDone, "Test took too long"); // if it took too long then report it to the test framework.
block.Reset(); // set the event to non-signaled before making the next asynchronous call.
}
}
}

Here is an example of how you would use it to create a method that acts like a synchronous method, but calls an asynchronous WCF Service.

public GetWorkflowStatusCompletedEventArgs GetWorkflowStatus(long requestID)
{
AsyncTest at = new AsyncTest();

GetWorkflowStatusCompletedEventArgs returnedArgs = null;

// setup our service reference and callback for when it is done
ServiceClient wf = new ServiceClient();
wf.GetWorkflowStatusCompleted += delegate(object sender, GetWorkflowStatusCompletedEventArgs e)
{
returnedArgs = e;
at.Done();
};


wf.GetWorkflowStatusAsync(requestID);
at.Wait();

return returnedArgs;
}

I created one of these methods for each of the asynchronous methods I wanted to test. In fact I created a helper class to hold them. Now, in my class that has all my tests in it, I just call the methods on this helper class which are synchronous. Now the test run properly.

For completeness, here is what the unit test (testmethod) would look like.

[TestMethod]
public void TestCanGetWorkflowStatusTwiceInARow()
{
var status = Helper.GetWorkflowStatus(1234);
Assert.AreEqual<long>(status.RequestID, requestData.RequestID, "The wrong request id was returned.");
Assert.IsTrue(status.RequestID > 0);
}
Now I can write a unit test just as easily as I do any other unit test. The synchronous / asynchronous issue is encapsulated in a helper class. I like it. Not much extra work either. Especially since each helper method I write is almost identical. It could be generated if desired (using CodeSmith, etc).
I wish I could take credit for all this, but I can’t. The solution / implementation is completely mine, but the underlying technique is borrowed. For more info on those links, see here:

Option 2: Use the Silverlight Unit Test Application

I think this method is a reasonable approach, but for testing a WCF Service, it seems a bit unnatural to me. I like Option 1 better because I want my test results to be managed in VS2010. If nothing else other than no browser opens and also that you can block check-in of code if tests fail. The integrated Unit testing just seems a bit more integrated with VS2010.
I do think the Silverlight Unit Test Application is a great testing technology. However, I think it is best and most natural for testing Silverlight applications, not the web services they call.
There are lots of good blogs on the subject, so I won’t repeat it here. Here are some of the blogs that I found particularly useful when I went down this road.

Tuesday, May 4, 2010

Getting Current User when using WCF and Silverlight

First off, when you start to create a WCF Service in Visual Studio 2010 or 2008 for that matter, you can choose WCF Service, but if you are using Silverlight as the client, you do NOT want to select this. You want to select, Silverlight-enabled WCF Service. If you don’t or didn’t you can follow the instructions here to make sure a few things are in place and then you will be in the same position as if you had selected the Silverlight-enabled WCF Service.

All I want to do is get the username of the user that is using my Silverlight application. Note, this also opens the door to ASP.NET roles.

Alot of what I read said that if I mess with my app.config and turn on transport or message security then I can get the user if I go to System.ServiceModel.ServiceSecurityContext.Current. Well, maybe that was for a Self-Hosted WCF service or some other scenario, but I could not get it to work in my tests with Silverlight with IIS hosted WCF Service. I think my biggest difficulty with these docs were that all the configuration tags that I expected to see in the web.config (they had an app.config) were not there, but yet I had a working (without security) WCF Service.

I had to assume it uses some defaults. I figured out that I was right. If you read A Developer's Introduction to Windows Communication Foundation 4 you will understand much better. It is a fairly lengthy read, but well worth it. There is actually a section on Workflow Foundation 4, but the first part of the article is most excellent in describing the defaults and how they work. For instance search it for ProtocolMapping to see that the defaults include basicHttpBinding, netTcpBinding, netNamedPipeBinding, and netMsmqBinding. They are defined in the Machine.config. WCF 4 also support inheritance / merging of configuration items. Very cool.

I am using an IIS hosted WCF service. I want to use Windows Authentication for authentication. Nothing fancy. What I found works well and quite easily is ensure the following things are in specified and in synch with each other. They must all agree!

Web Server
  • IIS has anonymous access disabled (not enabled).
  • IIS has Integrated Windows authentication enabled.
  • If you are using Visual Studio 2010 and using the built-in dev server, the default settings are fine. I did NOT have to check the NTLM Authentication checkbox.
Web.config
  • This is needed to have ASP.NET be able to get security info as well.
<system.web>
<authentication mode="Windows"/>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
  • Make sure you have aspnet compatability enabled as follows:
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"  aspNetCompatibilityEnabled="true"/>
Your Service Class
  • Make sure to add the following above your class for your WCF Service. You can also use Required, instead of of Allowed
    [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]

And now the moment of glory. You can now get the user just like you would in ASP.NET.

System.Web.HttpContext.Current.User.Identity.Name

References: A Developer's Introduction to Windows Communication Foundation 4

Tuesday, April 13, 2010

Using RIA Services / WCF with multiple host headers

If you are using RIA Services or just plain old WCF you and you have more than one url that you use to access your website and use IIS 6 you will need to modify your web.config file.

In my example, I access the same IIS web site using two different host headers because I have a small web farm and I want to be able to check each server in the farm after a deployment, not just use the load balanced url.

This means that I have two urls, one for load balancing that everyone uses, and the one I use for testing to make sure a particular server in the farm is working.

In my case, I have http://myapp:8888 which everyone uses, and http://myapp:18888 I use to hit server one, http://myapp:28888 to hit server two, etc.

Here is the change I had to make to my web.config on the first server.

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" >
<baseAddressPrefixFilters>
<add prefix="http://myapp:8888" />
<add prefix="http://myapp:18888" />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
</system.serviceModel>

If you don’t do this, you may get errors about anonymous, security, bindings, communication, etc. This tends to fix a lot of these issues.

This is one of the better references I have found for getting RIA Services and WCF running under .Net 3.x, IIS 6, etc.

Friday, March 19, 2010

Getting Started with RIA Services

WCF RIA Services -  You can download a version of RIA Services for either Visual Studio 2010 or 2008. This is also a great page to find sample code, walk-throughs, videos, forums, etc for RIA Services. This is a great starting point.

Below are some links to some more advanced RIA Services topics.

Silverlight 3 and RIA Services - The advanced things – Several interesting advanced topics

Walkthrough: Creating a RIA Services Class Library – If you have a Web Site instead of a Web Application, you may want to look at this since Web Sites can’t be linked to RIA Services. This serves as a nice workaround though and allows for reuse, which is very nice.

How to: Add or Remove a RIA Services Link – Nice if you want to change your RIA Services Link

WCF RIA Services Code Gallery – a good place to get source code for the walk-throughs.

Wednesday, March 10, 2010

RIA Services Rocks!

I cannot believe how cool RIA Services is. I knew it was cool, but I think it does everything I have been dreaming about.

Here is a video that shows how to do a pretty nice application in an hour. Simply AMAZING!!!

http://silverlight.net/learn/videos/all/net-ria-services-intro/

You can download RIA Services for Visual Studio 2008 or VS 2010 Beta. Click here for more info on downloading.

BTW, the entire sample in the video is in the Documentation / Samples of the download.

I’m sold!

Friday, March 5, 2010

Adding a new row to a DataForm in Silverlight

Below is a snippet of code that shows the code that can be used to programmatically add a new record to a DataForm. In this snippet, the DataForm is called _dataform and has a PagedCollectionView (list) of Person objects. The DataForm UI has a + button that adds records. We want to do the same thing, but with a different button, and also set some default or maybe even values that are not on the DataForm. To do this, we call AddNewItem() which is exactly what the + button does. Next we get the CurrentAddItem. This is of type Person so we can cast it as a Person and set any properties that are on the Person object, not just the ones on the DataForm.

public PagedCollectionView Persons { get; set; }

private void btnAdd_Click(object sender, RoutedEventArgs e)
{
_dataform.AddNewItem();

Person newPerson = Persons.CurrentAddItem as Person;
newPerson.Name = "zzz";

newPerson.City = "Tempe";
}
A working version of this code is available here. See the MainPageWithOnlyCustomButtons.xaml.cs file.

Another snippet that may come in handy for adding just like the above, but more for the scenario where you have not displayed any records in the DataForm, but you want to add a new one. This was the scenario I had when I used the DataForm in a Popup Window and showed only one record at a time or in this case needed to allow the user to add a new Person. Here is the snippet for that. The big difference is we have to populate the Persons variable with an empty list so that the DataForm knows what type of objects it is supposed to add. Otherwise, _datagrid will be null and the operation will have failed.
 
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
// the DataForm needs to know what we have a list of, so give it an empty list to start with
// then wehn we tell it to add a new one, it knows what to add/create.
Persons = new PagedCollectionView(new List<Person>());
_dataform.DataContext = null;
_dataform.DataContext = Persons;

_dataform.AddNewItem();
Person newPerson = Persons.CurrentAddItem as Person;
newPerson.Name = "zzz";
newPerson.City = "Tempe";
}

A working version of this code is available here. See the MainPageWithLoadOneRecordAtATime.xaml.cs file.

Thursday, March 4, 2010

A better way of using the ComboBox on a DataForm in Silverlight 3

At first I tried to use the ComboBox on a DataForm in Silverlight 3 and was pretty successful. You read about it here. It worked fairly well for me. It doesn’t update the field that it is bound to, but I think that should be able to be done using the SelectionChanged event. I have not verified that though. The concept behind this implementation was that I had a ComboBox that was populated with Owners (people) objects and I wanted to bind to an OwnerID field (the foreign key).

There was a fair amount of code to translate between the object and id. I don’t really like having to write that code. It also seemed to me that there must be an easier way, especially in the day of RIA Services, Data Services, etc that use Object graphs and the like. The concept behind the implementation I want to cover here is a shift towards a more object based approach and one that I have to believe Microsoft had in mind when they designed the ComboBox because it works well.

Unfortunately, this example is not the same basic as the other implementation, but I think the point will still be pretty clear. This example uses Address and Country tables / objects. Think about an Address table, it could have a foreign key to a Country table so that users are not just typing countries, they are instead selecting them from a ComboBox of countries.

This example is a little more in-depth as far as a real world UI (example is still simple though). In this user interface the page starts with a DataGrid that shows a list of addresses (Address and Country information). When a row in the DataGrid is selected, the DataForm shows the detail of that row and allows the user to change the Country. Any changes are immediately reflected in the DataGrid. The user can save or cancel the changes. The cancel does NOT revert changes or save really, but you can do that by making the Person object implement the IEditableObject interface or by handling the EditEnded event on the DataForm.

This solution does properly notify the DataForm that the select has changed. You can tell because the OK button enables itself automatically when the ComboBox selection is changed. It also properly sets the Country property on the Person object automatically as you would expect. The translation of Country object to CountryID is handled by RIA Services seemlessly, but you could also (if you are not using RIA Services) do that when you save the Person object back to the database.

In order for the DataGrid to get the changes immediately, the Person object must implement the INotifyPropertyChanged interface.

The Country object MUST override the GetHashCode() and Equals() methods. This is because we want to treat instances of the Country class as the same object as long as the have the same foreign key. We can do this because the user can’t change Country, and we just really want a way of showing a user-friendly text version of the Country object to the user, but really have the entire Country object at our disposal.

In the database simulation methods I took care to always get new instances of objects and not reuse them between the ComboBox and the Country property on the Person object. The reason is that it will appear as though the GetHashCode() and Equals() methods don’t need to be overridden. That is because the objects would actually be the same. In a real life scenario, EF or web service, WCF, RIA Services, etc would return different instances of objects each time you return objects. We need to handle real life, so be sure to override those methods.

I populated the ComboBox using code, but you could do it in XML as described here. I find the code to be a little more comfortable to me, but either should work equally as well. The trick is to do that in the ContentLoaded (not to be confused with the Load event) event of the DataForm.

The Countries and Persons properties on the MainPage class are what everything will bind to. This means that we need to populate these variables, THEN set the LayoutRoot.DataContext = this. If you do it in the reverse order, the binding will bind to empty variables and your UI will not show any rows or details.

You can download a working solution from here. I have include the source code below for convenience.

Let’s start with the MainPage.xaml. Here is what it looks like:

<UserControl x:Class="DataFormTest2.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"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:dataFormToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<StackPanel Orientation="Vertical">
<TextBlock>Combobox example</TextBlock>

<StackPanel Orientation="Vertical">
<data:DataGrid x:Name="_datagrid" ItemsSource="{Binding Persons}" Margin="0,0,5,0" AutoGenerateColumns="False">
<data:DataGrid.Columns>
<data:DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
<data:DataGridTemplateColumn Header="Country">
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBlock Text="{Binding Country.CountryName}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
<data:DataPager Grid.Row="1" Source="{Binding Persons}" PageSize="10" Margin="0" />
</StackPanel>

<dataFormToolkit:DataForm x:Name="_dataform"
ItemsSource="{Binding Persons}"
CommandButtonsVisibility="All"
AutoGenerateFields="True"
AutoCommit="False">
<dataFormToolkit:DataForm.EditTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<dataFormToolkit:DataField>
<TextBox Text="{Binding Name, Mode=TwoWay}" />
</dataFormToolkit:DataField>
<dataFormToolkit:DataField>
<ComboBox x:Name="_comboCountries" DisplayMemberPath="CountryName"
SelectedItem="{Binding Country, Mode=TwoWay}" >
</ComboBox>
</dataFormToolkit:DataField>
</StackPanel>
</DataTemplate>
</dataFormToolkit:DataForm.EditTemplate>
</dataFormToolkit:DataForm>

</StackPanel>

</Grid>
</UserControl>
This is the MainPage.xaml.cs.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.ComponentModel;


// Basis for this code was copied from here: http://forums.silverlight.net/forums/p/165152/372651.aspx
// Giant help from: http://weblogs.asp.net/manishdalal/archive/2009/07/03/silverlight-3-combobox-control.aspx

namespace DataFormTest2
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
_dataform.ContentLoaded += new EventHandler<DataFormContentLoadEventArgs>(_dataform_ContentLoaded);

this.Loaded += new System.Windows.RoutedEventHandler(MainPage_Loaded);
}

// This could be done in the Constructor of this page also
void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
// IMPORTANT: The Countries and People properties must be set
// BEFORE the DataContext is set to this
Countries = GetCountries();
Persons = new PagedCollectionView(GetPeople());
this.LayoutRoot.DataContext = this;
}

public List<Country> Countries { get; set; }
public PagedCollectionView Persons { get; set; }

#region Database Simulation

// simulate a database query
// used to populate the DataGrid and then the DataForm
private List<Person> GetPeople()
{

// get values for ComboBox
List<Country> countries = GetCountries();

// Get rows for DataGrid / DataForm
List<Person> persons = new List<Person>();
persons.Add(new Person { Name = "Charlie", Country = countries[2] });
persons.Add(new Person { Name = "Lola", Country = countries[1] });
persons.Add(new Person { Name = "Gabe", Country = countries[0] });
persons.Add(new Person { Name = "Jack", Country = countries[2] });
persons.Add(new Person { Name = "Vic", Country = countries[0] });

return persons;

}


// simulate a database query
// use this to populate the ComboBox list of values
private List<Country> GetCountries()
{
List<Country> countries = new List<Country>();
countries.Add(new Country("Andorra", 1));
countries.Add(new Country("Belgium", 2));
countries.Add(new Country("Canada", 3));

return countries;

}

#endregion

void _dataform_ContentLoaded(object sender, DataFormContentLoadEventArgs e)
{
// find the ComboBox in the DataForm and set the ItemsSource
var comboCountries = (ComboBox)_dataform.FindNameInContent("_comboCountries");
if (comboCountries != null)
{
comboCountries.ItemsSource = Countries;
}

}
}


// NOTE: You need INotifyPropertyChanged if you want the DataGrid to automatically update
public class Person : System.ComponentModel.INotifyPropertyChanged
{
private string _Name;

public string Name
{
get { return _Name; }
set { _Name = value; NotifyPropertyChanged("Name"); }
}

private Country _Country;

public Country Country
{
get { return _Country; }
set { _Country = value; NotifyPropertyChanged("Country"); }
}

public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(info));
}
}


}

public class Country
{
public Country(string countryName, int id)
{
CountryName = countryName;
ID = id;
}

public string CountryName { get; set; }
public int ID { get; set; }

// we need to override this for comparisons (see Equals method).
public override int GetHashCode()
{
return ID.GetHashCode();
}

// We override this method so that the values will be selected properly in the ComboBox
// The reason is that two objects are not considered equal if they are not the same object.
// We get two different objects because one would be the objects we got back from the
// database to populate the ComboBox. We would have a different instance of each object
// when we reference the Country property in the Person object we are editing.
// Since ID is a primary key, that is all we really need to use for comparison
// as far as the combo is concerned. This is ok, since we are not editing Country
// in the scenario so its data members never change.
public override bool Equals(object obj)
{
if (obj == null) return false;
Country cityToCompare = obj as Country;
if (cityToCompare == null) return false;
return ID.Equals(cityToCompare.ID);
}
}
}

References

http://betaforums.silverlight.net/forums/p/146398/325962.aspx

http://weblogs.asp.net/manishdalal/archive/2009/07/03/silverlight-3-combobox-control.aspx

http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx

http://msmvps.com/blogs/deborahk/archive/2009/11/25/silverlight-and-ria-adding-a-combobox-to-a-dataform.aspx

Friday, February 12, 2010

Where is Silverlight Toolkit installed?

The short answer is check your start menu for an item that is named similarly to Microsoft Silverlight 3 Toolkit November 2009. The typical answer is C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit. This has all shortcuts to items of importance. When you download the Silverlight Toolkit you will notice it is an MSI. This means it has an installer. However, this installer does not allow or tell you where it will install its goods.

After reviewing the Microsoft Silverlight 3 Toolkit November 2009 entry in my Start Menu, I found the following installation points.

Binaries – where the .dlls are that you can reference in your project,
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Bin

Documentation – the CHM file version of the documentation
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Documentation.chm

Sample Source Code – the source code to the controls in the toolkit and sample code for using the toolkit
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Source

Silverlight Toolkit on CodePlex – link to the Silverlight toolkit on CodePlex where you likely downloaded the toolkit from, and can get the latest version from.
http://www.codeplex.com/Silverlight

Silverlight .net Discussions – link to the Silverlight forums where you can post your own questions or just search for answers or even answer some questions :)
http://forums.silverlight.net/forums/35.aspx

Source Code – shortcut to the exact same place that Sample Source Code pointed to… Weird
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Source

Toolkit Samples – link to a local (runnable) copy of the Silverlight Toolkit. Opens in your default web browser.
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Samples\default.htm

Welcome – link to local web page that is a Good starting point, release notes, explanation similar to what I gave here, etc
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Welcome.htm

 

Other Points of Interest

Themes –Use these themes to change the look of your Silverlight applications without much work at all.
C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Nov09\Themes

Wednesday, February 10, 2010

Making the Silverlight ComboBox bind to multiple columns.

It is actually very simple to make the Silverlight ComboBox show multiple columns, but took me a while to figure out how. Below is what I learned.

The Setup

Let’s assume you have a ComboBox defined in XAML as follows

<ComboBox x:Name="cboTest" Width="100" Height="20" />

Now you want to populate it with some data that you get from the database (through WCF, Web Service, etc). All you have to do is set the ItemsSource property as shown below. In this case, GetMyData() returns a List<Person> type. You can do this in the code behind.

cboTest.ItemsSource = GetMyPersonData();

Now you want to select the appropriate item (the item with PeopleID equal to 123 in our sample) in the ComboBox.


Person foundItem = (cboTest.ItemsSource as ObservableCollection<Person>).FirstOrDefault(p => p.PeopleID == 123);
cboAccountManager.SelectedItem = foundItem;

Showing One Property for each Item in the ComboBox

This is easy, just set the DisplayMemberPath in your XAML or Code behind. In this case, we will display a ComboBox that shows a list of first names.

XAML

<ComboBox x:Name="cboTest" Width="100" Height="20" DisplayMemberPath="FirstName" />

Code-behind

cboTest.DisplayMemberPath="FirstName";

Showing Multiple Properties for each Item in the ComboBox

This is actually not bad at all either (once you see how to do it). You will want to remove any code or XAML that sets the DisplayMemberPath. Now all you have to do is change your XAML to look the way you want. Here is an example, that shows the FirstName and LastName properties of our Person object concatenated with a space.

<ComboBox x:Name="cboTest">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName, Mode=OneWay}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding LastName, Mode=OneWay}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
You are free to use whatever combination of controls you need to make your multi column layout or maybe just custom format you want.