Live Example
For an Introductory Article on LightSwitch, See
Note: You must have Visual Studio Professional, or higher, to perform all the steps in this tutorial.
You can download Visual Studio LightSwitch from this link:
Putting Multiple LightSwitch Applications Into Your Website
Microsoft Visual Studio LightSwitch suffers from what I call the "full screen limitation". LightSwitch wants to fill the entire screen, and it wants to manage the roles and users. This is fine if you only have one application, however in many situations, you want a LightSwitch application to be part of a group of applications in a single portal. You want all applications to share the same users, roles and database.
Unlike the article Online Ordering, that describes a normal "LightSwitch only" deployment, this article will explore the techniques used to deploy a LightSwitch application inside a ASP.NET application that contains other applications. In this article, DotNetNuke will be used, however, everything here can be used in any ASP.NET application.
The key to integrating LightSwitch into an ASP.NET application, is to use IFrames
.
The Requirements
In this example, we will create an application that meets the following requirements:
- Allow Registered Users (the Posters), the ability to create Posts of things they have for sale, without the need to post their email address
- Allow Anonymous Users (the Buyers) the ability to see the Posts without requiring them to have the Silverlight plug-in installed
- Allow the Buyers the ability to respond to a Post, and automatically email the Poster
- Allow the Poster the ability to view and respond to all communications sorted by Post
- Allow Administrators the ability to edit all data
This may not be considered a large application, but it would take a few days effort. With LightSwitch, you can create the entire application in about an hour.
Walk-Through of the 'Things For Sale' Application
You can try out the live Things For Sale application at this link:
When you are not logged-in, you will see a list of Posts that you can browse.
You can click on a Post to send the Poster a message.
When you log in, you will have the ability to create Posts, and to see any Messages related to a Post (you will be emailed when a new Message is created for one of your Posts).
Also note, that there are a lot of other features such as Concurrency Checking and Automatic Ellipses that LightSwitch implements automatically.
Creating the Application
You can download Visual Studio LightSwitch from this link:
After installing it, use File, New Project to create a LightSwitch application.
Double-click on Properties in the Solution Explorer.
Set the application as a Web application.
Set it to use Forms Authentication.
Categories Table And Screen
Creating a table for Categories and a screen to edit them, this is a task that can be completed in under a minute.
Right-click on the Data Sources node in the Solution Explorer, and select Add Table.
Click on the table name to change the name. Enter Category for the name.
Create the table above.
Right-click on the Screens node, and select Add Screen...
Create an Editable Grid Screen using Categories (LightSwitch automatically 'pluralizes' the name of the table).
The screen will display.
Hit F5 to run the application.
We can now create Categories in the application.
Close your web browser to stop the application.
Create the Remaining Tables
Create a Post
table with the schema above.
Create a Message
table with the schema above.
Create Relationships
Open the Message
table, and click the Relationship
button.
In the Add New Relationship box, enter the settings above.
Open the Post
table.
In the Add New Relationship box, enter the settings above.
The relationships are complete.
Setting relationships is very important with LightSwitch. It allows important features, such as allowing you to create screens, where the Posts
and the Messages
related to the Posts
, always stay in sync, without requiring any code.
It is very rare for any Entity
(table) to not have a relationship to one or more other Entities.
Set Default Values on Record Creation
Open the Message
table, and select Write Code, then Message Created.
Change the method to the following:
partial void Message_Created()
{
this.MessageCreated = DateTime.UtcNow;
}
This will set the date for a Message
when it is created. Notice that we are using "UtcNow" so that the time is recorded in Coordinated Universal Time (UTC) time. When we display the time, we can convert it to the user's local time.
Open the Post
table, and select Write Code, then Post Updating.
Change the method to the following:
partial void Posts_Updating(Post entity)
{
entity.PostUpdated = DateTime.UtcNow;
}
Open the Post
table, and select Write Code, then Post Created.
Change the method to the following:
partial void Post_Created()
{
this.PostedBy = this.Application.User.Name;
this.PostCreated = DateTime.UtcNow;
this.PostUpdated = DateTime.UtcNow;
this.Active = true;
}
Note the line:
this.PostedBy = this.Application.User.Name;
This is all that is required to segment the data by user.
At run-time, the DotNetNuke site (or any ASP.NET site running under Forms Authentication), will provide the username for "this.Application.User.Name
".
In a later step, we will use a PreProcess
query to restrict a user to only see their own Posts
(and Messages
).
Sending Emails
This application will require emails to be sent. Let's enable that functionality now.
To do this, we will need to switch to File View.
In the Server
project, add references to System.configuration
and System.Messaging
.
Add a class called MailHelper.cs to the UserCode folder of the Server
project.
Use the following code:
using System.Net;
using System.Net.Mail;
using System.Configuration;
using System;
namespace LightSwitchApplication
{
public class MailHelper
{
private string _SMTPSendingEmailAddress { get; set; }
private string _SMTPServer { get; set; }
private string _SMTPUserId { get; set; }
private string _SMTPPassword { get; set; }
private int _SMTPPort { get; set; }
private bool _SMTPSSL { get; set; }
private string _MailFromName { get; set; }
private string _MailToEmail { get; set; }
private string _MailToName { get; set; }
private string _MailSubject { get; set; }
private string _MailBody { get; set; }
public MailHelper(
string SendFromName, string SendToEmail,
string SendToName, string Subject,
string Body)
{
_MailFromName = SendFromName;
_MailToEmail = SendToEmail;
_MailToName = SendToName;
_MailSubject = Subject;
_MailBody = Body;
_SMTPSendingEmailAddress = Convert.ToString
(ConfigurationManager.AppSettings["SMTPSendingEmailAddress"]);
_SMTPServer = Convert.ToString(ConfigurationManager.AppSettings["SMTPServer"]);
_SMTPUserId = Convert.ToString(ConfigurationManager.AppSettings["SMTPUserID"]);
_SMTPPassword = Convert.ToString(ConfigurationManager.AppSettings["SMTPPassword"]);
_SMTPPort = Convert.ToInt32(ConfigurationManager.AppSettings["SMTPPort"]);
_SMTPSSL = Convert.ToBoolean(ConfigurationManager.AppSettings["SMTPSSL"]);
}
public void SendMail()
{
MailMessage mail = new MailMessage();
System.Net.Mail.MailAddress mailFrom =
new System.Net.Mail.MailAddress(_SMTPSendingEmailAddress, _MailFromName);
System.Net.Mail.MailAddress mailTo =
new System.Net.Mail.MailAddress(_MailToEmail, _MailToName);
var _with1 = mail;
_with1.From = mailFrom;
_with1.To.Add(mailTo);
_with1.Subject = _MailSubject;
_with1.Body = _MailBody;
SmtpClient smtp = new SmtpClient(_SMTPServer, _SMTPPort);
smtp.EnableSsl = _SMTPSSL;
smtp.Credentials =
new NetworkCredential(_SMTPUserId, _SMTPPassword);
smtp.Send(mail);
}
}
}
Click on the project name in the Solution Explorer, then select Show All Files.
This will allow you to see the ServerGenerated
project.
This project is created by LightSwitch and used when LightSwitch is deployed as a web application. It is the place where we will eventually place the .aspx files that will generate the HTML pages. For now, we only want to add some entries to the Web.config file:
This will allow us to easily change the SMTP Mail Server settings when the application is deployed.
Switch back to Logical View.
Open the Message
table, and select the Messages_Inserted
method.
Use the following code for the method (to send the email):
#region Messages_Inserted
partial void Messages_Inserted(Message entity)
{
string strSubject = "Message From ThingsForSale";
string strMessage = String.Format("{0}",
"This is a message From the Things For Sale program.")
+ Environment.NewLine + Environment.NewLine;
strMessage = strMessage + String.Format("Regarding the post '{0}'",
entity.Post.Description) + Environment.NewLine;
strMessage = strMessage + String.Format("This message was sent by {0}",
entity.NameFrom) + Environment.NewLine + Environment.NewLine;
strMessage = strMessage + String.Format("Message: {0}",
entity.MessageText) + Environment.NewLine;
MailHelper mailHelper =
new MailHelper(
entity.NameFrom,
entity.EmailTo,
entity.NameTo,
strSubject,
strMessage);
mailHelper.SendMail();
}
#endregion
Create the Posts And Messages Screen
In the Solution Explorer, right-click on the Screens node and select Add Screen...
Create a List and Details Screen.
Note: Because we created relationships between the tables, we can enable Posts and Messages to be on the same screen, by simply checking a box.
The screen will show:
When you run the application, you will be able to enter Posts and Messages.
Deploy Application into a DotNetNuke Website
Follow the directions here to deploy the application into a DotNetNUke website: Easy DotNetNuke LightSwitch Deployment.
We now have the basic layout illustrated above. The LightSwitch application is running in an IFrame
and has the same Database Connection, MachineKey, and Forms Cookie, so it is able to communicate with the DotNetNuke site hosting it, and share user authentication.
For many applications, this is enough. In our example, we need to determine if a user is an Administrator or not, because we want to provide additional features to Administrators.
We could simply add the DotNetNuke user and roles tables to the LightSwitch application as external tables, but I have found that this can sometimes cause the user table to lock (see this link for more information).
Adding a WCF RIA Service prevents any locking issues.
Creating a WCF RIA Service
(Note: You must have Visual Studio Professional, or higher, to perform the following steps.)
(See this link for official information on creating WCF RIA Services for LightSwitch.)
Add a New Project.
Create a new Class Library.
Right-click on the Class1.cs file that is created and delete it.
Add a Entity Data Model...
Connect to the DotNetNuke database.
Normally, we only need to add the vw_UserRoles
view to determine if a user is an Administrator or not.
However, we will also add the Category
, Post
, and Message
tables, because we will also use the Entity Data Model for the .aspx (HTML) pages that we will create in a later step.
Build the project.
Add a Domain Service Class.
We only need the vw_userRoles
in the Domain Service Class. Also, un-check Enable client access for added security because we won't need it.
The Domain Service Class will be created.
Add [Query(IsDefault = true)]
to the top of the method (that is automatically created).
Save the file and Build Solution.
Right-click on the Data Sources node, and select Add Data Source...
Select WCF RIA Service and click Next.
(Do not be surprised if the box goes away and nothing happens for a long time. Also, the box may now be hidden behind the Visual Studio main window.)
Click Add Reference.
Select the Data Project and click OK.
Wait for the Domain Service Class to appear in the list box. Sometimes, it can take 1-2 minutes.
When it appears, select it, and click Next.
Select the Entity to use by checking its box (in this case, we want to use the vw_UserRoles
).
Don't bother entering anything for the Connection String because we will set it in the Web.config manually.
Click Finish.
The data source will show up.
Copy the connection string from the App.config of the data project.
Switch to File View, and open the Web.config, and add the connection string.
Using the WCF RIA Service
To demonstrate how we can use our new WCF RIA Service, open the EditableCategoriesGrid
screen and select the EditableCategoriesGrid_CanRun
event.
Change the method to the following code:
partial void EditableCategoriesGrid_CanRun(ref bool result)
{
var WorkSpace = this.CreateDataWorkspace();
var UserInRole = (from DNNUser in WorkSpace.DNNDomainServiceData.vw_UserRoles
where DNNUser.Username == this.User.Name
where DNNUser.RoleName == "Administrators"
select DNNUser).FirstOrDefault();
result = (UserInRole != null);
}
Click on the project in the Solution Explorer.
This will allow you to select Publish.
Re-publish the application.
You will have to redo all the changes you made to the web.config when you followed the directions described in Easy DotNetNuke LightSwitch Deployment because new things have been added to the web.config when we created the WCF RIA Service.
When you run the application in the DotNetNuke website, only an administrator will see the link to edit the Categories.
Enabling Security using a Pre-Process Query
One of the requirements is that an administrator can see all Posts, but a non-administrator can only see their own Posts (and Messages).
Open the Posts Entity, and select Posts All PreprocessQuery.
Change the code to the following:
partial void Posts_All_PreprocessQuery(ref IQueryable<Post> query)
{
if (this.Application.User.IsAuthenticated)
{
string UserName = this.Application.User.Name;
var WorkSpace = this.Application.CreateDataWorkspace();
var UserInRole = (from DNNUser in WorkSpace.DNNDomainServiceData.vw_UserRoles
where DNNUser.Username == UserName
where DNNUser.RoleName == "Administrators"
select DNNUser).FirstOrDefault();
if (UserInRole == null)
{
query = query.Where(x => x.PostedBy == this.Application.User.Name);
}
}
}
Modal Windows (PopUps)
Modal Windows (otherwise known as Popups) are an important User Interface tool because they require the user to complete the task set before them before doing anything else.
In this sample application, we want Popups to show when a user is viewing an existing Message or responding to a Message.
There are other Popups, but they are created automatically by LightSwitch.
Currently, when an existing Message is opened, it shows all the fields like the image above.
We desire the PopUp to resemble the image above.
To do this, we will make our own PopUp and then override the code that opens the current PopUp, to open our PopUp.
In the screen designer, select the Details Column, then Add the Selected Item for Messages.
It will display.
Change the section to a Modal Window.
Change all the TextBoxes to Labels and delete the remaining items.
Select the Modal Window, and note the name of the window. Uncheck the Show Button box (otherwise LightSwitch would show a button at the bottom of the screen to open the window).
Click on the Messages Data Grid, expand the Command Bar, right-click on the Edit button, and select Override Code.
Change the code to the following:
partial void MessagesEditSelected_Execute()
{
this.OpenModalWindow("Messages_SelectedItem");
}
Now if we select the Edit button, it opens our custom Popup.
We will add a Respond button in the next step, that will allow us to actually create a Message, as a response to a Message entered in the HTML page (to be created in a later step).
Note: To understand the next steps, it is suggested that you read: This Is How LightSwitch Does MVVM.
Switch to File View, and add a Reference, in the Client
project, to System.Windows.Controls
(this is so we can programmatically interact with a PopUp
as a ChildWindow
).
Select Add Data Item...
Create a Local Property of type Message
and call it Message_Response
.
It will show on the screen's "View Model" (see: This Is How LightSwitch Does MVVM for an explanation of View Model).
Select the Details Column section, and add the Message Response property to the screen.
Change it to Modal Window.
The properties will show.
- Remove all the controls except the Name To, Email To, and Message Text
- Change the Name To to a Label
- In the Properties of the Modal Window, uncheck Show Button
Add a Button to the Command Bar of the Modal Window and call it SaveResponse.
In the Properties for the Button, change the Display Name to Save Message.
Right-click on the Button, and select Edit Execute Code.
Change the code to:
#region SaveResponse_Execute
partial void SaveResponse_Execute()
{
this.CloseModalWindow("Message_Response");
this.Save();
}
#endregion
Navigate up the object tree to the Command Bar for the Messages Data Grid, and delete the Add button, and add a New Button.
Call it RespondToMessage
.
Drag it to the top of the other two remaining buttons, and right-click on it and select Edit Execute Code.
Use the following code to create a new Message
and open the Popup, also to detect when the PopUp is closed (when clicking the x in the upper right corner of the Popup), and to remove any unsaved Messages
:
#region RespondToMessage_Execute
partial void RespondToMessage_Execute()
{
Message_Response = new Message();
Message_Response.Post = Posts.SelectedItem;
Message_Response.MessageBy = this.Application.User.Name;
Message_Response.NameFrom = Messages.SelectedItem.NameTo;
Message_Response.EmailFrom = Messages.SelectedItem.EmailTo;
Message_Response.NameTo = Messages.SelectedItem.NameFrom;
Message_Response.EmailTo = Messages.SelectedItem.EmailFrom;
this.OpenModalWindow("Message_Response");
this.FindControl("Message_Response").ControlAvailable +=
new EventHandler<ControlAvailableEventArgs>(PostsListDetail_ControlAvailable);
}
#endregion
#region PostsListDetail_ControlAvailable
void PostsListDetail_ControlAvailable(object sender, ControlAvailableEventArgs e)
{
ChildWindow window = (ChildWindow)e.Control;
window.Closed += new EventHandler(Message_Response_Closed);
}
#endregion
#region Message_Response_Closed
void Message_Response_Closed(object sender, EventArgs e)
{
ChildWindow window = (ChildWindow)sender;
if (!(window.DialogResult.HasValue))
{
foreach (Message message in
this.DataWorkspace.ApplicationData.Details.GetChanges()
.AddedEntities.OfType<Message>())
{
message.Details.DiscardChanges();
}
}
}
#endregion
You will also need to add using System.Windows.Controls;
to the top of the class.
Creating HTML Pages
Switch to File View.
Add a Reference to System.configuration
to the ServerGenerated
project.
Add an .aspx page called PublicPage.aspx, and use the following code for the code behind (please get the HTML code from the download):
using DNNData;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text.RegularExpressions;
using System.Transactions;
using System.Web.UI;
using System.Web.UI.WebControls;
using LightSwitchApplication;
namespace ApplicationData.Implementation
{
public partial class PublicPage : System.Web.UI.Page
{
#region CurrentPage
public int CurrentPage
{
get
{
if (ViewState["CurrentPage"] == null)
{
return 1;
}
else
{
return (int)ViewState["CurrentPage"];
}
}
set
{
ViewState["CurrentPage"] = value;
}
}
#endregion
#region CurrentPostID
public int CurrentPostID
{
get
{
if (ViewState["CurrentPostID"] == null)
{
return -1;
}
else
{
return (int)ViewState["CurrentPostID"];
}
}
set
{
ViewState["CurrentPostID"] = value;
}
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GetPosts(true, CurrentPage);
}
}
#region GetPosts
private void GetPosts(bool FillCategories, int intPage)
{
List<DNNData.Category> lstCategories = new List<DNNData.Category>();
string _IntrinsicData = Convert.ToString
(ConfigurationManager.ConnectionStrings["DotNetNuke5Entities"]);
DotNetNuke5Entities db = new DotNetNuke5Entities(_IntrinsicData);
int intCategoryID = -1;
if (!FillCategories)
{
intCategoryID = Convert.ToInt32(ddlCategories.SelectedValue);
}
if (FillCategories)
{
var colCatagories = (from Cat in db.Categories
select Cat).ToList();
DNNData.Category objCategory = new DNNData.Category();
objCategory.Id = -1;
objCategory.CategoryName = "All";
lstCategories.Add(objCategory);
foreach (var item in colCatagories)
{
lstCategories.Add(item);
}
ddlCategories.DataSource = lstCategories;
ddlCategories.DataBind();
}
var colPosts = from PST in db.Posts
select PST;
colPosts = colPosts.Where(x => x.Active == true);
if (intCategoryID != -1)
{
colPosts = colPosts.Where(x => x.Category.Id == intCategoryID);
}
colPosts =
colPosts.OrderByDescending(x => x.PostUpdated).
Skip(((intPage - 1) * 10)).Take(10);
gvPosts.DataSource = colPosts;
gvPosts.DataBind();
}
#endregion
#region ddlCategories_SelectedIndexChanged
protected void ddlCategories_SelectedIndexChanged(object sender, EventArgs e)
{
pnlMessage.Visible = false;
GetPosts(false, CurrentPage);
}
#endregion
#region btnLeft_Click
protected void btnLeft_Click(object sender, EventArgs e)
{
pnlMessage.Visible = false;
if (CurrentPage > 1)
{
CurrentPage--;
}
GetPosts(false, CurrentPage);
}
#endregion
#region btnRight_Click
protected void btnRight_Click(object sender, EventArgs e)
{
pnlMessage.Visible = false;
if (gvPosts.Rows.Count > 0)
{
CurrentPage++;
}
GetPosts(false, CurrentPage);
}
#endregion
#region gvPosts_RowCommand
protected void gvPosts_RowCommand(object sender, GridViewCommandEventArgs e)
{
LinkButton lnkButtton = (LinkButton)e.CommandSource;
CurrentPostID = Convert.ToInt32(lnkButtton.CommandArgument);
pnlMessage.Visible = true;
}
#endregion
#region btnSubmit_Click
protected void btnSubmit_Click(object sender, EventArgs e)
{
try
{
Transaction currentTrx = Transaction.Current;
Transaction.Current = null;
if (!IsValidEmail(txtEmail.Text))
{
lblError.Text = "Must use a valid Email";
return;
}
if (txtEmail.Text.Count() < 1)
{
lblError.Text = "Must enter a message";
return;
}
if (txtEmail.Text.Count() > 255)
{
lblError.Text = "Message must be less than 255 characters";
return;
}
string _IntrinsicData = Convert.ToString
(ConfigurationManager.ConnectionStrings["DotNetNuke5Entities"]);
DotNetNuke5Entities db = new DotNetNuke5Entities(_IntrinsicData);
var DNNUser = (from PST in db.Posts
from vw_Users in db.vw_UserRoles
where PST.PostedBy == vw_Users.Username
where PST.Id == CurrentPostID
select vw_Users).FirstOrDefault();
DNNData.Message NewMessage = new DNNData.Message();
NewMessage.NameFrom = txtName.Text;
NewMessage.EmailFrom = txtEmail.Text;
NewMessage.NameTo = DNNUser.DisplayName;
NewMessage.EmailTo = DNNUser.Email;
NewMessage.MessageText = txtMessage.Text;
NewMessage.MessageCreated = DateTime.UtcNow;
NewMessage.Message_Post = CurrentPostID;
db.AddToMessages(NewMessage);
db.SaveChanges();
var PostInfo = (from PST in db.Posts
where PST.Id == CurrentPostID
select PST).FirstOrDefault();
string strSubject = "Message From ThingsForSale";
string strMessage = String.Format("{0}",
"This is a message From the Things For Sale program.")
+ Environment.NewLine + Environment.NewLine;
strMessage = strMessage + String.Format("Regarding the post '{0}'",
PostInfo.Description) + Environment.NewLine;
strMessage = strMessage + String.Format("This message was sent by {0}",
txtName.Text) + Environment.NewLine + Environment.NewLine;
strMessage = strMessage + String.Format("Message: {0}",
txtMessage.Text) + Environment.NewLine;
MailHelper mailHelper =
new MailHelper(
txtName.Text,
DNNUser.Email,
DNNUser.DisplayName,
strSubject,
strMessage);
mailHelper.SendMail();
lblError.Text = "Success";
txtMessage.Text = "";
}
catch (Exception ex)
{
lblError.Text = ex.Message;
}
}
#endregion
#region IsValidEmail
public static bool IsValidEmail(string strIn)
{
return Regex.IsMatch(strIn,
@"^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|
[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))" +
@"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*
[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$");
}
#endregion
}
}
Creating a Link to the HTML Page in LightSwitch
Add a Reference, in the Client
project, to System.Windows.Browser
.
Switch to Logical View.
Add Screen...
Add a New Data Screen called PublicPage
with no Screen Data selected.
Select the PublicPage_Run
method.
Change it to the following code:
partial void PublicPage_Run(ref bool handled)
{
Dispatchers.Main.Invoke(() =>
{
HtmlPage.Window.Navigate(new Uri("PublicPage.aspx", UriKind.Relative));
});
handled = true;
}
You will also need to add the following using
statements to the class:
using Microsoft.LightSwitch.Threading;
using System.Windows.Browser;
We now need to add the PublicPage.aspx to the build file, so that LightSwitch will include it in the build.
Note: You will want to back up your entire solution before performing the following steps:
Switch to File View, right-click on the LightSwitch project and select Unload Project.
Right-click on the unloaded project and select Edit.
Add the following to the bottom of the _buildFile
section:
<_BuildFile Include="ServerGenerated\PublicPage.aspx">
<SubFolder>
</SubFolder>
<PublishType>
</PublishType>
</_BuildFile>
Reload the project.
Now you can run the project and click on the Public Page link...
... and navigate to the HTML page.
In your application, you will want to make the HTML page available for your unauthenticated users.
The live demonstration on the LightSwitchHelpWebsite, has one IFrame
that is pointed directly at the PublicPage.aspx, and is only shown to un-authenticated users. A second IFrame
, enabled only for Registered users, shows the normal LightSwitch application.
Finishing Touches
On the Posts screen, delete Posted By because it is set programmatically.
However, notice that it still shows up on the automatically created PopUp.
Open the Post Entity, and select the PostedBy
field, then un-check the Display by Default box.
The PopUp will no longer show the field.
On the Posts screen, set the Message Data Grid to Use Read-only Controls.
Select the CanExecute Code for the Respond To Message button.
Change the code to the following:
#region RespondToMessage_CanExecute
partial void RespondToMessage_CanExecute(ref bool result)
{
result = (Messages.SelectedItem != null);
}
#endregion
Do the same for the Message Edit button.
This causes the buttons to be disabled if there is no Message
selected.
Go into Properties for the project, set the Post List Detail screen as the startup screen.
An Advanced LightSwitch Application
This demonstrates an advanced LightSwitch application. However, there is still a lot more to LightSwitch. For example, the entire UI can be controlled using Silverlight Custom Controls.
There are a ton of tutorials, tips, blogs, and forums at: