Click here to Skip to main content
15,878,959 members
Articles / Desktop Programming / WPF

WPF Gadget Container Control

Rate me:
Please Sign up or sign in to vote.
4.00/5 (13 votes)
6 Mar 2009CPOL3 min read 73.9K   4.7K   51   14
A Vista-styled gadget container control.

screenshot.jpg

Introduction

I recently had a requirement to create a Gadget-like control, similar to the desktop gadgets found in Vista and Windows 7. After years of lurking on CodeProject (and benefiting), I decided to post my results.

Background

In researching this requirement, CodeProject was my first stop, where I found Josh Smith's excellent article on the DragCanvas (Dragging Elements in a Canvas). Josh provided the foundation of dragging UIElements around on a canvas, so I turned my attention to creating the actual Gadget control.

Using the code

I wanted a fairly generic container control which provided the look and feel and behaviour of a gadget, while allowing me to insert my own content in the form of a UserControl or custom control. After much deliberation, I decided on this control structure:

anatomy.png

  • GadgetContainer – this is the custom control
  • PART_Gadget – this is a ContentControl which is used to host the gadget
  • PART_ControlBarGrid – this is a Grid control used to house gadget controls
  • PART_CloseButton – this is the button used to close or unload a gadget
  • PART_OptionButton – is the button used to provide settings or resizing functionality
  • Grip – provides the gripper bar for dragging the gadget

The SnapCanvas control is a modified version of Josh’s DragCanvas. The main difference is the SnapCanvas sets up “snap regions” running along the left, top, right, and bottom areas of the canvas. When dragging a gadget, if you cross the SnapThreshold (a property on the SnapCanvas which determines whether snapping should occur), the gadget will snap into place.

snapregions.jpg

As you may have guessed, there is a strong relationship between the SnapCanvas and the GadgetContainer. I have included the SnapCanvas in the GadgetLibrary project, as the GadgetContainer is pretty much useless without it.

Because the SnapCanvas does the “snapping”, the GadgetContainer needs to know whether it’s been snapped. This is accomplished by implementing the IGadgetContainer interface:

C#
namespace GadgetLibrary
{
     public interface IGadgetContainer
     {
          SnapRegions SnapRegion { get; set; }
     }
}

When the SnapCanvas snaps a gadget, it sets the SnapRegion property on the control. This is needed when the SnapCanvas is resized...

C#
private void SnapCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
{
     SetSnapRectanges(e.NewSize);
     RelocateSnappedContainers();
}

SetSnapRectangles recalculates the snap regions based on the new size of the canvas. RelocateShappedContainers cycles through the children looking for IGadgetContainers that have been snapped, and relocates them accordingly.

The GadgetPrototype project includes a basic demonstration of how to use and wire-up the GadgetContainer. The sample gadgets included are useless and simply illustrate use.

In the Window1.xaml file, you will find:

XML
<GadgetLibrary:SnapCanvas x:Name="_SnapCanvas"
    Grid.Row="1"
    AllowDragging="True"
    SnapThreshold="20"
    AllowDragOutOfView="False">
</GadgetLibrary:SnapCanvas>

SnapThreshold is set to 20 pixels, which feels right to me. The menu handler for the Add Gadget | Weather menu item looks like this:

C#
private void _AddWeatherGadget_Click(object sender, RoutedEventArgs e)
{
    var gadgetContainer = new GadgetContainer();
    Canvas.SetTop(gadgetContainer, 100);
    Canvas.SetLeft(gadgetContainer, 100);
    gadgetContainer.OptionButtonType = OptionButtonTypes.Settings;
    gadgetContainer.Close += OnGadgetClose;
    var weatherGadget = new WeatherGadget();
    gadgetContainer.Gadget = weatherGadget;
   _SnapCanvas.Children.Add(gadgetContainer);
}

So, we create a new GadgetContainer, set its Top and Left properties, set the OptionButtonType to OptionButtonTypes.Settings (Settings, Resize, and Other), create an event handler for the Close event and then, set the Gadget property to the WeatherGadget UserControl. And lastly, add it to the SnapCanvas' Children collection.

Responding to the OptionButton Click event

Just below the Close button in the ControlBar is the OptionButton. The OptionButton can serve different purposes depending on your gadget. Most commonly, it is used to launch a settings dialog window; in Windows 7, it can also resize or enlarge the gadget.

I wanted the gadget itself to respond to this event. I ended up doing this through the IGadget interface, which is implemented by the gadget.

C#
public interface IGadget
{
    void OnShowOptions(OptionButtonTypes type);
}

When the OptionButton is clicked, the GadgetContainer will call the OnShowOptions method of the gadget.

In WeatherGadget.cs, we find:

C#
public void OnShowOptions(OptionButtonTypes type)
{
    if(type.Equals(OptionButtonTypes.Settings))
    {
        WeatherGadgetSettings settings = new WeatherGadgetSettings();
        settings.Show();
    }
}

which displays a settings window for the gadget. The PictureGadget uses the Resize option, and very crudely resizes its contents in response to this event.

Points of interest

I think that’s pretty much all I have to say about this. I hope someone finds some use for it. As always with WPF, I’m sure there are better, more efficient ways of skinning this cat. Any and all comments/questions welcome.

More info

History

  • Version 1.0 posted on 6 March 2009.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I'm a software developer living in Northampton, UK, and enjoy working with the latest .Net technologies.

Comments and Discussions

 
QuestionCan gadget snap each other ? Pin
Cyril03515-Jun-16 10:27
Cyril03515-Jun-16 10:27 
GeneralMy vote of 5 Pin
Simon Raffl23-Jan-13 2:28
Simon Raffl23-Jan-13 2:28 
QuestionHi Pin
Member 426405528-Mar-12 11:56
Member 426405528-Mar-12 11:56 
AnswerRe: Hi Pin
Ron Gramann29-Mar-12 12:54
Ron Gramann29-Mar-12 12:54 
GeneralRe: Hi Pin
Member 42640553-Apr-12 16:52
Member 42640553-Apr-12 16:52 
GeneralRe: Hi Pin
Ron Gramann4-Apr-12 8:06
Ron Gramann4-Apr-12 8:06 
QuestionI have the following error when moving an item thru the canvas ... Pin
s0m0s20-Sep-11 22:14
s0m0s20-Sep-11 22:14 
Generalprevent minimizing the gadget [modified] Pin
Padmanabh Ganorkar12-Aug-10 12:19
Padmanabh Ganorkar12-Aug-10 12:19 
GeneralRe: prevent minimizing the gadget Pin
Ron Gramann17-Aug-10 21:50
Ron Gramann17-Aug-10 21:50 
Generalnot a bad job, though it would be better if you had Pin
Sacha Barber6-Mar-09 21:04
Sacha Barber6-Mar-09 21:04 
GeneralRe: not a bad job, though it would be better if you had Pin
Ron Gramann7-Mar-09 0:03
Ron Gramann7-Mar-09 0:03 
Hi Sacha,
Yeah, didn't need to go there. This client simply wanted gadget-like functionality within their business application. I don't know if true Vista gadgets can be hosted and run in another environment.
GeneralRe: not a bad job, though it would be better if you had Pin
Sacha Barber7-Mar-09 0:50
Sacha Barber7-Mar-09 0:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.