|
|||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionIn many times, in your Silverlight application, you need download something or do something need a period of time. At this time you may want to display an indicator to indicate the user your application is in busy. So you may want to create such a control can be used in your application. In this article I'll step by step creating a Vista busy cursor like control. Part 1. Cteating a Silverlight AppWhy we first creating a SL application? The reason is the Expression Blend 2 (with SP1) can't directly design the SL control's default template. So we first creating a application using Belend to design the visual of the control. Step 1.1 Creating a Silverlight Application In VS 2008Open Visual Studio 2008, creating a Silverlight application. Right clicking the Page.xaml file, selecting "Open in Expression Blend", the project will be opened with Blend 2. Step 1.2 Designing the Visual of the ControlIn Blend, the Page.xaml already opened. In "Objects and Timeline" panel, select the
Then, selecting a
In "Objects and Timeline" panel, double clicking the
The final
Step 1.3 Creating the VisualStatesNow we creating In "States" panel, click the "Add states group" button add a states group.
Rename the "VisualStateGroup" to "BusyIdleStates". Clicking the "Add State" button in right of the "BusyIdleStates", add two
Selecting the "BusyState" in "States" Panel. Then Opening the Timeline panel and in "Objects and Timeline" panel selecting the
The "Brush Transform" tool and using it.
Move the timeline to "0:00.600", using the "Brush Transform" tool rotating the Brush to 90 degree. Repeat this step until rotating a whole circle. In the end, selecting the Step 1.4 TestingAdding following code to the Page.xaml.cs file. public Page()
{
InitializeComponent();
// add a event handle to Loaded event
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
// Go to BusyState
VisualStateManager.GoToState(this, "BusyState", false);
}
Right clicking the project in VS 2008, selecting "Debug" then "Running a new instance". You will see the effects of the application. Part 2. Creating the ControlStep 2.1 File Structure of Our ControlIn this part, we changing our just created application to a control. So you can easy using this control in any application. First, add a "Silverlight Class Library" project to the current solution, named it "WaitingIcon". Rename the class1.cs to WaitingIcon.cs, also rename the
Selecting the Generic.xaml file and right click it, then selecting the Property menu item. In the Property window, set the Build Action to Resource and delete the text in the Custom Tool box.
Step 2.2 Creating Default Control Template of Our ControlOpening the Generic.xaml file, add following code to the file. <ResourceDictionary xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
xmlns:controls="clr-namespace:Cokkiy.Display">
<Style TargetType="controls:WaitingIcon">
<Setter Property="Template">
<Setter.Value>
<--Control Template for the WaitingIcon-->
<ControlTemplate TargetType="controls:WaitingIcon">
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Opening the Page.xaml file we created in Part1, copy all code between "<Grid>" and "</Grid>" to Generic.xaml file and insert it into after "<ControlTemplate TargetType="controls:WaitingIcon">". <ControlTemplate TargetType="controls:WaitingIcon"> <Grid> <Ellipse StrokeThickness="{TemplateBinding StrokeThickness}" x:Name="ellipse" Stroke="{TemplateBinding Background}" Opacity="0"> </Ellipse> </Grid> </ControlTemplate> In the application, we directly set the <Style TargetType="controls:WaitingIcon">
<Setter Property="StrokeThickness" Value="6"/>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF0A0E94" Offset="0.576"/>
<GradientStop Color="#FF0FFF1B" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
Copy the "VisualStates" define from the Page.xmal to Generic.xaml and insert it into after <Grid>. <Grid>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="BusyIdleStates">
<vsm:VisualState x:Name="BusyState">
<Storyboard AutoReverse="False" RepeatBehavior="Forever">
<PointAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse"
Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.StartPoint)">
<SplinePointKeyFrame KeyTime="00:00:00.25" Value="0.868,0.161"/>
<SplinePointKeyFrame KeyTime="00:00:00.5" Value="0.997,0.44"/>
<SplinePointKeyFrame KeyTime="00:00:00.75" Value="0.845,0.863"/>
<SplinePointKeyFrame KeyTime="00:00:01" Value="0.545,0.999"/>
<SplinePointKeyFrame KeyTime="00:00:01.2500000" Value="0.166,0.873"/>
<SplinePointKeyFrame KeyTime="00:00:01.5" Value="0.001,0.536"/>
<SplinePointKeyFrame KeyTime="00:00:01.7500000" Value="0.084,0.222"/>
<SplinePointKeyFrame KeyTime="00:00:02" Value="0.462,0.001"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="ellipse"
Storyboard.TargetProperty="(Shape.Stroke).(LinearGradientBrush.EndPoint)">
<SplinePointKeyFrame KeyTime="00:00:00.25" Value="0.132,0.839"/>
<SplinePointKeyFrame KeyTime="00:00:00.5" Value="0.003,0.56"/>
<SplinePointKeyFrame KeyTime="00:00:00.75" Value="0.155,0.137"/>
<SplinePointKeyFrame KeyTime="00:00:01" Value="0.455,0.001"/>
<SplinePointKeyFrame KeyTime="00:00:01.2500000" Value="0.834,0.127"/>
<SplinePointKeyFrame KeyTime="00:00:01.5" Value="0.999,0.464"/>
<SplinePointKeyFrame KeyTime="00:00:01.7500000" Value="0.916,0.778"/>
<SplinePointKeyFrame KeyTime="00:00:02" Value="0.538,0.999"/>
</PointAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ellipse"
Storyboard.TargetProperty="Opacity">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="IdleState"/>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
Step 2.3 Creating Code for Our ControlWe just creating file structure and Control Template for our control, now we should add code to it. In the control template we binding the #region StrokeThickness Property
/// <summary>
/// Gets or sets the width of the <see cref="WaitingIcon"/> stroke outline.
/// </summary>
/// <value>The width of the <see cref="WaitingIcon"/> outline, in pixels.
/// The default value is 0. </value>
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
/// <summary>
/// Identifies the <see cref="StrokeThickness"/> dependency property.
/// </summary>
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register("StrokeThickness", typeof(double), typeof(WaitingIcon),
new PropertyMetadata(6.0));
#endregion
The purpose of we creating this control is to indicate the application is busy doing something, so our control should have a property indicating whether in busy or not. #region IsBusy Property
/// <summary>
/// Gets or sets a value indicating is busy or not
/// </summary>
/// <value>A value indicating whether the control is in busy state or not.
/// <para>The default value is <c>false</c>.</para></value>
public bool IsBusy
{
get { return (bool)GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
/// <summary>
/// Identifies the <see cref="IsBusy"/> dependency property.
/// </summary>
public static readonly DependencyProperty IsBusyProperty =
DependencyProperty.Register("IsBusy", typeof(bool),
typeof(WaitingIcon),
new PropertyMetadata(false, IsBusyPropertyChanged));
/// <summary>
/// The <see cref="IsBusy"/> property changed callback function.
/// </summary>
/// <param name="d">The <see cref="WaitingIcon"/> control whosevsee cref="IsBusy"/> property changed.</param>
/// <param name="e">The DependencyPropertyChangedEventArgs contains old and new value.</param>
private static void IsBusyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
WaitingIcon wi = d as WaitingIcon;
wi.IsBusyChanged((bool)e.OldValue, (bool)e.NewValue);
}
#endregion
When the /// <summary>
/// The <see cref="IsBusy "/> property changed.
/// </summary>
/// <param name="oldValue">The old value of the <see cref="IsBusy"/> property.</param>
/// <param name="newValue">The new value of the <see cref="IsBusy"/> property.</param>
protected virtual void IsBusyChanged(bool oldValue, bool newValue)
{
if (newValue)
{
VisualStateManager.GoToState(this, WaitingIcon.BusyStateName, false);
}
else
{
VisualStateManager.GoToState(this, WaitingIcon.IdleStateName, false);
}
}
The final step is apply the default control template to our control. In constructor, set the /// <summary>
/// Initialize a new instance of <see cref="WaitingIcon"/> class.
/// </summary>
public WaitingIcon()
{
// The default style key
this.DefaultStyleKey = typeof(WaitingIcon);
}
/// <summary>
/// Apply new template
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (this.IsBusy)
{
// if set to busy in XAML, we must go to BusyState here
VisualStateManager.GoToState(this, WaitingIcon.BusyStateName, false);
}
}
Compiling the project of we just created, our control ready to use. Part 3. Using the ControlCreate a new Silverlight application, add reference to our control assembly. The in the Page.xaml file, put our control where you want and set a backgroud and storke thickness or just using the default. <UserControl x:Class="WaitingTest.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cdc="clr-namespace:Cokkiy.Display;assembly=Cokkiy.Display.WaitingIcon"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="#FF090808">
<cdc:WaitingIcon Width="20" Height="20" IsBusy="True">
<cdc:WaitingIcon.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF070B9C" Offset="0.57599997520446777"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>
</cdc:WaitingIcon.Background>
</cdc:WaitingIcon>
</Grid>
The Points of InterestYou may notice both in
|
||||||||||||||||||||||||||||||||||||||||