Discussions of aesthetics and usability in software user interface design have a tendency to lead to unwinnable wars of opinion, so I’ll try to avoid that here. I’ll just say that, there are very good reasons to consider using rounded corners in the design of your application UI.
As an alternative to the default Lightswitch HTML Client theme, I’m posting the dotnetlore-blue-theme as a starting point for those who prefer a more rounded look to their UI elements.
Read More Post a comment (0)One visual element users have come to expect in modern web applications is an animated “please wait” or “in progress” indicator. You’ve probably noticed that the Lightswitch HTML Client provides this automatically for its long-running asynchronous data operations.
But what about your own code? Suppose you’ve added a button which asynchronously loads some data from the web, say via jQuery’s getJson() or ajax(). How do you get Lightswitch to display its progress animation until your async request is complete?
The Lightswitch HTML Client makes use of WinJS promise objects for its async operations. It surfaces a simple way for you to create your own promises – msls.promiseOperation(). It also provides a function call msls.showProgress() which takes a promise object as a parameter and shows the “in progress” animation until that promise completes.
You can find out more about WinJS promises here and here, but here’s some example code to get you started:
msls.showProgress(msls.promiseOperation(function (operation) {
// your long running async code goes here
// to help demonstrate, we'll use a 10 second delay
setTimeout(function () {
// whenever your async calls have completed, call operation.complete -
// this will stop the showProgress animation
operation.complete("we're done!");
}, 10000);
}).then(function (result) {
msls.showMessageBox(result);
}));
On Paul van Bladel’s excellent blog, Lightswitch for the Enterprise, there was a recent post about protecting entity properties which may be only updated by server side processing.
This post describes a common scenario: you want your server-side code to make changes to a property that normal users cannot themselves modify. As a concrete example, suppose you have an Orders table and a LastUpdatedByUser field in that table. You don’t want your users modifying LastUpdatedByUser directly – you only want the server itself to set that field’s value.
So you go to the Properties dialog for your Lightswitch application, and on the Access Control tab you add a permission. Let’s call it ManageAuditData.
Then in your LastUpdatedByUser_IsReadOnly method, you put this code:
result = !Application.User.HasPermission(Permissions.ManageAuditData);
And in your Orders_Updating method, you have this code:
using (Application.User.AddPermission(Permissions.ManageAuditData) entity.LastUpdatedByUser = Application.User.Name;
At first blush, you may think this works fine. If you’re developing a silverlight client with Lightswitch, you might not even notice that this code doesn’t actually protect the LastUpdatedByUser property from being directly edited by the user. The user can’t edit the field from the silverlight client itself. And the field can’t be edited from the server code, either, unless you grant the ManageAuditData permission as we have done above.
However, the OData endpoint leaves the property completely unprotected.
And if you create an HTML client for your app, you’ll notice that it, likewise, allows the user to edit the supposedly protected field. The IsReadOnly code is never even triggered.
I’ve logged this bug in this Microsoft Connect entry. Hopefully it will be addressed in an upcoming VS 2012 update.
In the meantime, I need to find a satisfactory solution.
Paul demonstrates one workaround – add code at the beginning of the entity’s Updating and Inserting methods to check for changes to your protected field and throw an exception if there are any.
However, what if you’ve got many entities with many ReadOnly properties? It would be nice to be able to use the IsReadOnly methods as they were designed… but have them actually work, regardless of whether the client is silverlight, html, or direct OData calls. And ideally, we’d like to do it without having to add extra code in every Updating and Inserting method for every entity in the project.
So, here’s my initial attempt at a workaround. The SaveChanges_Executing is called before any insert, update, or delete of any entity in the data workspace. (Take a look at the chart in this article from Code Magazine for more information on the Lightswitch save pipeline)
In the SaveChanges_Executing, I search through all the pending changes, and if any changed properties have IsReadOnly evaluating to true, I throw an exception.
By keeping this workaround code only in this one method, and keeping the relevant business logic in the IsReadOnly methods, whenever the Microsoft Lightswitch team introduces a fix for this bug, the only change needed in your code should be to remove the workaround code from SaveChanges_Executing.
partial void SaveChanges_Executing()
{
EntityChangeSet changes = this.DataWorkspace.ETMPortalData.Details.GetChanges();
var addedOrModified = changes.ModifiedEntities.Union(changes.AddedEntities);
Func<IEntityProperty,bool> isChanged = p =>
p.Entity.Details.EntityState == EntityState.Added && p.Value == null ?
false
: p is IEntityStorageProperty ?
(p as IEntityStorageProperty).IsChanged
: p is IEntityReferenceProperty ?
(p as IEntityReferenceProperty).IsChanged
: false;
var changedReadOnlyProperties = addedOrModified
.SelectMany(entity => entity.Details.Properties.All()
.Where(property => isChanged(property) && property.IsReadOnly)
.Select(changedReadOnlyProperty => new
{
EntityName = entity.Details.DisplayName,
PropertyName = changedReadOnlyProperty.DisplayName
}));
if (changedReadOnlyProperties.Count() > 0)
throw new Exception(
string.Format("The following properties are read-only:\n{0}",
string.Join("\n", changedReadOnlyProperties.Select(
x => x.EntityName + ":" + x.PropertyName))));
}
I’m being a bit cute here with the “one-liner” function isChanged. In practice, you’ll probably want to make it more readable and declare it as an extension method in a helper class; but you get the idea.
Update 3 May 2013:
Steve Lasker, program manager on the Visual Studio Lightswitch team, replied to the Microsoft Connect entry with a proposed workaround, and explains the following:
Unfortunately, there’s a bit of a disconnect that’s happened with how this property was intended to be used. IsReadOnly was a client scenario, specifically to help set UI Controls to a readonly state, and not intended as a full security access feature. It was not meant to enforce access on the server, but we completely understand that’s how it could be interpreted.
When the entity is sent to the server, we do not fire all the events for all the properties of each entity submitted to the server upon deserialization.
Even setting IsReadOnly will not cause an access exception to be thrown.
So the official word is that IsReadOnly works as designed. It’s a bit of an odd duck. It’s meant to help set UI Controls to a readonly state. But it also enforces that state depending on the tier that initiates the action.
It appears in both the “Desktop Client” and “Server” perspectives in the Entity Designer. Its description reads, “Returns whether the property is read-only. Runs on the tier where the property’s read-only value is checked.” This sounds awfully similar to the description for the Validate method, “Called when the property is validated. Runs on the tier where the property is validated.” The Validate method is applied regardless of tier, but IsReadOnly is applied only when initiated by the Desktop Client or the Server. One can easily see the potential confusion.
The Validate method, by the way, is less than ideal for this sort of validation – try using it alongside permission elevation scenario I’ve outlined here and it will fail to see the elevated permission.
For now, I’ll be sticking to the SaveChanges_Executing workaround I’ve outlined – it seems the cleanest approach.
In a previous post, I demonstrated one way of having vertical column header text in LightSwitch grids. A comment in that post asked if it was possible to use a similar approach to right-align column header text.
Here’s one way to do it… create a new override column header style based on the default column header style, but with an additional setter to modify the horizontal alignment property of the TextBlock. Iterate through the grid’s columns and apply that override column header style to the columns which have their TextAlignment property set to Right.
using System.Collections.Generic;
using Microsoft.LightSwitch;
using Microsoft.LightSwitch.Presentation.Extensions;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows;
using Microsoft.LightSwitch.Presentation.Implementation.Controls;
namespace LightSwitchApplication
{
public partial class EditableProductsGrid
{
partial void EditableProductsGrid_InitializeDataWorkspace(List<IDataService> saveChangesTo)
{
this.FindControl("grid").ControlAvailable += (s, e) =>
{
var dataGrid = e.Control as DataGrid;
var overrideColumnHeaderStyle = new Style(typeof(DataGridColumnHeader));
overrideColumnHeaderStyle.BasedOn = dataGrid.ColumnHeaderStyle;
overrideColumnHeaderStyle.Setters.Add(new Setter(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Right));
foreach (var column in dataGrid.Columns)
{
var ci = column.Header as ContentItemWrapperForColumnHeader;
var textAlignmentProperty = (string)ci.ContentItem.Properties["Microsoft.LightSwitch:RootControl/TextAlignment"];
if (textAlignmentProperty =="Right")
column.HeaderStyle = overrideColumnHeaderStyle;
}
};
}
}
}
Thanks to Ciro for the VB version:
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Controls.Primitives
Imports Microsoft.LightSwitch.Presentation.Implementation.Controls
'Prerequisites:
' Need to Add References to Client project (File View/Client/References/Add References) to:
' 1. System.Windows.Controls.Data (.NET tab of Add Reference dialog)
' 2. Microsoft.LightSwitch.Client.Internal (Use Browse tab do point do dll: C:Program FilesMicrosoft Visual Studio 10.0Common7IDELightSwitch1.0ClientMicrosoft.LightSwitch.Client.Internal.dll)
Namespace LightSwitchApplication
Public Class EditableCarsGrid
Private Sub EditableProductsGrid_InitializeDataWorkspace(saveChangesTo As System.Collections.Generic.List(Of Microsoft.LightSwitch.IDataService))
' Write your code here.
AddHandler FindControl("grid").ControlAvailable, _
Sub(sender As Object, e As ControlAvailableEventArgs)
Dim dataGrid = CType(e.Control, DataGrid)
Dim overrideColumnHeaderStyle = New Style(GetType(DataGridColumnHeader))
'
overrideColumnHeaderStyle.BasedOn = dataGrid.ColumnHeaderStyle
overrideColumnHeaderStyle.Setters.Add(New Setter(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Right))
For Each column In dataGrid.Columns
Dim ci = CType(column.Header, ContentItemWrapperForColumnHeader)
Dim textAlignmentProperty = CStr(ci.ContentItem.Properties("Microsoft.LightSwitch:RootControl/TextAlignment"))
If (textAlignmentProperty = "Right") Then
column.HeaderStyle = overrideColumnHeaderStyle
End If
Next
End Sub
End Sub
End Class
End Namespace
In some scenarios, there is the need to dynamically change the display name for one or more screens (and thus the associated menu items) in a LightSwitch application. This most often happens as part of supporting multiple localizations, but comes up in other cases as well. Luckily, this is a pretty easy task, but it’s not immediately obvious how to do it; it takes some digging through ill documented object trees to find the right objects.
Read More Post a comment (4)My CoffeeScript fizzbuzzplopping “one-liner” for the day…
console.log([1..175].map((i)->(((if i % v is 0 then k) for k,v of {fizz:3,buzz:5,plop:7,ping:11}).join '') or i))
So what’s this about?
Javascript has some bitter parts. Javascript has, underneath the bitterness, some tasty goodness.
CoffeeScript is one of several solutions currently available that attempts to surface the tasty parts while minimizing your exposure to the bitterness. These days, Javascript is increasingly becoming as much as platform as a language. CoffeeScript is Javascript with a couple dozen syntactic sugars, making it similar in syntax to Ruby, which compiles directly to surprisingly readable Javascript.
Read More Post a comment (0)Here’s a quick and dirty way of achieving vertical text for selected column headers in your LightSwitch grid without resorting to a custom control.
Read More Post a comment (16)When running Out-Of-Browser, the System.Windows.Application class surfaces the MainWindow.Title in Silverlight 5 (and thus LightSwitch for Visual Studio 11). For In-Browser in either Silverlight 4 or 5 (and LightSwitch 2011), you can use the DOM bridge to set the page title.
if (System.Windows.Application.Current.IsRunningOutOfBrowser)
System.Windows.Application.Current.MainWindow.Title = title;
else
System.Windows.Browser.HtmlPage.Document.SetProperty("title", title);
For LightSwitch for Visual Studio 11 apps, right-click on your LS project in the solution explorer and choose “View Application Code (Client)” and add this method:
public void SetTitle(string title)
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>
{
if (System.Windows.Application.Current.IsRunningOutOfBrowser)
System.Windows.Application.Current.MainWindow.Title = title;
else
System.Windows.Browser.HtmlPage.Document.SetProperty("title", title);
});
}
For LightSwitch 2011 apps, you can only do this In-Browser. Also you’ll need to add a reference to System.Windows.Browser in your client subproject.
public void SetTitle(string title)
{
Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() =>
{
if (!System.Windows.Application.Current.IsRunningOutOfBrowser)
System.Windows.Browser.HtmlPage.Document.SetProperty("title", title);
});
}
Now you can call this.Application.SetTitle(“My New Title”); from any of your screens.
LightSwitch:
- LightSwitch Help Website: A Full CRUD DataJs and KnockoutJs LightSwitch Example Using Only An .Html Page
- Paul Van Bladel: A Generic Audit Trail Solution – Revisited
- Eric Erhardt: Display a chart built on aggregated data in Visual Studio LightSwitch
Javascript/HTML5
- Gilad Bracha – Channel 9 Video: Dart: A Well Structured Web Programming Language
- Colin Eberhardt: KnockoutJS vs. Silverlight
Visual Studio:
- Dustin Campbell – Channel 9 Video: Going Deeper with Project Roslyn: Exposing the C# and VB compiler’s code analysis
WCF:
- Channel 9 Video: WCF Data Services v5, Performance Killers, Project Detroit and more
Windows Phone 7:
- WindowsPhoneGeek: New Coding4Fun Toolkit v1.5.6 released
- Den Delimarsky: Changes to the Dropbox API – Upload files the new way from a Windows Phone
When debugging LightSwitch applications within Visual Studio, you can elect to use a different web browser. This allows you to test with other traditional browsers (Firefox, Chrome, Opera, etc.), but perhaps more usefully, it lets you automatically start up your app in a tool like Silverlight Spy.
Switch to “File View” in your LightSwitch project.
Right-click on the Screens folder under the Client project and choose “Browse With…”
Either select one of the existing browsers, or add another…
Click “Set as Default” then “Cancel” (because we don’t actually want to browse the “Screens” folder!). Next hit F5 and start debugging your in-browser LightSwitch app using your newly selected browser.
There’s also a handy tool for Visual Studio 2010, WoVS Default Browser Switcher, which makes this easy via the Visual Studio toolbar.

