Showing posts with label silverlight. Show all posts
Showing posts with label silverlight. Show all posts

Thursday, March 15, 2012

Fixing CornerRadius in Silverlight

OK - I know I've not posted in nearly a year... but this time I'm covering one of those "why the frack does it work like that" issues with Silverlight 4.

I hit this one today - I wanted to unify the radii of corners within a Silverlight application to replace the random set of radii used (1, 2, 4, 5, 8, 10, 12, 15 and 20 pixels no less) with a simpler set - small, medium, large and massive.

The problem is that (for whatever reason), the developers of Silverlight decided that we didn't need to be able to create CornerRadius objects in our ResourceDictionaries. Or rather that we could TRY, but that the XAML Loader was never told how to deal with them. Even though the design surfaces in Visual Studio and Expression Blend can quite happily deal with this!

So if you *DO* try then you either get an error saying that you can't set the readonly TopLeft property of a CornerRadius, or if, like me, you do this in your theme.xaml you just get a catastrophic error - somewhere in your project.

So what was the solution?

Well, there was a very good answer to exactly this on Stack Overflow - using a Value Converter to read named resource values from the object for which we want to set the CornerRadius... But I suddenly realised that there was no need to have a "magic string" as keys for the TopLeft etc values - we can just use properties on the value converter ITSELF!

The result is a pretty elegant way to get around a limitation of Silverlight, thus:


<Border x:Name="buttonBorder">

<Border.CornerRadius>

<Binding ElementName="buttonBorder">

<Binding.Converter>

<Converters:DynamicCornerRadiusConverter TopLeft="{StaticResource massiveCornerRadiusValue}"

TopRight="{StaticResource massiveCornerRadiusValue}"

BottomRight="{StaticResource massiveCornerRadiusValue}"

BottomLeft="0.0" />

Binding.Converter>

Binding>

Border.CornerRadius>

Border>


Not quite as simple as defining a CornerRadius in a ResourceDictionary, but not bad at all - and certainly it allowed me to do what I wanted - to rationalise my myriad of Radii!

And here's the code:

namespace CheviotConsulting.Common.Silverlight.Converters
{
    using System.Windows;
    using System.Windows.Data;
 
    /// 
    /// Exposes a CornerRadius instance configured for a ValuationProgressButton
    /// 
    public class DynamicCornerRadiusConverter : IValueConverter
    {
        /// 
        /// Gets or sets the top left.
        /// 
        /// The top left.
        public double TopLeft { get; set; }
 
        /// 
        /// Gets or sets the top right.
        /// 
        /// The top right.
        public double TopRight { get; set; }
 
        /// 
        /// Gets or sets the bottom left.
        /// 
        /// The bottom left.
        public double BottomLeft { get; set; }
 
        /// 
        /// Gets or sets the bottom right.
        /// 
        /// The bottom right.
        public double BottomRight { get; set; }
 
        /// 
        /// Gets the corner radius.
        /// 
        /// The resource source.
        /// the corner radius
        private CornerRadius GetCornerRadius(FrameworkElement resourceSource)
        {
            var result = new CornerRadius(this.TopLeft, this.TopRight, this.BottomRight, this.BottomLeft);
            return result;
        }
 
        /// 
        /// Modifies the source data before passing it to the target for display in the UI.
        /// 
        /// The source data being passed to the target.
        /// The  of data expected by the target dependency property.
        /// An optional parameter to be used in the converter logic.
        /// The culture of the conversion.
        /// 
        /// The value to be passed to the target dependency property.
        /// 
        public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return this.GetCornerRadius(value as FrameworkElement);
        }
 
        /// 
        /// Modifies the target data before passing it to the source object.  This method is called only in cref="F:System.Windows.Data.BindingMode.TwoWay"/> bindings.
        /// 
        /// The target data being passed to the source.
        /// The  of data expected by the source object.
        /// An optional parameter to be used in the converter logic.
        /// The culture of the conversion.
        /// 
        /// The value to be passed to the source object.
        /// 
        public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
}

Monday, February 21, 2011

Tricks & Tips: ListBoxes, TextBoxes and SelectedItems

I ran across this today and thought it was worth sharing. The problem is one that's been found in both Silverlight and WPF, but there doesn't seem to be a nice simple solution for either.

The issue involves a control that can accept focus (e.g. a TextBox) being part of the ItemTemplate of a ListBox control. In this scenario, you can select one ListBoxItem by clicking on the whitespace within the ItemTemplate, but when you click on the focusable control (the TextBox) of another ListBoxItem, then the selection does NOT move along with the focus.

The solution is a dinky little behavior that walks up the Visual tree from the TextBox when it gets focus and selects the parent ListBoxItem.

namespace MyProject.Behaviors

{
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;

///
/// Behaviour that allows a control to cause a parent ListBox to become focused.
///

public sealed class ListBoxItemFocusBehaviour : Behavior<Control>
{
///
/// Called after the behaviour is attached to an AssociatedObject.
///

/// Override this to hook up functionality to the AssociatedObject.
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.GotFocus += OnControlFocused;
}

///
/// Called when the behaviour is being detached from its AssociatedObject, but before it has actually occurred.
///

/// Override this to unhook functionality from the AssociatedObject.
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.GotFocus -= OnControlFocused;
}

///
/// Called when [control focused].
///

