Page view counter

January 2009 - Posts

The Tree View Control

 

 

The Tree View control is ideal for displaying hierarchical data. While there is a great deal you can do with this control, in its simplest form it is fairly straightforward to work with, once you grok the essential recursiveness it demands (well, requests strongly).

We'll look at two examples: the TreeView raw, and then using DataBinding with a tiny bit of customization. Here's what we're building:

--- Top of Streaming Application ---

--- End of Streaming Application ---

Everything that follows is based on the work of Stephen R Strong who contributed his efforts in support of this blog, and whose work is very much appreciated.

To create the application shown above, we need to a hierarchical data source and we need a pair of treeview controls.

The easiest way to obtain the data is to just create it in memory (though of course, your source might be an xml file, retrieved from a database, etc.).

Hierarchical Data

The Data class I created for this example is defined like this:

public class Data
{
   public string Name { get; set; }
   public Data Parent { get; set; }
   public List<Data> Children;
   public int Depth  { get { return Parent == null ? 0 : Parent.Depth +1; } }
   

I opted to provide a default constructor, though it does so little, I could have let the compiler create one for me. The CreateChild method adds a new child to the current Data object.

public Data()
{
   Name=string.Empty;
   Parent = null;
   Children = new List<Data>();
}

public Data CreateChild( string name )
{
   Data child = new Data() { Name = name, Parent = this};
   Children.Add(child);
   return child;
}

Finally, the Data class provides a static method that returns a hierarchical collection of information about the United States,

public static Data CreateDataSample()
{
   Data root = new Data() { Name = "United States" };
   Data states = root.CreateChild( "States" );
   states.CreateChild( "Alabama" ).CreateChild( "Montgomery" );
   states.CreateChild( "Alaska" ).CreateChild( "Juneau" );
   states.CreateChild( "Arizona" ).CreateChild( "Phoenix" );
   states.CreateChild( "Arkansas" ).CreateChild( "Little Rock" );
   Data presidents = root.CreateChild( "Presidents" );
   Data W = presidents.CreateChild( "Washington" );
   Data WTerm = W.CreateChild( "Took office" );
   WTerm.CreateChild( "1789" );
   WTerm.CreateChild( "1793" );
   Data A = presidents.CreateChild( "Adams" ).CreateChild( "Took office" ).CreateChild( "1797" );
   Data J = presidents.CreateChild( "Jefferson" );
   Data JTerm = J.CreateChild( "Took office" );
   JTerm.CreateChild( "1801" );
   JTerm.CreateChild( "1805" );
   return root;
}

Note that CreateChild returns a Data object, and we take advantage of that in the third line where we create a Child of states whose Name field is Alabama, and then give that Data object a child whose name field is Montgomery (the capital of Alabama).

Ultimately, we return just the root Data object; but the structure we've created looks like this:

USOutline 

Here's the complete Xaml for the page that displays this data,

<UserControl x:Class="TreeView.TreeViewPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:control="clr-namespace:Microsoft.Windows.Controls;
assembly=Microsoft.Windows.Controls" Width="600" Height="600"> <Grid x:Name="LayoutRoot" Background="White"> <control:TreeView x:Name="LeftTreeView" HorizontalAlignment="Left" Background="Wheat" /> <control:TreeView x:Name="RightTreeView" HorizontalAlignment="Right" Background="Beige" /> </Grid> </UserControl>

The interesting work, of course, is done in the code behind.  L

public partial class TreeViewPage : UserControl
{
   public TreeViewPage()
   {
      InitializeComponent();
      Data root = Data.CreateDataSample();
      FillTree( LeftTreeView.Items, root );
      FillBoundTree( RightTreeView.Items, root );
   }

Recursion

After the call to InitializeComponent we call our static method that returns the root node (United States) which is pregnant with the entire data structure. We pass two arguments to a private helper method named FillTree:

