SharpGIS

#GIS from a .NET developer's perspective

WPF vs. Silverlight - Part 3 - Creating Bitmaps Programmatically

See intro blogpost here.

WPF Requires you to call BeginInit and EndInit before and after setting the source. Also the load failed handlers are different.

    BitmapImage bmi = new BitmapImage();
#if !SILVERLIGHT
    bmi.BeginInit();
#endif
    Image img = new Image();
    bmi.UriSource = new Uri(strUrl, UriKind.Absolute);
#if SILVERLIGHT
    img.ImageFailed += img_ImageFailed;
#else
    bmi.DownloadFailed += bmi_DownloadFailed;
    bmi.EndInit();
#endif
    Image myImage = new Image();
    myImage.Source = bmi;

Next: WPF vs. Silverlight - Part 4 - Animations

WPF vs. Silverlight - Part 2 - XamlReader

See intro blogpost here.

XamlReader has different overloads in WPF and Silverlight. Silverlight takes a string. WPF takes a stream to a string.

    UIElement element;
#if SILVERLIGHT
    element = XamlReader.Load(xaml);
#else
    using (MemoryStream xamlStream = 
        new MemoryStream(UTF8Encoding.Default.GetBytes(xaml)))
        element = XamlReader.Load(xamlStream);
#endif

Next: WPF vs. Silverlight - Part 3 - Creating Bitmaps Programmatically

WPF vs. Silverlight - Part 1 - Custom Controls Theme

See intro blogpost here.

When applying default theme and template to custom controls that you declared in "/Themes/Generic.xaml" it's done differently in Silverlight and WPF:

public class MyControl : Control
{
    public MyControl()
    {
#if SILVERLIGHT
        this.DefaultStyleKey = typeof(MyControl);
#endif
    }
    static MyControl() {
#if !SILVERLIGHT 
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(HoverControl),
            new FrameworkPropertyMetadata(
            typeof(HoverControl))); 
#endif
    }
}

Also, in the WPF Assembly, you need to register the theme file in AssemblyInfo.cs This is done with the following line of code:

[assembly: ThemeInfo(ResourceDictionaryLocation.None,ResourceDictionaryLocation.SourceAssembly)]

Note: This code is usually added automatically when you create a new WPF project.

Next: WPF vs. Silverlight - Part 2 - XamlReader

WPF vs. Silverlight - Part 0 - Introduction

In my day to day work, I work on building not one, not two, but three .NET API's. One for Silverlight, one for WPF, and one for Windows Phone. However, since this is all based on the same technology (.NET and XAML), we reuse most of our code for all 3 (a rough estimate is 99% is the same code files). That's pretty cool, because I can create one feature in for instance Silverlight, and WPF and Windows Phone will instantly have it.

...well except if I hit one of those inconsistencies that makes up the remaining 1% of code differences. I've searched through our code and looked for the most common code differences in the API's, and the following series will cover these.

When you do need to write platform specific code, you can use a compiler conditional to do it. By default a Silverlight project will have a "SILVERLIGHT" conditional declared that you can use to exclude or include code for a specific platform. This is done by surrounding the code with a #if [condition] ... #endif section. Example:

#if SILVERLIGHT
   //Silverlight and Windows Phone
#else
   //WPF
#endif

If you are writing code for Windows Phone as well, note that this is also a Silverlight app, and will compile with the SILVERLIGHT conditional. However, Windows Phone also has a default conditional you can use to exclude/include features separate from Windows Phone:
//Windows phone:

#if WINDOWS_PHONE
    //Windows Phone
#endif
or
#if !SILVERLIGHT || WINDOWS_PHONE
    //Windows Phone and WPF
#endif
or
#if SILVERLIGHT && !WINDOWS_PHONE
    //Silverlight but NOT Windows Phone
#endif

