Fixing Windows 8 Toggle Buttons

by StefanOlson 11. December 2012 03:10

In this post, Fixing the VisualState of your Win8 AppBar ToggleButton, Shawn Kendrot described a solution for dealing with issues with the Windows 8 ToggleButton.  Unfortunately his solution only delth with a situation where the user was clicking to change IsChecked.  If it was changed programmatically the same problem would exist.  So here is a slightly more generic solution:

public class AppBarToggleButton : ToggleButton
{
    /// <summary>
    /// IsCheckedInternal Dependency Property
    /// </summary>
    public static readonly DependencyProperty IsCheckedInternalProperty =
        DependencyProperty.Register("IsCheckedInternal", typeof(bool), typeof(AppBarToggleButton),
            new PropertyMetadata(false, OnIsCheckedInternalChanged));

    /// <summary>
    /// Gets or sets the IsCheckedInternal property. This dependency property 
    /// indicates ....
    /// </summary>
    public bool IsCheckedInternal
    {
        get { return (bool)GetValue(IsCheckedInternalProperty); }
        set { SetValue(IsCheckedInternalProperty, value); }
    }

    /// <summary>
    /// Handles changes to the IsCheckedInternal property.
    /// </summary>
    private static void OnIsCheckedInternalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        AppBarToggleButton target = (AppBarToggleButton)d;
        bool oldIsCheckedInternal = (bool)e.OldValue;
        bool newIsCheckedInternal = target.IsCheckedInternal;
        target.OnIsCheckedInternalChanged(oldIsCheckedInternal, newIsCheckedInternal);
    }

    /// <summary>
    /// Provides derived classes an opportunity to handle changes to the IsCheckedInternal property.
    /// </summary>
    protected virtual void OnIsCheckedInternalChanged(bool oldIsCheckedInternal, bool newIsCheckedInternal)
    {
        if (IsChecked != null)
        {
            VisualStateManager.GoToState(this, IsChecked.Value ? "Checked" : "Unchecked", false);
        }
    }
        
    public AppBarToggleButton()
    {
        BindingOperations.SetBinding(this, IsCheckedInternalProperty, new Binding(){Path=new PropertyPath("IsChecked"), Source = this});
    }
}

 

Hope this helps someone.

Tags:

Using Async/Await with Razor

by stefanolson 9. May 2012 06:12

I am working on making some information in my WinRT application available to the share charm in HTML format.  The easiest way to insert data into HTML content is to use razor, which is the basis of one of the view engines in ASP.NET MVC.  I’ll have a more detailed post soon on how to use razor with WinRT.

But in the meantime, I just wanted to quickly blog about using await within a razor file.  In WinRT, much of the API uses asynchronous functions, so if you want to call back into your application to get something like an image, you may need to await the result.

Unfortunately, if you have code like this:

<img src="@await AddImage(imageFile)"/>

Then it won't compile.  The solution is to use () around the expression, e.g:

<img src="@(await AddImage(imageFile))"/>

and then it works!

Hopefully this will help someone who encounters the same problem.

Tags:

WinRT Tapped Behaviour

by stefanolson 1. May 2012 14:55

In some of the default controls in WinRT XAML, when you press an item, such as a a GridViewItem it depresses down to indicate that has been tapped (pressed in pre-WinRT lingo!).  However, if you use an ItemControl, this does not happen.

The desired behaviour can be seen by going to the apps list on the start screen and tapping an icon (is actually easier to test with a mouse) and what you will notice is that as you move out of the button it goes back to normal size, which is consistent with the way the buttons have always worked on Windows.

Someone recently asked about replicating this behaviour in the WinRT forum:
http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/9a348a15-7f8d-46a9-a26c-4407180ed928

Unfortunately there is no default way to do this the moment, so I have built an extension that does this.

There is a bit of complexity in trying to ensure that the item returns to normal as you move out of or back into its rectangle. There doesn't seem to be an easily accessible WinRT function to confirm if your pointer is within the bounds.  Hopefully I've just missed something and someone can correct me.

Anyway, to use it, register the namespace:

xmlns:Controls="using:OlsonSoftware.WinRT.Controls"

and add Controls:TapBehaviourExtension.TapBehavour="On" to your control. e.g:

<Image Controls:TapBehaviourExtension.TapBehavour="On" Source="Assets/Logo.png" Stretch="None"/>

Example project is here:

Tags:

'Binding' type does not have a matching DependencyObjectType error

by StefanOlson 30. May 2011 06:53

This is one of those blog posts so that I can easily remember what causes this particular problem.  In the Virtual Tour Viewer, I have found on occasions with .net 4.0 that if you press the back button, to go back to a previous page you get a “'Binding' type does not have a matching DependencyObjectType” exception.

As it turns out this is because I had PresentationTraceSources in the page. e.g:

OlsImage="{Binding SmallImageFile,PresentationTraceSources.TraceLevel=High}"

If you remove the reference to PresentationTraceSources  (which allows you to debug bindings), then the problem goes away!

interestingly, this exception only occurs when using the back button – if I go directly to a page there is no problem.  Weird, eh?

Tags:

WPF | Virtual Tours

Handling Legacy Urls in Asp.Net MVC 3

by StefanOlson 26. April 2011 15:57

Update: I have discovered that the way this was originally written by Matt Hawley will cause asp.net MVC to incorrectly generate route urls. This is fixed by overriding GetVirtualPath. Code has been updated below.

I'm currently in the process of transforming the PalaceVirtualTours website from asp.net web forms to asp.net MVC 3. 

However there are a number of pages that already have URLs that are linked to by other sites or have reasonable search engine rankings, so if someone tries to go to that page it needs to be redirected to the the new MVC URL.

Matt Hawley wrote an article about this sometime ago: http://www.eworldui.net/blog/post/2008/04/ASPNET-MVC---Legacy-Url-Routing.aspx

Unfortunately the code that he provides doesn't work, MVC reports that a controller is required, as described in this stack overflow question: http://stackoverflow.com/questions/2528078/legacy-url-rewriting-with-query-string-parameters

The solution to this is to use an IHttpHandler directly, rather than an MVCHandler.

Here is the full updated, working code:

// The legacy route class that exposes a RedirectActionName
public class LegacyRoute : Route
{
    public LegacyRoute(string url, string redirectRuleName):base(url, new LegacyRouteHandler())
    {
        RedirectRuleName = redirectRuleName;
    }

    public string RedirectRuleName { get; set; }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        return null;
    }
}

// The legacy route handler, used for getting the HttpHandler for the request
public class LegacyRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new LegacyHandler();
    }
}

// The legacy HttpHandler that handles the request
public class LegacyHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        var requestContext = context.Request.RequestContext;
        string redirectActionName = ((LegacyRoute)requestContext.RouteData.Route).RedirectRuleName;

        var queryString = requestContext.HttpContext.Request.QueryString;
        foreach (var key in queryString.AllKeys)
        {
            requestContext.RouteData.Values.Add(key, queryString[key]);
        }

        VirtualPathData data = RouteTable.Routes.GetVirtualPath(requestContext, redirectActionName, requestContext.RouteData.Values);

        context.Response.Status = "301 Moved Permanently";
        context.Response.AppendHeader("Location", data.VirtualPath);
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

And here is how to use it:

routes.MapRoute(
    "BPTour", // Route name
    "buckingham-palace-virtual-tour", // URL with parameters
    new { controller = "Tours", action = "BuckinghamPalace", id = UrlParameter.Optional } // Parameter defaults
);
// redirect /bptour to the BPTour route.
routes.Add("", new LegacyRoute("bptour", "BPTour"));

Tags:

asp.net MVC

Introduction to JQuery Ui Server Controls

by StefanOlson 25. April 2011 15:20

Today I have released onto codeplex a new library, the jQuery UI server controls:

http://jqueryuiserverctls.codeplex.com/

This library is intended to make sure that when you use jQuery controls such as tabs you don't end up with the page rendering without the jQuery styling applied.  This happens because the scripts to create things such as tabs doesn't execute until after the page is loaded. This is jarring to the user because they see the tabs appearing like this:
image
Before the script gets applied.

