Second Stanza

May 2, 2009

Silverlight Color Picker Control

Filed under: Silverlight — Tags: — dfbaskin @ 2:21 pm

I’m not sure why a color picker was not included in Silverlight since it seems like such a common control. However, I needed one so I took a look at my options. Plenty of examples exist so I decided to take the work started by Page Brooks (here, here, and here) and incorporate the Modal Popup functionality.

I ended up with a PopupColorPicker control. Here’s a picture of it in all of its popped-up glory:

Popup Color Picker Control

This control uses the Hue/Saturation/Value color space to translate colors to and from RGB values (through the HSVColor structure that is similar to the Color structure). The control also includes selecting a value for the opacity.

The control initially displays a color display box/button, which opens the Popup panel to select the color, and a text box, which a user can enter in an ARGB value directly. When the user clicks the color display button, the Popup panel is displayed (as shown above). On the left the user selects the hue, in the middle the saturation and value, and on the right the opacity.

The source code can be downloaded from CodePlex.

Hope this is useful!

Silverlight Modal Popup

Filed under: Silverlight — Tags: — dfbaskin @ 1:18 pm

The Popup control in Silverlight is not, as you might think, like a modal dialog box where other portions of the application are disabled while the dialog is displayed. It is more like an overlay where the contents of the Popup control are displayed on top of everything else in the control. However, lower level controls are still active.

If you need something more like a modal dialog box, you can simulate this in Silverlight by including a rectangle in your Popup that spans over the entire display area of the control.

I’ve taken this idea and encapsulated it into a ModalPopup control. The control can be used similarly to the Popup control, such as in the following example:

<stz:AutoSizeUserControl x:Class="Demo.ModalPopupDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:stz="clr-namespace:Stanza.Silverlight.Controls;assembly=Stanza.Silverlight.Controls" Width="800" Height="600" MinWidth="300" MinHeight="200" ExtraHeight="140" ExtraWidth="20" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
	<Grid x:Name="LayoutRoot" Background="White">
		<Grid>
			<Rectangle Stroke="#FF0000FF" RadiusX="32" RadiusY="32" StrokeThickness="2">
				<Rectangle.Fill>
					<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
						<GradientStop Color="#FF000000"/>
						<GradientStop Color="#FFFFFFFF" Offset="1"/>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
				<Button Width="140" Height="26" x:Name="showDefaultBtn" Content="Show (Fixed)"/>
				<Button Width="140" Height="26" x:Name="showRelativeBtn" Content="Show (Relative)"/>
				<Button Width="80" Height="26" x:Name="showFullScreen" Content="Full Screen"/>
			</StackPanel>
		</Grid>
		<stz:ModalPopup x:Name="popupPanel" Height="200" Width="220" BackgroundOpacity="0.25" BackgroundFill="Green" Left="200" Top="100" d:IsHidden="True">
            <Border x:Name="popupPanelGrid" BorderThickness="4,4,4,4" Background="Green" BorderBrush="Red" Width="220" Height="200">
				<Grid>
					<Grid.RowDefinitions>
						<RowDefinition/>
						<RowDefinition/>
					</Grid.RowDefinitions>
					<Grid.ColumnDefinitions>
						<ColumnDefinition/>
						<ColumnDefinition/>
					</Grid.ColumnDefinitions>
					<Ellipse Margin="10" Grid.RowSpan="2" Grid.ColumnSpan="2">
						<Ellipse.Fill>
							<RadialGradientBrush GradientOrigin="0.25,0.25">
								<GradientStop Offset="0.25" Color="White" />
								<GradientStop Offset="1.0" Color="Red" />
							</RadialGradientBrush>
						</Ellipse.Fill>
					</Ellipse>
					<Button Width="70" Height="26" x:Name="closeBtn" Content="Close" Grid.Row="1" Grid.Column="1"/>
				</Grid>
            </Border>
		</stz:ModalPopup>
	</Grid>
</stz:AutoSizeUserControl>

The popup panel itself can be opened and closed using code like:

...
    showRelativeBtn.Click += new RoutedEventHandler( showRelativeBtn_Click );
    closeBtn.Click += new RoutedEventHandler( closeBtn_Click );
...

    void showRelativeBtn_Click( object sender, RoutedEventArgs e )
    {
        Point pt = showRelativeBtn.GetAbsolutePosition();
        pt.X += showRelativeBtn.Width / 2;
        pt.Y += showRelativeBtn.Height / 2;
        popupPanel.OpenPopup( pt );
    }

    void closeBtn_Click( object sender, RoutedEventArgs e )
    {
        popupPanel.ClosePopup();
    }

The GetAbsolutePosition() method is an extension method that allows you to get the position of the UIElement object relative to the entire Silverlight display area.

The source code can be downloaded from CodePlex.

Resizing a Silverlight Control within the Browser

Filed under: Silverlight — Tags: — dfbaskin @ 12:27 pm

A common user interface technique in a web page is to expand the contents of the page to the size of the browser window. There are solutions for doing this in both CSS or Javascript. A Silverlight control may also be resized in this way and since a Silverlight control can access the Browser’s DOM (unless permission is explicitly denied), resizing can be handled within the control itself.

