Silverlight / WCF : Writing your own Custom WCF Proxy Generator to support validation
Working on the data validation section of different projects in Silverlight we usually have to face the standard problem: basically in Silverlight 3 the data validation framework relies on exceptions thrown in the setter of objects properties.
In a real-world application our data will surely come from a Web Service (we are not using RIA Services yet), if we do not have control over the service itself we are forced to use the proxy classes generated by svcutil or Visual Studio as part of our domain model.
The main problem is we do not have huge control over the classes that are generated by the standard WCF Proxy Generator that Visual Studio provide, and the classes it generates are pretty simple (they only support the INotifyPropertyChanged interface).
Using the RIA services framework can help solving the validation problem because the proxy classes it generate have a richer set of functionalities built in.
However if we are stuck with plain WCF services we have several ways to overcome this problem and add validation logic (or any other business logic) to these classes.
One of the possible approach (not the simplest one I have to admit) is to write you own WCF Proxy Class Generator and alter the code that the standard generator provide; I had this idea looking at this post that explains the basis of customizing the generator: Customizing WCF Proxy Generation in Visual Studio 2008.
For a first implementation we want to be able to generate a class like this:
1: [System.Diagnostics.DebuggerStepThroughAttribute()]
Silverlight and the AG_E_NETWORK_ERROR - a thrilling story!
Working on the MusicStore project for the next DotNetMarche workshop I had the following scenario:
- A Web Service used to provide some data and images to the application.
- A Silverlight application (on a different website) that consumes the data and the images binding some absolute urls to Silverlight’s image controls.
here Image contains an absolute uri like: "http://localhost.:50671/Images/1.jpg"
Getting ready for the 12th DotNetMarche Workshop “Community Tour 2009”
We at DotNetMarche (our local, Italian .Net user group) are currently working on the last workshop for this year, it will be just before the Christmas Holidays on December 18th. The event will be divided in 2 different trances: in the morning we will have a presentation of Windows 7, Windows Server 2008 R2 and Hyper V virtualization and IIS7.5 for the IT managers and IT architects (these sessions will be presented by Piergiorgio Malusardi).
In the afternoon there will be a session entirely devoted to the Web Development using the 3 different technologies that the .Net world offers to the web developers: Asp.NET Classic (presented by Roberto Sileoni), Asp.NET MVC + jQuery (presented by Andrea Balducci), SIlverlight 3 (presented by Alessandro Giorgetti -myself :D).
We will show how you can build some portions of a simple MusicStore application using the 3 different technologies and which approach you can follow, the emphasis will be placed on the facilities that each technologies has in building the UI rather than the architecture of the whole project itself.
Here are some mockups of the interface we will implement:
If you are interested - I know you are! - go and subscribe at the event at: www.dotnetmarche.org.
As usual, for those that will stay with us after the workshop, we will organize a dinner and we will be at your service for further questions, jokes, boar ribs eating or whatever you like.
Related Content
- Last few days to sign up for the 12th DotNetMarche / Community Tour 2009 workshop (26/08/2015)
- Workshop: ‘Silverlight in Action - a starting point for Line of Business Applications’ (26/08/2015)
- 'Silverlight in Action' on December, Thursday 11 (12/01/2008)
- Are you ready for the upcoming DotNetMarche workshop on July 16 ? (07/08/2010)
- Tomorrow’s DotNetMarche Workshop Live Streaming (26/08/2015)
- More related document (49)
A very dirty trick to open a Popup after a PostBack operation
I’m not very proud of this cause it indicates a very poor interface design, but in a legacy project I’m working on we had the following scenario:
1- the user interact on some elements of the UI
2- the user clicks a button, at the PostBack operation information are gathered about the UI status and what the user done on some elements
3- at the end of the processing we needed to open a popup showing the result of the operation.
The problem is: opening a popup is a client-side operation, while all the processing is done server-side.
The trick is simple: at the end of the PostBack operation just inject some Javascript code that when executed at the client side (after all the DOM of the page has been constructed) open the popup with the usual window.open() function call.
You do that using the Page.ClientScript.RegisterStartupScript() call, but this one will not work if you try to use it inside an Ajax UpdatePanel; to solve the problem you have to use the ‘new’ ScriptManager.RegisterStartupScript() call, here’s an example:
Public Function CreateWindowsOpenFunction(ByVal link As String) As String
Changing the blog RSS feed
I’m changing this blog feed to conform it to the new domain name, you can subscribe to the new feed using these addresses:
http://www.primordialcode.com/index.php/feed/
http://feeds.feedburner.com/PrimordialCode
The old feed will be redirected to this new one and continue to exists anyway (at least for some time), if you follow my blog I would really appreciate if you can subscribe to this new one, thanks in advance.
Related Content
Windows Forms: Closeable TabControl
Today I needed to modify the UI of an application built by my company to enable the support for a multi-tabbed document interface (like the standard Visual Studio interface); since there’s no default support for displaying a close button (or context menu specific to each opened tab, or any other action button you may like to have on the tabs) I needed to implement my own version of this control.
It isn’t too hard to do once you read the documentation: basically you need to inform the control you will be going to render the content of each tab header by yourself (instead of using the default rendering) setting the value of the property DrawMode to TabDrawMode.OwnerDrawFixed. Then you can write your own rendering logic overriding the OnDrawItem function.
The main problem is: you can’t place other controls inside the Tab Header and you have to do all by hand; the same goes for the hit tests to see if you clicked on the custom action buttons you placed there, so you just need to do some basic math calculations to see if the mouse if over the buttons’ sensitive areas.
In my example I decided to render the close button using some standard GDI calls at first, but you can modify the code and use bitmaps or whatever you like.
here’s the full code:
/// <summary>
/// A tab control that can be used to close tabs with a custom drawn button.
/// </summary>
public class SidTabControl : System.Windows.Forms.TabControl
{
public SidTabControl()
{
SetStyle(ControlStyles.DoubleBuffer, true);
TabStop = false;
DrawMode = TabDrawMode.OwnerDrawFixed;
_closeButtonBrush = new SolidBrush(_closeButtonColor);
ItemSize = new Size(ItemSize.Width, 24);
// used to expand the tab header, find a better way
Padding = new Point(16, 0);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_stringFormat.Dispose();
_closeButtonBrush.Dispose();
}
base.Dispose(disposing);
}
public delegate void TabClosedDelegate(object sender, ClosedEventArgs e);
public delegate void TabClosingDelegate(object sender, ClosingEventArgs e);
public event TabClosedDelegate TabClosed;
public event TabClosingDelegate TabClosing;
private int _buttonWidth = 16;
[DefaultValue(16), Category("Action Buttons")]
public int ButtonWidth
{
get { return _buttonWidth; }
set { _buttonWidth = value; }
}
private int _crossOffset = 3;
[DefaultValue(3), Category("Action Buttons")]
public int CrossOffset
{
get { return _crossOffset; }
set { _crossOffset = value; }
}
private readonly StringFormat _stringFormat = new StringFormat
{
Alignment = StringAlignment.Near,
LineAlignment = StringAlignment.Center
};
private Color _closeButtonColor = Color.Red;
private Brush _closeButtonBrush;
[Category("Action Buttons")]
public Color CloseButtonColor
{
get { return _closeButtonColor; }
set
{
_closeButtonBrush.Dispose();
_closeButtonColor = value;
_closeButtonBrush = new SolidBrush(_closeButtonColor);
Invalidate();
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (e.Bounds != RectangleF.Empty)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
for (int nIndex = 0; nIndex < TabCount; nIndex++)
{
Rectangle tabArea = GetTabRect(nIndex);
Rectangle closeBtnRect = GetCloseBtnRect(tabArea);
if (nIndex != SelectedIndex)
{
e.Graphics.DrawRectangle(Pens.DarkGray, closeBtnRect);
DrawCross(e, closeBtnRect, Color.DarkGray);
}
else
{
//Drawing Close Button
e.Graphics.FillRectangle(_closeButtonBrush, closeBtnRect);
e.Graphics.DrawRectangle(Pens.White, closeBtnRect);
DrawCross(e, closeBtnRect, Color.White);
}
string str = TabPages[nIndex].Text;
e.Graphics.DrawString(str, Font, new SolidBrush(TabPages[nIndex].ForeColor), tabArea, _stringFormat);
}
}
}
private void DrawCross(DrawItemEventArgs e, Rectangle btnRect, Color color)
{
using (Pen pen = new Pen(color, 2))
{
float x1 = btnRect.X + CrossOffset;
float x2 = btnRect.Right - CrossOffset;
float y1 = btnRect.Y + CrossOffset;
float y2 = btnRect.Bottom - CrossOffset;
e.Graphics.DrawLine(pen, x1, y1, x2, y2);
e.Graphics.DrawLine(pen, x1, y2, x2, y1);
}
}
private Rectangle GetCloseBtnRect(Rectangle tabRect)
{
Rectangle rect = new Rectangle(tabRect.X + tabRect.Width - ButtonWidth - 4, (tabRect.Height - ButtonWidth) / 2, ButtonWidth, ButtonWidth);
return rect;
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (!DesignMode)
{
Rectangle rect = GetTabRect(SelectedIndex);
rect = GetCloseBtnRect(rect);
Point pt = new Point(e.X, e.Y);
if (rect.Contains(pt))
{
CloseTab(SelectedTab);
}
}
}
public void CloseTab(int tabindex)
{
CloseTab(TabPages[tabindex]);
}
public void CloseTab(TabPage tp)
{
ClosingEventArgs args = new ClosingEventArgs(TabPages.IndexOf(tp));
OnTabClosing(args);
//Remove the tab and fir the event tot he client
if (!args.Cancel)
{
// close and remove the tab, dispose it too
TabPages.Remove(tp);
OnTabClosed(new ClosedEventArgs(tp));
tp.Dispose();
}
}
protected void OnTabClosed(ClosedEventArgs e)
{
if (TabClosed != null)
{
TabClosed(this, e);
}
}
protected void OnTabClosing(ClosingEventArgs e)
{
if (TabClosing != null)
TabClosing(this, e);
}
}
public class ClosingEventArgs
{
private readonly int _nTabIndex = -1;
public ClosingEventArgs(int nTabIndex)
{
_nTabIndex = nTabIndex;
Cancel = false;
}
public bool Cancel { get; set; }
/// <summary>
/// Get/Set the tab index value where the close button is clicked
/// </summary>
public int TabIndex
{
get
{
return _nTabIndex;
}
}
}
public class ClosedEventArgs : EventArgs
{
private readonly TabPage _tab;
public ClosedEventArgs(TabPage tab)
{
_tab = tab;
}
/// <summary>
/// Get/Set the tab index value where the close button is clicked
/// </summary>
public TabPage Tab
{
get
{
return _tab;
}
}
}