You will see these conditionals used in the upcoming blogposts to separate the code differences between the platforms. Click to select a topic below:

  1. WPF vs. Silverlight - Part 1 - Custom Controls Theme
  2. WPF vs. Silverlight - Part 2 – XamlReader
  3. WPF vs. Silverlight - Part 3 - Creating Bitmaps Programmatically
  4. WPF vs. Silverlight - Part 4 – Animations
  5. WPF vs. Silverlight - Part 5 - XAML Control Instantiation
  6. WPF vs. Silverlight - Part 6 - Debug.WriteLine
  7. WPF vs. Silverlight - Part 7 - Case sensitivity
  8. WPF vs. Silverlight - Part 8 - Reusing code in Visual Studio #1
  9. WPF vs. Silverlight - Part 9 - Reusing code in Visual Studio #2
  10. WPF vs. Silverlight - Part 10 - XAML Parser Differences 
  11. WPF vs. Silverlight - Part 11 - Silverlight on Phone vs. Browser
  12. More to come… keep checking back… 

Enjoy!

---

A note on our development approach: We generally build a new feature for Silverlight first. Since Silverlight is a subset of WPF, we are less likely to be using an API that's not available in WPF (since it has most of what Silverlight has). We then test the code in WPF and tweak if necessary (tweaks rarely needed). Windows Phone is Silverlight (albeit roughly an earlier version), so we might exclude a feature here and there, but generally the only differences here are various simplifications for performance reasons (most of which isn’t needed with the upcoming Mango release), and of course sometimes retemplating for a smaller touch-centric screen.

GZIP Compressed Web Requests in WP7

Before you read on, you might want to read the “Take 2” blogpost instead: http://www.sharpgis.net/post/2011/08/28/GZIP-Compressed-Web-Requests-in-WP7-Take-2.aspx

If you use the WebClient in Silverlight, the browser handles the web request for you, and if the browser supports compressed content (which all of them does), it will take full advantage of that, and you never have to worry about it. However on Windows Phone 7, there is no browser, and the Silverlight API itself handles the web request. However, this client does NOT support compressed content. The result of that is often a much larger response, which in turn means an app that loads data from the web updates much slower, and for those who pay per Mb downloaded, also a big increase in dataplan costs. Data like JSON and XML can sometimes compress as much as 10x, so there’s quite a benefit to compress data responses.

Unfortunately you can’t choose to request compressed content through the header and handle the uncompressing yourself, because the required header (Content-Encoding=gzip,deflate) is a restricted header. This is probably a carry-over from Browser-Silverlight (since there the browser handles this), and for whatever reason this restriction wasn’t removed (this is also the case with the Mango beta release). Not supporting gzip and/or deflate in web requests really seems like a (huge) oversight in Windows Phone. If you agree, please vote for this feature here.

So what to do? Well luckily Mango adds support for Sockets which is basically the core component driving the WebClient. So I ventured into creating my own WebClient subclass, and building custom HttpWebRequest/HttpWebResponse handlers that uses a Socket to request data in gzip format.

You can download the compiled library as well as source code below. It works exactly like WebClient (in fact it’s a subclass of WebClient). However, note that the “OpenWrite” is currently not supported (DownloadString, OpenRead and UploadString are all OK to use).

Example:

   1:  WebClient c = new SharpGIS.GZipWebClient();
   2:  c.OpenReadCompleted += new OpenReadCompletedEventHandler(c_OpenReadCompleted);
   3:  c.OpenReadAsync(new Uri("http://www.google.com"), "TESTSTATE");
   4:   
   5:  ...
   6:   
   7:  private void c_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
   8:  {
   9:      StreamReader reader = new StreamReader(e.Result);
  10:      string result = reader.ReadToEnd();
  11:  }

Note: The library requires SharpZipLib (included in binary).

.NET Code Reuse Presentation–The bits

To those who came out to see my presentation either in person or online (and stuck out till after all the raffle prizes :-), thanks! I had a blast doing the presentation.

As promised here is the slide deck:

