Archive

Archive for January, 2011

Getting empty string default constraints to work in WCF RIA Services through a Fluent API

January 16, 2011 Leave a comment

This post is based on the excellent post by Nikhil Kothari. You should read his blog post before you continue as all I am going to introduce to how I was able to port his code to .NET 4.0 and get the Fluent API working.

First of all, let’s take a look at my file structure:

Entity Framework/RIA Services file structure

One of the issues that I have with WCF RIA Services is the whole workflow that is involved when anything changes in the data model:

  1. Exclude my partial Domain Service files.

    Fluent RIA Services - Exclude partial files

  2. Delete my Domain Service files.
  3. Open my Entity Framework (.edmx) file in the visual designer.
  4. Delete any of the model objects that have been changed. (I have found that I need to delete since Visual Studio doesn’t really serialize the changes from the database correctly.
  5. From the context menu, click on Update Model from Database…

    Fluent RIA Services - Update Model from Database

  6. Select the model objects that have changed.
  7. Build the project.
  8. Add a Domain Service.
  9. Add the partial keyword “partial” to the DomainService class.

    Fluent RIA Services - partial keyword to DomainService class

  10. Include your custom partial files in the project.

    Fluent RIA Services - Include partial files

  11. Add all of your [Include()] statements back to the .metadata file. (I have another blog post for this that get’s this to work.)
  12. Build your project.

Clearly this is a very intensively workflow and it is very easy to screw things up and your application will stop working as before. The problem I have with WCF RIA Services is that it doesn’t support or enforce default values from the database or check constraints on the client.

The use case that I am trying demonstrate is if you have a column in a table that is set as non-null but has a default value of empty string. I have a client that uses this as a standard in their database model and it becomes painful for us to get this to work. As you can see from the above workflow is that the DomainService is deleted and recreated. I have moved a lot of my custom .metadata logic to my partial file. Let’s take a look at what is required to allow empty string for a Required attribute using a slight port to Nikhil Kothari’s implementation:

public MemberValidationMetadata Required()
{
	return Required(null);
}

public MemberValidationMetadata Required(bool allowEmptyStrings)
{
	AddMetadata(new RequiredAttribute() { AllowEmptyStrings = allowEmptyStrings });
	return this;
}

This code snippet comes from the MemberValidationMetadata.cs file. It basically is an overload from the default Required() method and provides support for passing in a boolean to determine if AllowEmptyStrings is true or false.

public class rv_sbt_SiteBillTypeMetadata : MetadataClass
{
	public rv_sbt_SiteBillTypeMetadata()
	{
		this.Validation(p => p.rv_sbt_BillTypeDefinition).Required(true);
		this.Validation(p => p.rv_sbt_BillTypeDescription).Required(true);
		this.Validation(p => p.rv_sbt_BillTypeLongDescription).Required(true);
		this.Validation(p => p.rv_sbt_BillTypeName).Required(true);
		this.Validation(p => p.rv_sbt_CreatedBy).Required(true);
		this.Validation(p => p.rv_sbt_CustomerValue).Required(true);
		this.Validation(p => p.rv_sbt_ModifiedBy).Required(true);

		this.Projection(p => p.rs_sdf_SiteDocumentFormat).Include();
		this.Projection(p => p.rv_al_AccountingLink).Include();
		this.Projection(p => p.rv_obt_OrganizationBillType).Include();
		this.Projection(p => p.rv_sbtd_SiteBillTypeDetail).Include();
		this.Projection(p => p.rv_sis_SiteInstalledSubsystem).Include();
		this.Projection(p => p.rv_urbt_UserReportBillType).Include();
		this.Projection(p => p.rv_xrf_ReturnFrequency).Include();
	}
};

As you can see, I am using the overload Required method and it allows me to now support the empty string default constraint from the database. It is also possible to do this in the .metadata.cs file that is created when you create a new DomainService but I find that I prefer the Fluent API. The cool thing about this approach is that you can have both the Fluent API as well as what you get from the DomainService .metadata.cs file. The datamodel is rather large and I only add the table objects to the partial file (.metadata.partial.cs) and comment out the same definition in the .metadata.cs file shown below:

Fluent RIA Services - Comment out existing definition

Data access is still a very painful workflow for Silverlight development. I try to use metadata from a database as much as possible and this really is a good candidate for doing some code generation with T4. I do wish that we had the capability to have check contraints executed on the client without needing to write custom code but so far this doesn’t seem to work very well. I would also like to see a better alternative to forcing us to use the designer for the Entity Framework model as the only way to update and modify your model.

Perhaps an ability to code closer to what WebMatrix with Razor. That would be an awesome combination for us Silverlight developers.

Once again, thanks for reading….

Getting the content from a Grid if you know the Row and Column in Silverlight

January 16, 2011 Leave a comment

This should be a quick post about something that I do quite a bit when creating my own designer screens. I like to use a Grid control as my designer surface since it allows me to provide the same paradigm that I would use if I were to manually create a screen in Visual Studio. It also gives users good feedback when you set the property ShowGridLines to true. Well, one of the things that I allow my users to do is to set the RowSpan or ColumnSpan of a control through a property editor. When the user does this, I need to have a mechanism to set the value for the corresponding control that is in the Grid.

Let’s take a look at what I am talking about. I am going to use a screen that I talked about in a previous post which allows users to create bills and invoice formats:

Grid with a Control selected.

When we set the ColumnSpan to 2, we should see the following:

Grid with a Control now with a ColumnSpan of 2.

Now let’s look how we can get the control in question from a Grid and set its ColumnSpan programmatically.

The property grid on the right is associated with whatever control is selected on the designer surface. I have some metadata around my controls, which I have a class called DesignerItem, that exposes a Row and Column property. When I perform a drag and drop operation, I make sure that I set the Row and Column properties correspondingly. Then I use the ValueChanged event handler of the RadNumericUpDown control to get the control object from the Grid:

public void nudColumnSpan_ValueChanged(object sender, 
	Telerik.Windows.Controls.RadRangeBaseValueChangedEventArgs e)
{
	var item = View.Designer.Children.Cast<FrameworkElement>().Where((o) => Grid.GetColumn(o) == CurrentDetailItem.Column && 
	Grid.GetRow(o) == CurrentDetailItem.Row).FirstOrDefault();

	if (item != null && e.NewValue > 0)
	{
		Grid.SetColumnSpan(item, span);
	}
}

Basically I am using a little lambda magic and Grid.GetColumn(…) and Grid.GetRow(…) methods to find the correct object in the corresponding Column and Row position of the Grid.

NOTE: You will have to write a little more code if you have multiple controls residing in the same location in your Grid.

This may seem trivial but it really saved me a lot of time and effort when I was first trying to get all of the basic workflow working in my designer. As a side note, you could get past all of this if you had metadata to support ColumnSpan and RowSpan like I did for Column and Row. If you had that, than you could have just done standard data binding.

Hope this helps….

Categories: English Tags: , ,

Getting the user credentials both in and out of the browser in Silverlight

January 15, 2011 6 comments

Silverlight is quite powerful and gives you a lot of flexibility. You can have your application run in the browser our you can opt for a more Windows like experience and run your application Out of the Browser. One of the frustrations that I have encountered in the past, is trying to write my code so that it supports both.

A common scenario is trying to get the current user signed into the computer. With Silverlight running in the browser, this is quite easy by passing information into the InitParams. But this becomes quite a bit more difficult when you are trying to do the same Out of the Browser.

The following is a screen shot of retrieving the currently signed in user from a web page:

Current User - Browser

In discussing this issue with some colleagues of mine, it came to me that solving the problem for out of the browser could be quite simple if we allow for elevated priviledges. My solutions was to use COM Automation.

The following is the same application now running out of the browser displaying the currently signed in user:

Current User - Out Of Browser

In this post we will go through getting the currently signed in user from the hosting web page and then via COM.

We will start with the web page first. First of all, you need to have a web page that has code-behind associated with it. The default behavior of Visual Studio is to create an ASPX page without any code-behind. The following is a code snippet of the hosting web page:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestComInterop.Web.Default" %>




    TestComInterop
    <!--
    html, body {
	    height: 100%;
	    overflow: auto;
    }
    body {
	    padding: 0;
	    margin: 0;
    }
    #silverlightControlHost {
	    height: 100%;
	    text-align:center;
    }
    
