Silverlight, WPF and .NET Subscribe via RSS
Photo of Alan Cobb
About me:   I'm a .NET, Silverlight 3, 4 and WPF (Windows Presentation Foundation) programmer based in Northern California, USA.   See more about the Silverlight presentations I have been giving here.

I'm currently available for work.  Send me an email at the address here and we can talk about your project. 
Translating ScottGu’s Silverlight “Digg Client” to WPF
By: Alan Cobb Date: 2008-Feb-26 15:01

As Jesse Liberty has suggested, since the Silverlight 2 beta has not yet been released I decided to do a WPF implementation of ScottGu’s excellent Silverlight 2 “Digg client” tutorial (thanks Scott!).  It turned out to be a bit harder than I expected, but I did learn things.  Below I list the changes I had to make to translate Scott’s Silverlight 2 app to WPF.  Scott already lists some of these in step 8 of his tutorial.

 

You can download my working WPF VS-2008 solution here.

 

Converting to a WPF “Navigation App”:

To create a browser-like experience similar to Silverlight I wrote my version as a WPF “navigation app”.  Another way would be as an XBAP, but since Scott used a full WPF desktop app, so did I.  To make it a WPF “navigation app” I had to replace Scott’s outer Window with a NavigationWindow.  Scott’s original Silverlight UserControl subclass has the name Page, but WPF already has a general Page class used by navigation apps.  Therefore I replaced his UserControl base class with a WPF Page base class, and named the derived class Page1.

 

 

 

Emulating Silverlight 2’s HyperlinkButton:

Since WPF does not have an exact equivalent of Silverlight 2’s HyperlinkButton class, Scott replaces it with a TextBlock.  I’m not sure if Scott wrote the extra WPF code to do it, but I decided to make the TextBlock actually behave like a “hyperlink”.  Therefore when clicked it must actually navigate to the target HTML page, and it must expose bindable dependency properties (DPs) that emulate HyperlinkButton’s DPs.  I ended up creating a UserControl called HyperlinkButton_ForWPF to encapsulate this functionality and wrap the TextBlock. 

 

To support data binding I needed to add two custom DPs to HyperlinkButton_ForWPF: Content2 and NavigateUri.  Why call it Content2 and not Content like Silverlight does?  Because UserControl already has a DP named Content.  There might be a way to “repurpose” the UserControl.Content DP, but the things I tried didn’t work, so I just added the custom Content2 DP instead.

 

Once the HyperlinkButton_ForWPF was working, I was able to click on the title text for an individual Digg HTML article and have the outer NavigationWindow get filled with that HTML page.  Initially pressing the back button did return me to the original Page, but all the existing Digg content was gone.  That is the default behavior of a WPF navigation app.  It recreates each page from scratch whenever it is reentered.   But we want the state of the Page saved, so that we don’t need to requery Digg each time.  By setting Page.KeepAlive to true, we get the desired state-retaining behavior.

 

 

  

 

Calling the Digg Web API:

Scott uses a WebClient object to query the Digg web API.  I needed to make several changes before it would work correctly under WPF.  The original version returned HTTP error code 403 in response to my queries.  Digg’s documentation says that our HTTP query request must include a User-Agent HTTP Header.  Adding that fixed the 403 errors.  Another problem was that apostrophes in stories were displayed with strange characters.  The fix for that was to explicitly tell the WebClient object to assume UTF-8 encoding.

 

I modified Scott’s original Digg query a little also.  Instead of just requesting 20 random stories from a given topic (/stories/topic/{topic name}), I used a different endpoint (/stories/topic/{topic name}/popular).  The added  “popular” part asks for the most popular stories.  I also added a “sort” parameter, so the most popular stories are at the top of the list.  By the way, there are only about 50 “topics” that this endpoint queries for, so don’t expect to be able to put any arbitrary phrase in the search box (as if it were Google).  The list of topics is here: http://apidoc.digg.com/Topics.  For example, “basketball”, “microsoft” or “music”.

 

What was my conclusion from all this?  That it will be great when we actually get the real Silverlight 2 beta to play with, rather than trying to approximate it :).

Alan Cobb