Download the source code from the app I built. Note: You will need the v2.2beta or later version of the ArcGIS API for Silverlight/WPF and Windows Phone to build this. Download is free, but you will need to register for an Esri account to download it (also free). You can get get these bits here: https://betacommunity.esri.com/

.NET Code Reuse presentation

Tomorrow, I’ll be doing a presentation on .NET code reuse across Silverlight, WPF and Windows Phone at the LA SLUG user group meeting.

Microsoft has been touting for a while that you can reuse your code across these platforms, but never really tell you about all the gotcha’s. As part of my day job building the ArcGIS API for Silverlight, WPF and Windows Phone (where 99% of the code is reused), I’ll talk about the experiences and lessons learned, and what usually hides in the remaining 1%.

The meetup will take place:
Wednesday, May 25, 2011 at 7:00 PM (PDT)
United Future / Wongdoody
8500 Steller Dr Culver City, CA

If you are not in the LA Area, you will miss out on the free beer and pizza, but for the first time ever LA SLUG will be streaming the event online. See event details for more info. I’ll post slides (and if there is a recording, a link to that as well) shortly after.

Silverlight vs. WPF

Silverlight or WPF? Who will win? Or will they team up to be the best tigerblood-powered kick-ass platform ever conceived?

Custom Cursors in Silverlight

There has been quite a few blog posts on how to create custom cursors in Silverlight, but I felt some of them were very limited or not very re-useable, or required you to put the cursor in the layout and put restrictions on your layout (like for instance requiring you to use a Canvas as parent for your cursor). So I ended up writing my own class for it that doesn’t have any of these restrictions.

The basic idea is the same as other approaches out there: You “disable” the cursor on your element by setting myElement.Cursor = Cursors.None. Next you move a custom UIElement around on top of your layout which represents your custom cursor. My approach uses a Popup, and therefore never requires you to modify your layout, and you can easily change the cursor on the fly. The cursor look is defined using a DataTemplate and can contain animations and so on.

All you need to do is define a DataTemplate and use the Attached Property to define the template. Below is an example of this working on a border element:

<UserControl x:Class="CustomCursor.MainPage"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:local="clr-namespace:SharpGIS.CustomCursor">
   <UserControl.Resources>
        <DataTemplate x:Key="CircleCursor">
            <Ellipse Fill="Red" Width="20" Height="20" />
        </DataTemplate>
   </UserControl.Resources>
   <Grid>
       <Border Background="Blue" 
           local:CustomCursor.CursorTemplate="{StaticResource CircleCursor}" />
   </Grid>
</UserControl>

And that’s all there is to it!

If you need to customize where the centering of the element is, simply apply a TranslateTranform to the element. Ie. if you want the above circle to center on the mouse location, add a TranslateTransform of –10,-10 to the ellipse.

Get Microsoft Silverlight

Downloads:

Update: Someone awesome ported this to Windows Store apps as well! Go download here: http://customcursor.codeplex.com/

Windows Phone 7 Copy/Paste on TextBlocks

With the recent update of Windows Phone 7, AKA the "NoDo" update, Windows Phone got support for Copy/Paste. Any existing app out there instantly gets this support automatically, without the developer has to do anything.

However, copy/paste only works on TextBoxes, but what if you want to allow the user to copy text from a TextBlock? Today this is not possible. The trick to make this work is to simply use a readonly TextBox, and restyle it to look like a TextBlock. Here's the TextBox style that accomplishes this:

<Style x:Key="ReadOnlyTextBox" TargetType="TextBox">
	<Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}" />
	<Setter Property="IsReadOnly" Value="True" />
	<Setter Property="TextWrapping" Value="Wrap" />
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate>
				<Grid>
					<ContentPresenter x:Name="ContentElement" />
				</Grid>
			</ControlTemplate>
		</Setter.Value>
	</Setter>
</Style>

Note: This approach actually also applies to "normal" browser-Silverlight as well.

RefreshBox for Windows Phone 7