-->
    <script src="Silverlight.js" type="text/javascript"><!--mce:0--></script>
    <script type="text/javascript"><!--mce:1--></script>


<form id="form1" style="height: 100%;">
<div id="silverlightControlHost"></div>
</form>


I posted the whole in its entirety but there is only one element that you need to pay attention to with the ID=”InitParameters”. We will use this Literal tag to inject our current user from the code-behind.

Now let’s look at the code-behind:

public partial class Default : System.Web.UI.Page
{
	protected void Page_Load(object sender, EventArgs e)
	{
		Response.Cache.SetCacheability(HttpCacheability.NoCache);
		ConfigureSilverlightDeploymentSettings(InitParameters);
	}

	private static void ConfigureSilverlightSettings(Literal settings)
	{
		StringBuilder sb = new StringBuilder();
		sb.Append("<param name=\"InitParams\" value=\"");
		sb.Append("UserName");
		sb.Append("=");
		sb.Append(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
		sb.Append("\" />");
		settings.Text = sb.ToString();
	}
};

Basically, I am turning off caching in the Page_Load method as well as calling the ConfigureSilverlightSettings method. It is in this method that we dynamically construct a Param with the name of “InitParams”. This is the mechanism that Silverlight gains access to parameters we wish to pass to it externally. We then just create a key/value pair setting the UserName value to GetCurrent().Name property from System.Security.Principal.WindowsIdentity.

The last piece of this puzzle is to see how this is accessed from Silverlight. This leads us to the App.xaml.cs file. For brevity, I am only going to show you the Application_Startup method as it is the only thing that concerns us:

private void Application_Startup(object sender, StartupEventArgs e)
{
	this.RootVisual = new MainPage();

	if (Application.Current.IsRunningOutOfBrowser)
	{
		if (AutomationFactory.IsAvailable)
		{
			using (dynamic wScript = AutomationFactory.CreateObject("WScript.Network"))
			{
				this.UserName = string.Format(@"{0}\{1}", wScript.UserDomain, wScript.UserName);
			}
		}
	}
	else
	{
		// We are running in the browser and can use the HTML-Bridge to get our user.
		this.UserName = e.InitParams.ContainsKey("UserName") ? e.InitParams["UserName"] : "UNKNOWN";
	}

	Application.Current.Resources.Add("UserName", this.UserName);
}

I am showing you the solution for both but I want you to first focus on the else condition. Basically, we are just pulling the key/value pair from the InitParams object off of the StartupEventArgs object. I also ensure that we get a dummy value if no “UserName” exists as a key.

The final step is to add this to the Application.Current.Resources dictionary so that we can access it globally. You may have your own mechanism or may want to use your favorite DI/IOC container to handle this as well.

This really completes the web page workflow. Since we have the code for the App.xaml.cs file, let’s examine how this is accomplished out of the browser. If you look above, we are first checking to be sure that the application IsRunningOutOfBrowser. We also check to be sure that we have elevated priviledges to use COM Automation. Once this is established the we simply create a “WScript.Network” object. This allows us to use the Windows Script API and access the networking stack. Finally we format a string so that it looks just like what we would get from the web page.

The last piece of the puzzle is displaying the message box. The code-behind from the MaingPage.xaml file has the follwoing content:

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

	private void Button_Click(object sender, RoutedEventArgs e)
	{
		if (Application.Current.IsRunningOutOfBrowser)
		{
			MessageBox.Show(string.Format("OOB Current User: {0}", Application.Current.Resources["UserName"]));
		}
		else
		{
			MessageBox.Show(string.Format("Browser Current User: {0}", Application.Current.Resources["UserName"]));
		}
	}
};

I only added a condition test so that the screen shots would be different. The rest is just accessing the Resources property off of the Application.Current object. Again, you could do this quite differently using DI/IOC in your code.

I have zipped up a sample application to download here.

Hope this helps….

Automatically scrolling to a selected item in a ScrollViewer in Silverlight

January 15, 2011 Leave a comment

Sometimes it is necessary to have some custom user interactions as you are building business applications. It became necessary during a design session that the client needed the ability to design their own bill layouts. They needed the ability to basically drag and drop controls on the screen to build an invoice to send to their customers. With the power of Silverlight, I wanted to present them with a grid or canvas and allow them to create their own layouts. The problem with this is that they started making really complex layouts that made perfect sense to them but required scrolling during the design phase of the bill. One issue that came up is that when they wanted to navigate to an input control, they had to scroll and search for the control. I am using a ValidationSummary control to provide validation errors but since I was out of the context of a DataForm, I couldn’t just have my custom controls get highlighted. So I found two different implementations that provided a good starting ground but I wanted to have both vertical and horizontal navigation. I created a Behavior to support this and now when a user clicks on an item in the ValidationSummary control, they are navigated to the corresponding control.