  1. The Items Collection of the TreeView control declared in the Xaml
  2. The Data instance that serves as the root of the tree

The helper method is created to provide a place for recursion, because the process of adding nodes to the tree is (almost) inherently recursive.

I wrote almost inherently recursive because of course you can do this without recursion, even without data binding, but there are some things that just lend themselves to recursion and this is surely one.
 private void FillTree( ItemCollection itemColl, Data dataNode )
 {
    TreeViewItem tvi = new TreeViewItem();
    itemColl.Add( tvi );
    tvi.Header = dataNode.Name;
    //….

FillTree creates an instance of a TreeViewItem (a node in a TreeView) and adds it to the collection that is passed in (in this first case, to the items collection of the TreeView control).

It then sets the tree view item's header property to the Name property of the Data object it received.  At this point we can conceive of things as looking like this:

TreeViewFirstStep

It is important to note that the TreeViewItem does not hold a copy of the Data object, but rather the Header property of the TreeViewItem gets its string from the DataObject.

The FillTree method then iterates through each child in the current Data object's Children property (which you will remember is a List<Data>.

    foreach ( Data childDataNode in dataNode.Children )
    {
       FillTree( tvi.Items, childDataNode ); // dang. dang. (curse, recurse)
    }
 }  // end method

For each child it finds, it recurses, passing in the Items collection of the new TreeView Item and, one by one, the children of the current Data object,

Recurse

Thus, the first time the method recurses, the parameters are now the Items collection of the TreeViewItem whose header is United States, and the Data object States.

In this way each data object's name is added to a TreeViewItem in the appropriate "level" of the tree.

Final line of the constructor of TreeViewPage calls FillBoundTree

public TreeViewPage()
{
   InitializeComponent();
   Data root = Data.CreateDataSample();
   FillTree( LeftTreeView.Items, root );
   FillBoundTree( RightTreeView.Items, root );
}

 

Data Binding

This second method looks a lot like FillTree but works quite differently.

private void FillBoundTree( ItemCollection itemColl, Data dataNode )
{
   TreeViewItem tvi = new TreeViewItem();
   itemColl.Add( tvi );
   tvi.DataContext = dataNode;
   tvi.Header = new TreeViewNode();
   foreach ( Data childDataNode in dataNode.Children )
   {
      FillBoundTree( tvi.Items, childDataNode ); 
   }
}

The key is found in the two lines I've shown in red.  In this case, rather than copying the text of the Name field to the Header, we set the DataContext (which signals right away that we're doing some kind of data binding) and we set the Header to an instance of a TreeViewNode.

TreeViewNode is a user control. Here is the complete Xaml for TreeViewNode,

<UserControl x:Class="TreeView.TreeViewNode"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="300" >
    <Grid x:Name="LayoutRoot" Background="Bisque">
    <Border BorderBrush="Black"
            BorderThickness="4">
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Name}"
                   Margin="3" />
        <TextBlock Text="{Binding Depth}"
                   Margin="3"/>
      </StackPanel>
    </Border>
  </Grid>
</UserControl>

(No work is done in TreeViewNode.cs)

You can see that the heart of this user control is a pair of TextBlock objects, one of which is bound to the Name property and the other to the Depth property of the Data object. As each Data object is passed in to the FillBoundTree method it serves as the DataContext from which these properties are extracted.


This work is licensed under a Creative Commons Attribution By license.

Toolkit: Header Controls Video Posted

Navigate to previous blog entry


MORE Blog entry on HeaderContentControl

I'm happy to say that my latest video on the Silverlight Toolkit, covering the HeaderContentControl and the HeaderItemsControl is now available for download.

HeaderContentControl


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | 2 comment(s)
Filed under: ,

How Do I Video Series on Hyper-video released



 


HyperVideo3aI'm pleased to say that the third and final part of my series on Hyper-video is now available (just click on the image or click here).

In this last video I demonstrate how to respond to embedded markers by displaying a button and, if you click on the button by pausing the playing video and starting up a related video.

 

More: Start of thread on hyper-video 
(Note: This link jumps to the start of the thread rather than the most recent entry)

 


This work is licensed under a Creative Commons Attribution By license.

Why I'm Going To MIX

I confess, if I didn’t work for Microsoft I probably would go to fewer conferences than most folks.  I never did well in school, I just don’t learn well in classrooms, and while the networking in the hallways is incredibly valuable, the overall cost that I was paying as an independent was high.  So I picked carefully; especially in hard times.

Mixes But MIX is different, and more so if you are interested in RIA and Silverlight. 

While PDC is a great place to see where Microsoft is going and TechEd is fantastic for deep technical information, Mix could almost be renamed “Silverlight Neonatal Unit” (though I admit I may have a skewed perception). 

It was at MIX07 that I switched from being a general .NET  programmer to being a Silverlight Programmer (before joining Microsoft) and it was at MIX08 that we revealed Silverlight 2, a upgrade that I thought was about as big as that from Win 3.1 to Windows 95.