I always liked the simplicity in iPhone for refreshing a list of various feeds, for instance email, tweet, RSS etc. Basically when you get to the top of the list, you simply keep pulling and the app will check for the latest items:

image

I wanted something similar in my WinPhone application, and ventured out to make this. You could probably go and argue now that Windows Phone 7 shouldn’t be copying ideas from other phones but be its own, which is a somewhat fair argument, but when something just works, it just works. So yes this post is about totally ripping of an iPhone idea. I’ll admit that Smile

If you don’t care how this was done, just jump to the bottom to see the result in action, and/or download the bits.

Anyway, luckily creating a control like this wasn’t too hard. It starts with inheriting from the ListBox control which has all the list features needed. It also supports pulling beyond the contents of the list and when you let go, it “pops back” to the top item. So all I need to do, is :
1. Find a way to place an item in this “outside area”.
2. Detect that the user is pulling the list out in this area.

Placing the element in the outer area proved to be really simple. The ListBox template is basically just a ScrollViewer with an ItemsPresenter inside it. So all we need to do is place a grid with the contents on top of the ItemsPresenter with a negative vertical margin:

<ControlTemplate TargetType="local:RefreshBox"> 
    <ScrollViewer x:Name="ScrollViewer" ...> 
        <Grid> 
            <Grid Margin="0,-90,0,30" Height="60" VerticalAlignment="Top" x:Name="ReleaseElement"> 
                <!-- content goes here --> 
            </Grid> 
        </Grid> 
        <ItemsPresenter/> 
    </ScrollViewer> 
</ControlTemplate>

Sprinkle a little visual states in that content, and we would be able to change the message when we detect the user has been pulling beyond the threshold.

The first thing we do is get a reference to the ScrollViewer and the ReleaseElement during OnApplyTemplate(), and listen to MouseMove (the event that causes the scrolling) and ManipulationCompleted (triggered when the user lets go of the screen).

public override void OnApplyTemplate() 
{ 
    base.OnApplyTemplate(); 
    ElementScrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer; 
    if (ElementScrollViewer != null) 
    {            
        ElementScrollViewer.MouseMove += viewer_MouseMove; 
        ElementScrollViewer.ManipulationCompleted += viewer_ManipulationCompleted; 
    } 
    ElementRelease = GetTemplateChild("ReleaseElement") as UIElement;        
    ChangeVisualState(false); 
}

In MouseMove we can then check the VerticalOffset of the ScrollViewer. You would think this offset is negative, but it gets clamped at 0, so we can’t use that. Instead by calculating where the ReleaseElement is physically located gives us an idea of how far we pulled:

private void viewer_MouseMove(object sender, MouseEventArgs e) 
{ 
    if (VerticalOffset == 0) 
    { 
        var p = this.TransformToVisual(ElementRelease).Transform(new Point()); 
        if (p.Y < -VerticalPullToRefreshDistance) //Passed thresdhold : In pulling state area 
        {             
            //TODO: Update layout//visual states 
        } 
        else //Is not pulling 
        { 
            //TODO: Update layout/visual states 
        } 
    } 
}

Similarly, when you let go of the screen we make the same check and raise an event if necessary:

private void viewer_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) 
{ 
    var p = this.TransformToVisual(ElementRelease).Transform(new Point()); 
    if (p.Y < -VerticalPullToRefreshDistance) 
    { 
        //TODO: Raise Polled to refresh event 
    } 
}

So here’s that this looks like….

Scrolled to the top of the list:

image

Pulling slightly down on the listbox beyond the top item:

image

Pulling all the way down: Message tells you to let go to refresh:

image

And here’s what that look like in action:

You can download the code and binary for a fully skinnable control/reusable below here:

Source : SharpGIS.Controls.RefreshBox_source.zip (32.31 kb)

Binary : SharpGIS.Controls.RefreshBox_binary.zip (6.48 kb)

UPDATE: If you are using v7.1 (Mango), the above approach will only work if you set ScrollViewer.ManipulationMode ="Control" on the RefreshBox. See herefor details.