And then it appears like this:
image

Whilst you may not notice this when running on localhost, a site like this demonstrates it adequately:
http://en.webdiyer.com/MvcPager/Demo/MsAjaxOrders

If you use this library to create your tabs all that styling is applied on the server and thus your page always appears the way it should when the client first sees it!

How to use it

Normally, if you were using jQuery UI to create the tabs above , here is how it would look:

<script type="text/javascript">
    $(function () { $("#nonservertabs").tabs(); });
</script>         

<div id="nonservertabs">
    <ul>
        <li><a href="#nonservertabs-1">Gallery</a></li>
        <li><a href="#nonservertabs-2">List</a></li>
    </ul>
    <div id="nonservertabs-1">
    This is the gallery tab
    </div>
    <div id="nonservertabs-2">
    <p>This is the list tab at @DateTime.Now.ToString()</p>
    </div>
</div>

Here is how the same code can be created using the  jQuery UI server controls:

@Html.JQueryUiTabs(new JQueryUiTabsSettings
{
    Items = new List<JQueryUiTab>
                {new JQueryUiTab{Title="Gallery"}.SetContent(@<text>This is the gallery tab</text>),
                 new JQueryUiTab{Title="List"}.SetContent(@<p>This is the list tab at @DateTime.Now.ToString()</p>)}
}).Render()

Which results in this output:

<script type="text/javascript">$(function(){$('#tabs').tabs({selected:0,});});
</script>
<div class="ui-tabs ui-widget ui-widget-content ui-corner-all" id="tabs">
<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
<li class="ui-state-default ui-corner-topui-tabs-selected ui-state-active"><a href="#tabs-1">
<
span>Gallery</span></a></li><li class="ui-state-default ui-corner-top"><a href="#tabs-2">
<
span>List</span></a></li></ul> <div class="ui-tabs-panel ui-widget-content ui-corner-bottom" id="tabs-1"> This is the gallery tab </div> <div class="ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" id="tabs-2"> <p>This is the list tab at 25/04/2011 5:28:51 p.m.</p> </div> </diV>

As you can see, all the styles required by jQuery are automatically inserted for you, which ensures that the client sees the tabs as you intended without any potential delay caused by script execution.

There are other options  you can apply, such as cookies that I will talk about the future blog posts.

Download the library for yourself today and try it out! Would love to get your feedback on how it can be improved.

Tags:

asp.net MVC | jQuery Ui Server ControlsUi Server Controls

Silverlight 5: does anyone at Microsoft talk to each other?

by StefanOlson 25. April 2011 12:11