To do so, the control will need to be notified of the browser’s OnResize event, which can be attached using the following code:

...
HtmlPage.Window.AttachEvent( "onresize", new EventHandler<HtmlEventArgs>( BrowserWindow_Resized ) );
...

void BrowserWindow_Resized( object sender, HtmlEventArgs e )
{
    AdjustControlSize();
}

Then, you can determine the new size of the browser window using a technique similar to what might be used in Javascript:

        public static bool IsIECSSCompatibleMode
        {
            get
            {
                bool isCompatibleMode = false;
                string mode = HtmlPage.Document.GetProperty( "compatMode" ) as String;
                if( ( mode != null ) && ( String.Compare( mode, 0, "CSS1", 0, 4, StringComparison.InvariantCultureIgnoreCase ) == 0 ) )
                    isCompatibleMode = true;
                return isCompatibleMode;
            }
        }

        public static double BrowserWindowWidth
        {
            get
            {
                object w = HtmlPage.Window.GetProperty( "innerWidth" );
                if( w != null )
                    return Convert.ToDouble( w );
                else if( IsIECSSCompatibleMode )
                {
                    w = HtmlPage.Document.Body.Parent.GetProperty( "clientWidth" );
                    if( w != null )
                        return Convert.ToDouble( w );
                }
                else
                {
                    w = HtmlPage.Document.Body.GetProperty( "clientWidth" );
                    if( w != null )
                        return Convert.ToDouble( w );
                }
                return double.NaN;
            }
        }

        public static double BrowserWindowHeight
        {
            get
            {
                object h = HtmlPage.Window.GetProperty( "innerHeight" );
                if( h != null )
                    return Convert.ToDouble( h );
                else if( IsIECSSCompatibleMode )
                {
                    h = HtmlPage.Document.Body.Parent.GetProperty( "clientHeight" );
                    if( h != null )
                        return Convert.ToDouble( h );
                }
                else
                {
                    h = HtmlPage.Document.Body.GetProperty( "clientHeight" );
                    if( h != null )
                        return Convert.ToDouble( h );
                }
                return double.NaN;
            }
        }

I’ve encapsulated this technique into a Silverlight control called AutoSizeUserControl. This control is derived from the standard UserControl and automatically resizes itself based on changes to the size of the browser window. It can be used simply as a replacment for the UserControl:

<stz:AutoSizeUserControl x:Class="Demo.AutoSizeDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:stz="clr-namespace:Stanza.Silverlight.Controls;assembly=Stanza.Silverlight.Controls" Width="800" Height="600" MinWidth="300" MinHeight="200" ExtraHeight="164" ExtraWidth="20">
    <Grid x:Name="LayoutRoot" Background="White">
		<Rectangle Stroke="#FF000000" RadiusX="16" RadiusY="16" StrokeThickness="4" >
			<Rectangle.Fill>
				<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
					<GradientStop Color="#FF000000"/>
					<GradientStop Color="#FFFFFFFF" Offset="1"/>
				</LinearGradientBrush>
			</Rectangle.Fill>
		</Rectangle>
		<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Width="250" Height="120">
			<Grid.RowDefinitions>
				<RowDefinition/>
				<RowDefinition/>
				<RowDefinition/>
				<RowDefinition/>
			</Grid.RowDefinitions>
			<Grid.ColumnDefinitions>
				<ColumnDefinition/>
				<ColumnDefinition/>
				<ColumnDefinition/>
				<ColumnDefinition/>
			</Grid.ColumnDefinitions>
			
			<TextBlock Text="Browser Window" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.ColumnSpan="2"/>
			<TextBlock Text="Width:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
			<TextBox Text="0" x:Name="browserWidthBox" Grid.Column="1" IsReadOnly="True" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="40"/>
			<TextBlock HorizontalAlignment="Center" Text="Height:" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"/>
			<TextBox Text="0" x:Name="browserHeightBox" Grid.Column="1" Grid.Row="2" IsReadOnly="True" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="40"/>
			
			<TextBlock Text="Silverlight Control" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.ColumnSpan="2"/>
			<TextBlock Text="Width:" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
			<TextBox Text="0" x:Name="controlWidthBox" Grid.Column="3" IsReadOnly="True" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="40"/>
			<TextBlock HorizontalAlignment="Center" Text="Height:" Grid.Row="2" Grid.Column="2" VerticalAlignment="Center"/>
			<TextBox Text="0" x:Name="controlHeightBox" Grid.Column="3" Grid.Row="2" IsReadOnly="True" HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="40"/>
			
			<Button Grid.Row="3" Content="Full Screen" Grid.ColumnSpan="2" Grid.Column="1" Width="80" Height="24" x:Name="fullScreenButton"/>
			
		</Grid>
    </Grid>
</stz:AutoSizeUserControl>

Source code can be downloaded from CodePlex.

Second Stanza Source Code Repository

Filed under: .NET Development, Silverlight — dfbaskin @ 11:46 am

I’ve created a project on CodePlex to store the source code I’ve publish within this blog. The project is located at secondstanza.codeplex.com. The first set of source code is a set of useful Silverlight controls. Enjoy!

Blog at WordPress.com.