Now, without saying anything out of school, let's put together just two public facts:

  • On November 16, Scott Guthrie posted a glimpse of Silverlight 3 indicating it will ship in 2009.
  • On Jan 14 the Mix 09 site posted a page called Silverlight 3 Sessions including
    • What's new in Silverlight 3
    • What's new in Silverlight 3 Media
    • Deep Dive into Silverlight 3 Graphics

So it is fair to speculate that Silverlight 3 will play an important role in this year's Mix. And that is pretty exciting news indeed.

I'll say more as soon as I can, but what I will say right now is this: I'm at least as excited about Silverlight 3 as I was about Silverlight 2.

{ Update – There is a $400 discount until Feb 13 and be sure to check out the MIX site for details about keynote speakers, the agenda and the new Mix Online pages. Also be sure to signup for MIX's Twitter feed and keep an eye on the MIX tweme [1] }

[1] See Meme


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | 3 comment(s)
Filed under: ,

Report From MDC – NY & Boston

I had a blast speaking at the MSDN Developer’s Conference (MDC) in both NY (January 20) and Boston (January 22). 

Each was a total blast and as promised, here are the links from that presentation.

 

Okay, favorite thing to geek out on: the elevators in the hotel: you push the button on a panel and it instantly lights up with a letter of the alphabet: that is your elevator, whose doors are open by the time you get there. Step in and off you go. No buttons inside, straight to your chosen floor. Zow!

.NET Rocks & RIA Panel

.NETRocksCodeMashAs promised, here is the  .NET Rocks recorded panel on RIA at Code Mash. It was a blast and got a great reception.

Participants in the panel included myself, Carl and Richard, Josh Holmes (Microsoft RIA Architect Evangelist), Leon Gersing (Teligent), and James Ward (Flex Tech.  Evangelist).

Takes a few minutes to get going, but then it gets quite interesting.

 

 

Previous Article


More: Report on CodeMash 2009


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | 2 comment(s)
Filed under: ,

The Header Content Control

 

This quick introduction to the HeaderContentControl of the Silverlight Toolkit will lay the ground work for future entries on the Expander control.

To see the HeaderContentControl with as little fuss as possible, create a new Silverlight application and add a reference to the Microsoft.Windows.Controls.dll from the toolkit.

Page.xaml

 

Begin by adding a reference to the Microsoft.Windows.Controls.dll to your application and then declare an XML Name Space at the top of Page.xaml,

xmlns:control="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls" 

The HeaderControl consists of two parts: the header part and the contents part,

<Grid x:Name="LayoutRoot" Background="White">

<control:HeaderedContentControl 
x:Name="SimpleHeaderContent" Grid.Row="0"> <control:HeaderedContentControl.Header> <TextBlock x:Name="HeaderContentControlHeader" Text="Header for simple Header Content Control" FontSize="16" FontFamily="Georgia" FontWeight="Bold" /> </control:HeaderedContentControl.Header> <control:HeaderedContentControl.Content> <TextBlock x:Name="Message" Text="Content for the content control." TextWrapping="Wrap" FontFamily="Comic Sans MS" FontSize="24" Margin="10" /> </control:HeaderedContentControl.Content> </control:HeaderedContentControl> </Grid>

In the code shown above we are using text for both the header and the content portions,

HeaderInFF

Not Just Text

An interesting thing happens if you put a page with a  HeaderContentControl into Expression Blend, and then template the control…

ContentPresenters

The control consists of a pair of ContentPresenter objects within a stack panel.  If, however, the Header (e.g.,) is a ContentPresenter, then it is in no way restricted to text. 

(Close Blend and don't save the changes)

Let's add an image to Page.xaml's directory and then make that image a compiled resource by adding it to the project

AddExisting

Make sure the Build Action (in the properties window) is set to Resource,

BuildAction

 

Now we can return to Page.xaml and remove the text and substitute the Image,

<control:HeaderedContentControl.Header>
   <!--   <TextBlock x:Name="HeaderContentControlHeader"
             Text="Header for simple Header Content Control"
             FontSize="16"
             FontFamily="Georgia"
             FontWeight="Bold" /> -->
  
  <Image Source="LogoSmall.jpg"
         Stretch="UniformToFill"
         VerticalAlignment="Stretch"
         HorizontalAlignment="Stretch"
         MaxHeight="100"
         MaxWidth="100" /> 
</control:HeaderedContentControl.Header>
The result is immediately obvious,
ContentControlHeaderlWithImage 

 

The HeaderContentControl makes a powerful building block, especially when combined with, e.g., the Expander, as we'll see very soon.

 

 


MORE Header Controls Video


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | 8 comment(s)
Filed under: , ,

Hyper-video videos posted

I'm very pleased to say that the first two of the four-part series of videos on HyperVideo are now available (clicking on the images will bring you to the videos)

Links to Part 1

Links to Part 2

You can also find a blog thread on Hypervideo beginning here.  If you find it interesting, just follow the arrows at the end of each article.

Thanks.


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | 1 comment(s)
Filed under: ,

Outlook on my PC and Phone and Keeping Organized

This message has nothing to do with Silverlight  Feel free to skip it.

I have been struggling since I joined Microsoft to ensure that

  • I don't miss any messages that are important
  • I spend less time managing my 600+ daily emails *
  • I file everything away in case I need it later
  • I can find things quickly

(* I archive frequently, and read feverishly, but a quick search found 2300 unread emails as I wrote this).

This is made much more complicated because I look at my email through three views: on my desktop, via the web (rare) and via my phone (frequent).  Set aside the web; when I'm looking via my desktop I don't mind if new messages show up in a folder, and folders help keep me organized.

FuzeMy new phone is the AT&T Fuze which I'm coming to love.  but like the Dash before it, it is designed  to strongly favor the inbox. It will synchronize with any folders I want, but the tilt towards the inbox is strong enough that messages elsewhere are easy to miss.

 

 



(NB: I don't use the "touch flow" interface shown here)

 

 

Solving All My Outlook Issues At Once

I have tried various solutions, but I've finally hit on one I really like, and I thought I'd write it up briefly in case it might simplify your life.  The key, or me, is to

  1. make sure that everything I care to see goes to my inbox
  2. I don't have to file (nearly) anything
  3. Things I don't need to see do not go to my inbox.

This is all accomplished with a couple very simple rules.  First, I created a category called "Filed"  Then, for nearly every person or group that I care to see, I created a rule that told Outlook to make a copy of the message and file it on arrival and to mark the original (in the inbox) as in the category filed.  Thus, when looking at my inbox, I see this:

Filed 

As you can see, all but one of the messages is already marked filed. I can then tick through the messages, deleting them as I read them, knowing that they are already filed away where I want them.

(I could use different categories rather than just "filed" to indicate where they are filed, but since I have a couple hundred folders that would get tricky).

Most important, since all the messages now go to the inbox (and are not "moved" by a rule but rather copied) I know I'm seeing them on the phone.

Here are my basic rules:

Anything I want to see:

Rule1

Anything I want to file but don't want to see

rule2

Outlook

Posted by jesseliberty | with no comments
Filed under: ,

Report on CodeMash 2009

CodeMashLogo This year I had the incredible pleasure of speaking at CodeMash 2009 (last year I missed it by breaking my glenoid just before going. This was better).

The organizers asked for feedback, and I realized that my feedback (slightly edited) made for a reasonable field report as well.  Here it is…

You can find the complete program for this conference here.

 

About Your Sessions


I had two sessions. The first was on Hypervideo. Unfortunately, despite having rehearsed just hours before, a critical piece of software fell off my computer and wasn’t there when needed. Fortunately,  John Stockton was there with just what I needed, and I had the presentation backed up on thumb drive (and, for that matter, my entire disk backed up as well just in case), so only 10 minutes was lost.

The presentation went well, I thought, and the Q&A was good. I did get one flame later on Twitter, but a follow-up email to the writer produced a terrific exchange and he was quite gracious and had good suggestions.

The second session was on Templating controls and (a) it should have come before the first and (b) I should have realized the wide variety of experience in the room and chosen a topic that assumed less familiarity with Silverlight. That said, it went well and people were into it and asked good probing questions.

Who did you have great conversations with?

More people than I have had with at any similar conference. Truly excellent conversations with very motivated, very interesting and very bright programmers.  That was great.   I talked to about 2 dozen people at length and another dozen briefly. Could have been more but I spent a lot of time sleeping and rehearsing.  Great atmosphere, lots of fun but very serious about the technology. It was a blast.

What value did you get out of being at CodeMash?

A bit of a  breakthrough in my role as a Technical Evangelist, defined by me as a techie (coder/ developer) who is sufficiently excited about a technology that I want to talk about it, share it, show it, and teach it. I’d been fighting that role a bit, and many things at CodeMash contributed to my embracing it.

What did you get out of the Ask The Experts panel?

It was a blast.  The .NET Rocks guys do and the panel was an opportunity to listen to a  different perspective and see clearly how much sense it made in its context.  I hope to follow up with James Ward and maintain contact. Great guy, very smart. 

Plus, every time I come within 6 meters of Josh Holmes I learn something about how to do my job. 

Must mention that Jim Holmes has an incredible knack for making everything easy. 

A great time, hope I get to go again.

 

Next Article


More: .NET Rocks RIA Panel


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | 3 comment(s)
Filed under:

Help Wanted

I have some ideas about improving this blog that will require going through past messages and adding forward/backward references and FAQ indicators and more.  If you are willing to work for "recognition" and eternal gratitude, please send email to jliberty@microsoft.com  with Blog Slog in the subject line!  Thanks.

Wow! What a response!  Thank you all; I have so many volunteers I hardly know what to do.  Can't thank you all enough.

 

-jesse

Silverlight

Posted by jesseliberty | 2 comment(s)
Filed under:

Drag and Drop with Managed Code

 

The last time I looked at Drag and Drop was with Silverlight version 1 and now seemed like a good time to see how one might accomplish this seemingly straight forward task with managed code.

The experience was interesting. Once I had it working, it was hard to explain why it had been difficult, though it did seem that the documentation took you right up to what you needed to know and then stopped short. I'm not certain that is true, but I know I struggled longer than I expected to.  In any case, now that it is working, it is easy to demonstrate.

This blog entry will make short work of it. To keep things simple, we'll just draw a circle and a square and drag them around the surface of the larger canvas (we'll use canvas because it uses absolute positioning which makes positioning the shape much easier). I've added color to the canvas so you can see where its boundaries are.

DragAndDropRunning
(Composite image of dragging circle)

  
The Xaml file is very simple,

<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="DragDrop.Page"
Width="800"
Height="600"
HorizontalAlignment="Left"
VerticalAlignment="Top">
<Canvas Background="AntiqueWhite">
<Ellipse
x:Name="Circle"
Height="150"
Width="150"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Fill="#FFFFFF00"
Stroke="#FF000000"
Canvas.Left="10"
Canvas.Top="25" />

<Rectangle
x:Name="Square"
Height="100"
Width="100"
Canvas.Left="200"
Canvas.Top="50"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Fill="Red"
Stroke="Black"
StrokeThickness="1"
Opacity="0.75" />
</Canvas>
</UserControl>

The Supporting Code

All of the code for this example is in Page.xaml.cs.  We want to implement three event handlers for each shape:

  1. MouseLeftButtonDown – the user has started to drag
  2. MouseMove – the user is dragging
  3. MouseLeftButtonUp – the user has stopped dragging

The key to understanding how this works is that these events are fired by the shapes themselves, not by the mouse or the canvas. Once that is clear, the rest follows naturally.

To make for easier-to-maintain code, we'll share event handlers between the Square and the Circle.

public partial class Page : UserControl
{




// are we currently tracking the mouse?
private bool isTracking = false;
  // constructor
public Page()
{
InitializeComponent();

Circle.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );
Square.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );

Circle.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );
Square.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );

Circle.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
Square.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
}

 

MouseLeftButtonDown

Clicking the left mouse button acts as a signal to begin dragging. We'll set the member flag to indicate that we are tracking, and then we'll want to set a few properties on the shape.

Unfortunately, we have only the sender (type object) and the MouseButtonEventArgs OriginalSource property (also of type object). This is not a problem, however, as we know that any object firing this event is of type shape, so we are safe to cast accordingly,

void Shape_MouseLeftButtonDown( 
object sender,
MouseButtonEventArgs e )
{
isTracking = true;
Shape s = e.OriginalSource as Shape;


// For robust code, you should test that s is not null

With a reference to the shape, you can now set the opacity to half its current value. We won't set it to a fixed value (e.g., 0.5) as that would break any shape whose initial opacity is not 1 (such as our square!).

s.Opacity *= 0.5;

(We'll restore this later by doubling the value, returning it to whatever it was, without the need to cache the original value)

When the user is dragging, it is possible that the mouse will move off the shape which will cause the MouseMove event to stop firing (the technical term for this is "bad"). To prevent that, we'll capture the mouse:

s.CaptureMouse();

MouseMove

Each time the user moves the mouse a MouseMove event is fired. We test for whether we are tracking the mouse (the IsTracking private member variable is set in ButtonDown and cleared in ButtonUp) and if so we get the current position of the mouse from the MouseEventArgs,

void Shape_MouseMove( object sender, MouseEventArgs e )
{
if ( isTracking )
{
double currentMouseX = e.GetPosition( null ).X;
double currentMouseY = e.GetPosition( null ).Y;

These values will be the new position for the Left and Top values of our shape. While this works okay for a square, it is counter intuitive for a Circle as a Circle's top-left corner is actually that of the invisible bounding rectangle, as illustrated here (with the bounding rectangle filled in artificially in turquoise),

BoundingRect1

Since the bounding rectangle is actually invisible however, the user is forced to drag from a point to the north-west of the circle, a disconcerting and odd experience,

BoundingRect2

To eliminate that, we'll reposition to the center of the shape,

    Shape s = e.OriginalSource as Shape;
    Canvas.SetLeft( s, currentMouseX  - s.Width / 2);
    Canvas.SetTop( s, currentMouseY - s.Height / 2);

MouseLeftButtonUp

When the left mouse button is released, we're done dragging, we can release our capture of the mouse and set IsTracking to false, remembering to restore the opacity to its original value

void Shape_MouseLeftButtonUp( 
object sender,
MouseButtonEventArgs e )
{
isTracking = false;
Shape s = e.OriginalSource as Shape;
s.Opacity *= 2;
s.ReleaseMouseCapture();
}

 

Here is the complete Page.xaml.cs in one place for easy copying:

using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;

namespace DragDrop
{
public partial class Page : UserControl
{
private bool isTracking = false;

public Page()
{
InitializeComponent();
Circle.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );
Square.MouseLeftButtonDown +=
new MouseButtonEventHandler( Shape_MouseLeftButtonDown );

Circle.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );
Square.MouseLeftButtonUp +=
new MouseButtonEventHandler( Shape_MouseLeftButtonUp );

Circle.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
Square.MouseMove +=
new MouseEventHandler( Shape_MouseMove );
}

// ** Button down **
void Shape_MouseLeftButtonDown(
object sender,
MouseButtonEventArgs e )
{
isTracking = true;
Shape s = e.OriginalSource as Shape;
s.Opacity *= 0.5;
s.CaptureMouse();
}


// ** Mouse Move **
void Shape_MouseMove(
object sender,
MouseEventArgs e )
{
if ( isTracking )
{
// get the mouse position
double currentMouseX = e.GetPosition( null ).X;
double currentMouseY = e.GetPosition( null ).Y;

// center the shape at the mouse position
Shape s = e.OriginalSource as Shape;
Canvas.SetLeft( s, currentMouseX - s.Width / 2);
Canvas.SetTop( s, currentMouseY - s.Height / 2);
}
}

// ** Button up **
void Shape_MouseLeftButtonUp(
object sender,
MouseButtonEventArgs e )
{
isTracking = false;
Shape s = e.OriginalSource as Shape;
s.Opacity *= 2;
s.ReleaseMouseCapture();
}
} // end class
} // end namespace
 
Try it: 

 

 

-j

Posted by jesseliberty | 17 comment(s)
Filed under: , ,

Navigating threads

For the past couple weeks I've been ironing out a new navigation feature that I've added to my blog. The goal is to allow you to follow a topic as it threads through the blog, skipping over intervening messages, or going back to see previous messages on the topic.

While tags help with this, they are not efficient for following a series of messages that build on one another. Thus I've settled on this convention: when I add a message that builds on a previous message, even obliquely, I add a backward pointer to the new message and a forward pointer to the old message.


Previous: Name of previous entry    Next: Name of next entry

The goal is that you will be able to follow a discussion thread through the blog, skipping over the intervening messages as you desire, without this system getting in your way if you wish to ignore it.

Posted by jesseliberty | 1 comment(s)
Filed under:

Pie Chart and Column Chart videos post

NewPieChartVideoI’m pleased to announce that my videos on the Silverlight Toolkit PieChart and Columns chart are now available. 

What is very nice is that once you understand how one of these charts works, working with the other becomes almost self-evident.

 

 

 

 

 

 

 

Posted by jesseliberty | 8 comment(s)
Filed under:

Tag + Phone = Contact

This excellent idea from Microsoft UX Evangelist René de Paula Jr arrived just 1/2 a day too late for me to try it out at Code Mash, but I will do so at my next opportunity. He suggests placing a Microsoft Tag encoding my VCard as the final slide in my presentation; which I think is nothing short of brilliant.

ContactMe

(note, using the gettag phone application on the image above will, in fact, add my contact information to your contacts).

It will be interesting to think about how these tags might be integrated into Silverlight applications.

Posted by jesseliberty | 3 comment(s)
Filed under:
Next