The following is a sample screen shot of one of the bill design that was created:

Bill Designer

The following is a screen shot when the user click on the item in error:

Bill Designer - Auto Scroll

Here is the implementation for the Behavior:

 public class ScrollToSelectedItemBahavior : Behavior<ScrollViewer>
{
	private const int SCROLL_PADDING = 10;

	#region Overrides
	protected override void OnAttached()
	{
		base.OnAttached();

		this.AssociatedObject.Loaded += OnLoaded;
	}

	protected override void OnDetaching()
	{
		base.OnDetaching();

		this.AssociatedObject.Loaded -= OnLoaded;
		var controls = this.AssociatedObject.GetVisualDescendants();
		foreach (FrameworkElement control in controls)
		{
			control.GotFocus -= Control_GotFocus;
		}
	}
	#endregion

	#region Events

	private void OnLoaded(object sender, RoutedEventArgs e)
	{
		var controls = AssociatedObject.GetVisualDescendants();
		foreach (FrameworkElement control in controls)
		{
			control.GotFocus += Control_GotFocus;
		}
	}

	private void Control_GotFocus(object sender, RoutedEventArgs e)
	{
		FrameworkElement element = e.OriginalSource as FrameworkElement;
		var transform = element.TransformToVisual(AssociatedObject);
		var positionInScrollViewer = transform.Transform(new Point(0, 0));

		if (positionInScrollViewer.Y < 0 || 
			positionInScrollViewer.Y > AssociatedObject.ViewportHeight)
		{
			AssociatedObject.ScrollToVerticalOffset(AssociatedObject.VerticalOffset + 
				positionInScrollViewer.Y - SCROLL_PADDING);
		}

		if (positionInScrollViewer.X < 0 || 
			positionInScrollViewer.X > AssociatedObject.ViewportWidth)
		{
			AssociatedObject.ScrollToHorizontalOffset(AssociatedObject.HorizontalOffset + 
				positionInScrollViewer.X - SCROLL_PADDING);
		}
	}

	#endregion

};

As with any Behavior you need to add a using statement for System.Windows.Interactivity. In this example, I am also using some helper functions from the Silverlight Toolkit and I also have a using statement for System.Windows.Controls.Primitives.

Basically, when we attach the Behavior to the underlying control, we wire up the Loaded event and in this event we cycle through all the descendants and wire up the GotFocus event. It is the method call GetVisualDescendants that is the helper method from the Silverlight Toolkit. Conversely, when we are detaching we unwire all of the GotFocus events.

In the Control_GotFocus method we simply create a transform and then scroll vertically, horizontally, or both depending on where the control is located.

That is basically all there is to coding this Behavior.

Now, let’s look at the Xaml required to get this to work:

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
	<i:Interaction.Behaviors>
		<core:ScrollToSelectedItemBahavior/>
	</i:Interaction.Behaviors>
	<Grid 
		x:Name="grdDesigner"
		Margin="10,10,10,10" 
		ShowGridLines="True"
		radDrag:RadDragAndDropManager.AllowDrop="True" 
		Background="#FF2D2D2D">
		<i:Interaction.Triggers>
			<i:EventTrigger EventName="MouseLeftButtonDown">
				<core:ExecuteDataMethod Method="Designer_MouseLeftButtonDown" />
			</i:EventTrigger>
		</i:Interaction.Triggers>

	</Grid>
</ScrollViewer>

The following are the links that got me started and show a slightly different implementation:
Silverlight 4 ScrollViewer & Keeping items in view
Silverlight BringIntoView() extension method (with OnGotFocus behavior)

Hope this helps…

Categories: English Tags: , ,