/// "sender">The sender.
/// "e">The "System.Windows.RoutedEventArgs"/> instance containing the event data.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "By design - p is re-used for multiple control types.")]
private static void OnControlFocused(object sender, RoutedEventArgs e)
{
var control = sender as Control;
DependencyObject p = control;
while (p != null && !(p is ListBoxItem))
{
p = VisualTreeHelper.GetParent(p);
}

if (p == null)
{
return;
}

((ListBoxItem)p).IsSelected = true;
}
}
}

Alll you have to do is attach this behavior to your focusable control and when it receives focus, its associated ListBoxItem gets selected.
                <TextBox x:Name="MyTextBox>

<Interactivity:Interaction.Behaviors>
<Behaviours:ListBoxItemFocusBehaviour />
<Interactivity:Interaction.Behaviors>
TextBox>
Not forgetting of course to register the appropriate namespaces and reference the System.Windows.Interactivity assembly from the Blend SDK.
xmlns:Behaviours="clr-namespace:MyProject.Behaviors;assembly=MyProject" 
xmlns:Interactivity="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Nothing too it!

Friday, November 13, 2009

Friday Quickie: The *other* TemplateBinding syntax

Setting up the template for a new custom control in Silverlight is fraught at the best of times – the Silverlight runtime invariably swallows any error in the template and gives just a cryptic exception.

But stranger still is a limitation on how the {TemplateBinding ...} syntax can be used and the exception that is thrown when in error.

The {TemplateBinding ...} syntax provides a quick and simple way to bind properties within a control’s template to the properties of the control itself. According to the MSDN documentation, it’s a shortcut to the more full-featured {Binding ...} syntax. But what’s not clear from the documentation is that {TemplateBinding ...} can only bind a control property to a DependencyProperty on the control class.

If you try and use {TemplateBinding ...} against a normal property on the control, you get the strange exception shown right – confusing because the target control (WizardActionButton in the example) absolutely does have a State property.

The solution is to use the {Binding ...} syntax where the source property isn’t a DependencyProperty, and to use the {RelativeSource ...} syntax to specify that you’re actually binding to the control within its template.

Wrong:

<i4tControls:WizardActionButton x:Name="RetreatButtonPart"

Style="{StaticResource ActionButtonStyle}"

State="{TemplateBinding CanRetreat}"

Content="{TemplateBinding RetreatButtonContent}"

ContentTemplate="{TemplateBinding RetreatButtonContentTemplate}"

/>

Correct:

<i4tControls:WizardActionButton x:Name="RetreatButtonPart"

Style="{StaticResource ActionButtonStyle}"

State="{Binding Path=CanRetreat,RelativeSource={RelativeSource TemplatedParent}}"

Content="{TemplateBinding RetreatButtonContent}"

ContentTemplate="{TemplateBinding RetreatButtonContentTemplate}"

/>

Wednesday, October 15, 2008

You can't stop the light (redux).

Loads more Silverlight goodness today too.

Robin MestrĂ© has posted no less than four three-part series on why Developers, Designers , Marketing types and Application Architects should look at Silverlight. The posts are very much brochure-style, but they do give an excellent overview of the capabilities of the Silverlight platform – plenty of pictures to help you sell the technology to your managers.

Shawn Burke notes the release of Silverlight 2, but more interestingly give a teaser as to the state of play with the Silverlight Toolkit – due for a first preview release at PDC. The screenshot shows just how cool these controls are going to be.

On the WPF SDK Blog, Jim Galasyn points to the revised Silverlight 2 documentation now available on MSDN.

Finally, Scott Morrison has posted about what I think is one of the most exciting controls released as part of Silverlight 2 RTW – the DataGrid. This control will be making a number of 3rd party control manufacturers sweat – it’s already VERY fully featured, as Scott#’s post shows. In a follow-up, he also shows how to use the Frozen Columns feature – damn handy.

Silverlight Toolkit: http://blogs.msdn.com/sburke/archive/2008/10/14/silverlight-2-released-silverlight-toolkit-on-the-way.aspx

Documentation: http://blogs.msdn.com/wpfsdk/archive/2008/10/14/silverlight-2-docs-are-posted.aspx

DataGrid Features: http://blogs.msdn.com/scmorris/archive/2008/10/14/silverlight-2-datagrid-is-released.aspx

Frozen Columns: http://blogs.msdn.com/scmorris/archive/2008/10/15/freezing-columns-in-the-silverlight-datagrid.aspx

Tuesday, October 14, 2008

You can't stop the light

(was "Busy day at Silverlight Central" - don't ask!)

Yep – today the Microsoft Blogosphere has been buzzing with the news that Silverlight 2.0 has Released to the Web (RTW). Congrats to the Silverlight team on that – I was expecting the release to be closer (if not DURING) the PDC.

Of course ScottGu is the authoritative source as always, but I lost count of the MSDN blog posts today that reposted the news - now all I’ve got to do is un-install the RC0 bits and install the RTW bits before I can compile up code that will be shippable. Well, it will probably be shippable as soon as the CUI and Controls teams update their control libraries!

Interestingly, Ronan Geraghty went in a slightly different direction – pointing to a set of Silverlight tooling for Eclipse. This is good, because it gives an alternative tooling for Silverlight, and one that’s in use by a load of Java developers out there. Whilst it’s Windows only at the moment, it’s roadmap does include support for “Other OS” – so it probably won’t be long before that same tooling will allow for Silverlight / Moonlight development on Linux. Good times!

Scott shows us the light: http://weblogs.asp.net/scottgu/archive/2008/10/14/silverlight-2-released.aspx

Eclipsing the light: http://www.eclipse4sl.org/download/