Comments [8]  |  Silverlight | WPF #  
By: Adam Wawrzyniak Date: 2008-Mar-18 18:09 UTC
Very interesting post. Thank you for it!
Can you elaborate a bit more about the differences between WPF and Silverlight? I have project created in WPF containing few Pages and now I would like to convert this project to Silverlight. I have hard time to find some info related to that topic (except yours and Scott's blog) and I am not sure what is the best way to do modification, except rewriting line by line... and this approach I would like to avoid :)

I am sorry that probably I am not providing you appropriate information about my project, but I don't know what is relevant since I am the designer who got developers work to do ;)
I would appreciate your comments!
Adam
By: Alan Cobb Date: 2008-Mar-19 01:26 UTC
Hi Adam,

Longer term MS is talking about having some tools to make conversions easier, but as of today there are enough differences that IMO you really have to know both WPF and SL (and their differences) in order to do a translation.

Is your target SL1 or 2? SL2 is definitely closer to WPF than SL1 is, but even SL2 has enough differences to make most real-world apps a bit of work to convert IMO. For example, as I mentioned in my post, ScottGu uses a HyperlinkButton on the SL2 side, but that is actually quite different from WPF's Hyperlink element. I realize the "party line" from MS is that conversion (at least from SL to WPF) will (or will eventually be) not too difficult, but I think part of that is marketing-spin.

One approach would be to contract with someone (like me or someone local to you) to do the "rough" conversion, and then you could finish the details and tune it up to an appearance of your liking.

Alan Cobb
By: Adam Wawrzyniak Date: 2008-Mar-19 20:36 UTC
Alan,

Do you know how to replace a TabControl in SL2? My application has a number of tabs hiding unwanted content. I know that I can change the visibility of the object without placing it inside the tab, but the extra code needed for changing the visibility as a response for any user action is just..., lets say... too much work :)

Any online resources you would recommend on the topic: converting WFF into SIlverlight 2?

About the idea of contracting someone from outside to do the job: it maybe the most efficient way, but its not likely to happen.

Adam
By: Alan Cobb Date: 2008-Mar-20 19:01 UTC
Hi Adam,

Re. TabControl in SL2:
One way to do tabs would be to create a two-row Grid. The top row (narrow) would be a horizontal StackPanel full of Buttons. You would style the buttons to look like tabs. The bottom row (big) would hold the "pages" (UserControls) containing the contents of each "tab". When you pressed a button your code-behind would make its associated "page" visible in the row below. I don't see any way to get around some code-behind.

Re. Resources on converting WPF -> SL2:
I haven't seen anything on that yet. I agree it would probably make an interesting blog or CodeProject article.

Alan Cobb
By: Alan Cobb Date: 2008-Mar-23 02:48 UTC
Below is a post from Silverlight.net where the guy implements a simple SL2 tab control (see the post from 'coder21' on 03-22-2008). He includes a downloadable VS2008 project. His TabControl class derives from ItemsControl.

http://silverlight.net/forums/p/12271/39856.aspx#39856

Alan Cobb
By: Adam Wawrzyniak Date: 2008-Mar-24 18:06 UTC
Hi Alan,

Thank you for the advice, I will use it! :)

Adam
By: Rolf Rhoden Date: 2008-Jun-02 12:41 UTC
Alan, I can't get the sample to Navigate to the Digg story. I keep getting this error when the NavigationService.Navigate method is called

System.ArgumentException was unhandled
Message="';' must be followed by parameter=value pair."
Source="WindowsBase"
StackTrace:
at MS.Internal.ContentType.ParseParameterAndValue(String parameterAndValue)
at MS.Internal.ContentType..ctor(String contentType)
at MS.Internal.WpfWebRequestHelper.GetContentType(WebResponse response)
at System.Windows.Navigation.NavigationService.GetObjectFromResponse(WebRequest request, WebResponse response, Uri destinationUri, Object navState)
at System.Windows.Navigation.NavigationService.HandleWebResponse(IAsyncResult ar)
at System.Windows.Navigation.NavigationService.<>c__DisplayClassc.<HandleWebResponseOnRightDispatcher>b__8(Object unused)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at DiggDesktopSample.App.Main() in C:\Documents and Settings\chuck.wagner\My Documents\Visual Studio 2008\Projects\DiggDesktopSample\obj\Debug\App.g.cs:line 0
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
By: MVP Ken Lin Date: 2008-Jul-17 09:39 UTC
I am sorry, where is the netvigation windows from?
I right click the WPF Project and add new item, Then from the new item windows, i cannot find any called Netvigation Window
All comments require the approval of the site owner before being displayed.
Name
E-mail
Home page
Comment: (No HTML)  
Live Comment Preview:
Please enter the anti-spam code shown.
Copyright 2010 Alan Cobb:  www.alancobb.com    Subscribe: Subscribe via RSS
Theme by Alan Cobb, based on dasBlog calmBlue.
newtelligence dasBlog 2.3.9074.18820
Page rendered: 2010-Mar-09 13:57 CA, USA Time
dasBlog logo
Search
Admin Login