The Silverlight 5 beta was made available a couple of weeks ago (http://www.silverlight.net/getstarted/silverlight-5-beta/).  Most of the features had been telegraphed in December at the Microsoft Silverlight firestarter which appeared to have been hastily organised to try and fend off criticism that Silverlight was being deprecated in favour of HTML 5.

Certainly there was, and still is some confusion as to what the purpose of Silverlight is. It was originally sold to us as a cross-platform browser independent platform.  That now seems to have changed and it is HTML 5 is the cross-platform browser independent platform.  Unfortunately the tooling to support developing HTML and JavaScript is absolutely appalling in comparison with the outstanding tools for Silverlight.

Based on this, a website that I was developing for a customer was going to have all the public parts written in HTML and the pieces where you need to login written in Silverlight.  I have now changed that and completely removed Silverlight from the project and it will all be in HTML.

So why would anyone use Silverlight? This is a good question, if you want to have a rich application that can make use of the available hardware, why wouldn’t you build a WPF application?  Well partially because WPF appears to be completely on the scrapheap. The WPF Toolkit hasn't even been updated to support visual studio 2010 and the .net 4 framework!

My previous post on LightSwitch described how they had chosen to use Silverlight rather than WPF for desktop applications.  This appears to be what Microsoft wants you to do, with continued improvements in full trust and multi-window support.

So what's new in Silverlight 5 that isn't available in WPF:

  • XAML Debugging with breakpoints for binding debugging. This looks outstanding!
  • Double (and multi) click support
  • GPU-accelerated XNA-compatible 3D and immediate-mode 2D API
  • RichTextBox overflow

But there has been no word on when or if any of these features will be available in WPF. Why is there not a new release of the WPF Toolkit with the 3-D and 2-D API available? Those of us who have invested massive amount of time in developing 3-D software using WPF (in my case for the 360° panoramas in the virtual tours) have to start from scratch, yet again!  Whilst it may be a good move to use XNA, as it is available on multiple platforms, it means that people working in both WPF in Silverlight have two different Apis to write for.

The RichTextBox overflow is completely baffling to me, why did they just not port flow documents?

There are also plenty of features already in Silverlight that are not available in WPF:

  • DeepZoom
  • Ria services - to use this you have to create a WCF service and you don't get all the advantages that you do when working with it in Silverlight
  • HyperlinkButton
  • ChildWindow
  • UriMapping

It appears from some rumours that Silverlight will be the primary programming language for Windows 8, once again suggesting that WPF has a limited future, which may be why these features have not made it into WPF.

What’s still missing from in Silverlight from WPF:

  • MultiBinding (see here for an alternative)
  • Preview events (in WPF all events such as mouse button down have a preview event that runs down the visual tree)
  • Triggers
  • FlowDocuments (see here for my attempt at FlowDocuments)
  • RoutedEvents
  • BooleanToVisibilityConverter
  • GroupBox
  • Toolbars
  • Expander
  • Commanding infrastructure
  • Default set of brushes
  • Many ToolTip options
  • I'm sure there are more than I have missed.

All of these make developing Silverlight a lot harder and you often find yourself hacking around the lack of these features.  I have built a library to try and ease this, but you are forced to have separate xaml between the two targets because there are so many things not available in both.

To top this off, there is a new release of Silverlight for the Windows phone, but that is only Silverlight 4!

If, like me you are building an application for WPF, Silverlight and Windows Phone, this just makes life incredibly difficult because across all three platforms there are features that are available in completely different ways! 

One wonders why people at Microsoft don't sit down and talk to each other and try and make these things simpler for developers, especially since some developers are likely to abandon WPF because of the complexity of trying to manage Silverlight and WPF development, or developers like me will abandon Silverlight development for public facing websites.

There are certainly some good new features in Silverlight 5, but I hope that the various teams at Microsoft will start talking to each other and create a more cohesive development platform.  With Google already way ahead on the phone market and wanting to get into the operating system market Microsoft really have to up their game.

Tags:

Silverlight | WPF

Is this the beginning of the end for WPF?

by StefanOlson 4. August 2010 07:16

Microsoft yesterday announced a new product, called LightSwitch, which is a new Visual Studio-based IDE to rapidly develop applications. You can see a very impressive demonstration here:

http://channel9.msdn.com/posts/Dan/Jay-Schmelzer-Introducing-Visual-Studio-LightSwitch/

Looks like there's some very nice controls (for handling phone numbers etc.) in there, hopefully they will be made available outside of that product.

What is particularly interesting about this is that they are producing a Windows application, which is not using WPF. They have chosen to use Silverlight  running out of browser. This is bad for WPF, because that is what you would expect to be used on the Windows platform.  It suggests that over time WPF will be replaced by Silverlight, even on Windows.

So why have they chosen Silverlight? I guess there is some advantages in allowing organizations to be able  run the application on the web.  Hopefully, the reason for that decision will become clearer over time.

What I would've done is built the two desktop targets using WPF. However, what the Microsoft development team would've found is that it's almost impossible to share xaml code between WPF and Silverlight, so they would quickly given up and gone the Silverlight only route.

Hopefully Microsoft can improve the developer experience when single sourcing WPF and Silverlight, but there's still a long way to go.

….Stefan

Tags:

Silverlight | WPF

Workaround for low-quality bitmap resizing in WPF 4

by StefanOlson 20. July 2010 09:55

As many people have already discovered Microsoft made a change in the.net framework resulting in the quality of bitmap scaling being reduced by default.  This is because the default mode is now low quality, rather than high-quality.  Optionally you can go back to the way it was previously, but this requires you to turn this feature on. 

It is very disappointing that Microsoft have chosen to break backwards compatibility in this way. Apparently it was to help some customers to were experiencing slow image scaling. Why they were not just told to set the default to low quality image scaling, rather than forcing everyone in this mode is beyond me! In another similar situation they specifically didn't change the default font scaling mode, designed to increase text quality because it would break existing applications. Why they did not apply the same theory to this feature is confusing at the least.

Details of the changes are here:.

Crappy Image Resizing in WPF? Try RenderOptions.BitmapScalingMode

I have found the best way to ensure that this feature used throughout a program is to set the default scaling mode in the window constructor:

public MainWindow()
{
    InitializeComponent();

    RenderOptions.SetBitmapScalingMode(this, BitmapScalingMode.);
}

However, this does not deal with a situation where you need to use RenderTargetBitmap, for which this setting does not apply.  You might use RenderTargetBitmap in a situation where you want to resize an image, something like this:

RenderTargetBitmap result = new RenderTargetBitmap(newWidth, newHeight, 96, 96, PixelFormats.Default);

DrawingVisual vis = new DrawingVisual();
using (DrawingContext dc = vis.RenderOpen())
    dc.DrawImage(Image, new Rect(0, 0, newWidth, newHeight));

result.Render(vis);

So obviously you would probably try and do this:

RenderOptions.SetBitmapScalingMode(vis, BitmapScalingMode.HighQuality);

Which would do nothing.  Unfortunately, Microsoft's support of this particular problem has been extremely poor with no responses in newsgroups or in comments on blogs. I e-mailed Pete Brown, and received no response.

As it turns out, thankfully there is a workaround. You just need to recode,using a DrawingGroup (I found the solution here: http://xiu.shoeke.com/2010/07/15/resizing-images-with-wpf-4-0/) and set the attached property on the DrawingGroup. e.g:

RenderTargetBitmap result = new RenderTargetBitmap(newWidth, newHeight, 96, 96, PixelFormats.Default);

var group = new DrawingGroup();  

RenderOptions.SetBitmapScalingMode(group, BitmapScalingMode.HighQuality);
group.Children.Add(new ImageDrawing(Image, new Rect(0, 0, newWidth, newHeight)));  

DrawingVisual vis = new DrawingVisual();
using (var drawingContext = vis.RenderOpen())  
    drawingContext.DrawDrawing(group);  

result.Render(vis);

Which does result in a large amount of additional unnecessary code, but at least it is still possible for your application to work in WPF 4!

….Stefan

Tags:

WPF

Updates to Silverlight Multi-binding support

by StefanOlson 28. April 2010 10:36

Update 29/June/2010: Colin Eberhardt who originally developed this technique has posted an update, including these changes: http://www.scottlogic.co.uk/blog/colin/2010/05/silverlight-multibinding-solution-for-silverlight-4/

The Silverlight multi-binding functionality that I have described previously (see here) doesn't work in Silverlight 4, due to the changes in the xaml parser. This code:

<local:MultiBinding TargetProperty="Text" Converter="{StaticResource TitleConverter}">
    <Binding Path="Surname"/>                            
    <Binding Path="Forename"/>
</local:MultiBinding>

Gives this exception:

System.Windows.Markup.XamlParseException: Set property 'SLMultiBinding.MultiBinding.Bindings' threw an exception

the solution is to wrap the bindings in a binding collection, e.g:

<local:MultiBinding TargetProperty="Text" Converter="{StaticResource TitleConverter}">
    <local:BindingCollection>
        <Binding Path="Surname"/>                            
        <Binding Path="Forename"/>
    </local:BindingCollection>
</local:MultiBinding>

 

You also need to download the latest version of the MultiBinding.cs file, from here

Tags:

Silverlight

About the author

Stefan Olson is the Managing Director of Olson Software.  He has been developing software using Microsoft Technologies for nearly 20 years.

He is currently working on building the next generation Virtual Tour software in WPF and Silverlight for www.palacevirtualtours.com.