Binary Bob’s Blog

19
Apr

“Tax Season” is especially painful this year!

Posted By Bob Bartholomay under Flex Study, Misc, Silverlight. This post has No Comments

Ouch! Right on the heals of April 15th (tax day in the U.S.) come big product releases from both Adobe and Microsoft.

Long ago the term “Redmond Tax” was coined referring to the constant cost to stay current with Microsoft products but there’s an equal San Jose Adobe tax as well. If I were a big software company I’d give away my tools so those hardworking, creative programmers and designers will build amazing apps that make my brand so much stronger and boosted sales in other areas (wax those corporate users for office! – but I need that too…).

While employers may buy volumne liscenses and give you your key, I have always wanted my own tools and have always ponied up and bought everything I needed to produce in the technologies I’m currently using. Now that I’m doing both Flex and Silverlight I pay big-time for that luxury. But hey, some people collect paintings, other shoes, with me its software. Man that feels good to press that “Buy Now…” button and get my system all upgraded with the latest bits and safely Ghosted (need that too).

So if I want to keep this up I’ll need to upgrade my current tools (and I will):

  • Microsoft Visual Studio 2010 upgrade from 2008 version $549.00 (I wish they never released so I could use the Beta bits)
  • Microsoft Expression Blend. Here I get off easy with a “free” upgrade for Silverlight 4 (I guess they just couldn’t live with themselves if they nailed me again already) as I had already purchased Expression Studio) otherwise:  $349
  • Adobe Creative Suite 5 Web Premium (update from CS3 as we all waited to get past Adobe’s “Vista”  of CS4)  for $799.

Well, there goes that early IRA funding for this year.  I rationalize it all by rightfully reminding myself that I make good money via these tools and the cost is therefore justified. But I used to make money using Linux, Java and MySQL too! – Cheers!

25
Mar

Flex 4 RadioButtonGroup is non-visual

Posted By Bob Bartholomay under Flex Study. This post has No Comments

I noticed a few things with respect to RadioButtonGroup with Flex 4. It inherits directly from EventDispatcher and is thus “non-visual” as stated in the docs:

Notice that the RadioButtonGroup component is a subclass of EventDispatcher, not UIComponent, and implements the IMXMLObject interface. All other Flex visual components implement the IVisualElement interface. The RadioButtonGroup component declaration must be contained within the tag since it is not assignable to IVisualElement.

The part that threw me was that you can specify the group to which any particular RadioButton belongs to (and thus is mutually exclusive in selection with that group’s other members) in one of two ways:

  • via the group property which is of type RadioButtonGroup
  • via the groupName property of type  String

It seems though that the framework is making some assumptions on your behalf in that you can omit the declaration of the RadioButtonGroup altogether and the RadioButtons work fine. If you opt for the String variation and don’t declare the RadioButtonGroup in the fx:Declarations tag the application will cheerfully compile and run without error. In fact, you can specify nothing for the group and it will run fine. Seems if they are in the same container they will work.

To be safe, declare the RadioButtoGroup in a fx:Declarations section and use the groupName property and curly brace syntax so the compiler has a chance to weigh in.

Have a look at this Flex 4 code and play with it running below to get the drift. – Cheers!

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx">
	<fx:Declarations>
		<s:RadioButtonGroup id="rgroup1"/>
	</fx:Declarations>
 
	<s:layout>
		<s:VerticalLayout paddingTop="20"
						  paddingLeft="20"/>
	</s:layout>
 
	<s:VGroup height="100">
		<s:Label text="both to rgroup1 via group property"/>
		<s:RadioButton group="{rgroup1}"/>
		<s:RadioButton group="{rgroup1}"/>
	</s:VGroup>
 
	<s:VGroup height="100">
		<s:Label text="both to rgroup1 via groupName property"/>
		<s:RadioButton groupName="rgroup1"/>
		<s:RadioButton groupName="rgroup1"/>
	</s:VGroup>
 
	<s:VGroup height="100">
		<s:Label text="both to non-existent rgroup2 via group property, they are still mutually exclusive"/>
		<s:RadioButton groupName="rgroup2"/>
		<s:RadioButton groupName="rgroup2"/>
	</s:VGroup>
 
	<s:VGroup height="100">
		<s:Label text="each to different non-existent rgroup3 and rgroup4, they are NOT mutually exclusive"/>
		<s:RadioButton groupName="rgroup3"/>
		<s:RadioButton groupName="rgroup4"/>
	</s:VGroup>
 
	<s:VGroup height="100">
		<s:Label text="Both have no group specified at all, but they are still mutually exclusive"/>
		<s:RadioButton/>
		<s:RadioButton/>
	</s:VGroup>
 
</s:Application>

Here’s the application running

.

6
Mar

Flex 4 ItemRenderers and the selected property

Posted By Bob Bartholomay under Uncategorized. This post has No Comments

If you’ve just searched on “Flex 4  +  cannot select ItemRenderer”,  you may have ended up here.  You see, I spent some time on that question recently and until I RTFM‘d the Flex 4 docs on the ItemRenderer class, I once more wrongfully jumped to the conclusion there’s a bug.

You see, Flex 4 introduces the DataGroup control which is meant to serve as a lightweight vehicle for holding data items with the goal of improved performance.

Perfromance improvement means sacrificing the ability to skin the DataGroup and (apparently) the ability to select the Itemrenderers used to display each item.

The compiler will not mention a thing when you include selected = “true” in the Itemrenderer (why should it? Its owner may be List) but when you run your project, while the hovered state is rendered, nothing happens when you click on the items. Simply changing the tag to List will remedy the situation.

I found the answer in the Flex 4 Help docs, specifically “Defining item renderer view states for a Spark container” which mentions:

  • The selected, normalAndShowCaret, hoveredAndShowCaret, and selectedAndShowCaret view states are supported by the list-based components. The list-based components are sublcasses of the spark.components.supportClasses.ListBase class. The DataGroup and SkinnableDataContainer containers do not implement these view states.

There you have it! Read the docs, its all in there (somewhere)! – Cheers!

28
Feb

On Desginers, Developers and the Adobe and Microsoft worlds

Posted By Bob Bartholomay under Blend, Flash Study, Silverlight. This post has 1 Comment

I spent the summer and fall in the Silverlight world and it became apparent to me that the designer and developer worlds are converging. With the emergence of Expression Blend 3 designers visually create  XAML using Blend’s States and Properties panels. This XAML can be VERY long and verbose but the results when applied to UI components can be staggering with respect to effects and state changes.  In this new world, if you want really expressive states and transitions you need to use a tool (unless your Charles Petzold) and not write it all by hand.

With this worldly collision, the designer needs to know more coding than before and that’s a two-way street in that the the coders need to know more design as well. If you walk through some of the Adobe demos for Flash Catalyst, the designer creates the graphics, application flow, hooks up controls (e.g Button clicks change states) and other things that used to be the domain of the programmer. The coder is left to integrate the backend data. I thought: “Man, I need to learn design or I’ll be out of a profession”.

Both of the Microsoft tools for creating Silverlight applications, Visual Studio and Blend, work off the same code base simultaneously, and when you make changes in one, you are prompted in the other that , indeed, changes have been made and do you want to use them? I found myself with both tools open and switching between them constantly. Its as if Blend became the Visual Studio designer that was the brunt of so much ridicule as it never really was there.

Now I’m back in the Flex world, in particular, Flex 4 whose tools are Flash Builder and Flash Catalyst. Flex 4 makes the huge and necessary change to using “lookless’ controls ala Silverlght where a control’s behavior is separated from its look and feel. This allows for radically different looking things to act similarly because, even though the ‘skin’ (how it looks) may have been greatly changed, the underlying code dictating how it acts is unchanged. Support for tooling (Blend, Flash Catalyst) is a major driving force in this shift.

I wanted to find out what Adobe intended for us to use to create complex skins for components. Simple ones can be hand edited in Flash Builder but anything more complex (and real world) can quickly evolve beyond hand editing and that is where tools are useful.

Enter Flash Catalyst. The current available Beta is version 2 along with Flash Builder (the re-branded Flex Builder). Let’s be fair here and note the word Beta. Rumors are that when released, we will see big changes and I hope so as I was under-impressed at first blush (the usual I’m not a technology vigilante inserted here… I just want to work in both Flex and Silverlight).

After a little on ramp learning, I came up with this hello world workflow:

  • create a new project in Calalyst
  • place a button on the design surface
  • use the different states and the timeline to change the appearance of the Button for various states and add transitions between them.
  • preview it in Catalyst to be sure its what you want
  • export the project (*.fxp) to my file system
  • Open the  Flash Builder project that I have been working on and want to use this fancy button in
  • import the fxp project into the workspace
  • drag the MXML that was produced by Catalyst into my main project
  • delete the just created project by  importing the .fxp file
  • use the Catalyst Button (with its fancy states and transitions) in my main Flex project

Yikes! I found no way to:

  • export a skin from catalyst that I could directly import into the Flash Builder project I was working on and then assign it to a Button.
  • make changes to that skin in Flash Builder and then go back to Catalyst and work with it from there (so called round-tripping)
  • There was no way each application could work off the same code base, in real time.

I’m trying very hard to be fair, but an ace is an ace and I can only take solace in the fact that Adobe is vigorously working on these features and they will be present in the released versions of both products.

One other thing that came to mind is how about letting us import from Fireworks into Catalyst. It seems to me Adobe would have been better off taking one of their existing product (Flash or Fireworks maybe) and morphing that into what they envisioned for Catalyst.

I’m very anxious to see the next product cycle from Adobe. I want to see Flash CS5, Flash Builder and Flash Catalyst all come out feature rich, bug poor and working together seamlessly, but hey, seamlessly is a Microsoft term! – Cheers!

19
Jan

FlexibleBehavior class: More on reuse and Behaviors

Posted By Bob Bartholomay under Silverlight. This post has 4 Comments

A recent post explained how encapsulating functionality (e.g. Animations, etc) into a Behavior promoted reuse in that once this functionality is encapsulated into a Behavior, it can then easily be applied to multiple Controls in various projects by a designer using Blend (remember “write once run anywhere”!)

Thinking deeper I thought: “That’s not really as reusable as it could be. The triggering event is essentially hardcoded”, let me explain:

The typical workflow may go something like this:

  • the Designer gives the Developer specs for a needed Behavior: “I need to ‘dim’ a FrameworkElement via its Opacity value when the mouse enters my control and I want to control the duration of and amount its dimmed via Blend”
  • the Developer codes up a Behavior packaged into a DLL that the designer then references in Blend. The coder exposes public Properties for the Duration and Opacity so the Designer can tweak those settings in the Blend Properties Panel. He makes the Behavior trigger on the MouseEnter Event by adding a listener in the OnAttached() method.

Great stuff! The much ballyhooed Holy Grail of the “Design/Developer Workflow” is in full flower. But the leaves of this flower may start to fall off if the Designer comes back to the Developer (a few times) and says: “You know, I think we should use the LostFocus Event instead of MouseEnter”. The developer needs to touch the code for the Behavior, recompile, redistribute the DLL and the Designer then references the newly updated DLL. Can you see the problem? The Event is hardcoded in the Behavior. Wouldn’t it be great if the Designer could specify the Event in the Properties Panel like the other properties of the Behavior?

If what you are doing in the handler for whatever Event triggers the Behavior does not rely on the specific Event Type passed to it (like MouseEventArgs), and you can live with the basic Event class, then you can use a generic handler for any of the 15 odd Events exposed by the FrameworkElement class. You can then add a public property to the Behavior that allows the Designer to specify which event to use as the triggering event right in Blend and logic (say a switch) to figure out what Event to listen for in the Behavior by examining the value the designer put into the EventName field in Blend. The result is that the Event is no longer hardcoded and the Designer controls which event to use via Blend. He can apply this Behavior to any project for any FrameworkElement and use any of the available events.

General functionality (like tweaking the Opacity) may be applied to many different types of FrameworkElements on many different types of events. I created a “FlexibleBehavior” class that inherits from Behavior as follows:

?View Code CSHARP
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Interactivity;
 
namespace FlexibleBehavior
{
    public class FlexibleBehavior : Behavior
    {
        private string triggeringeventname = "MouseEnter";
 
        public string TriggeringEventName
        {
            get { return triggeringeventname; }
            set { triggeringeventname = value; }
        }
 
        protected override void OnAttached()
        {
            base.OnAttached();
 
            switch (TriggeringEventName)
            {
                case "BindingValidationError":
                    AssociatedObject.BindingValidationError += AssociatedObject_GenericEventHandler;
                    break;
                case "GotFocus":
                    AssociatedObject.GotFocus += AssociatedObject_GenericEventHandler;
                    break;
                case "KeyDown":
                    AssociatedObject.KeyDown += AssociatedObject_GenericEventHandler;
                    break;
                case "KeyUp":
                    AssociatedObject.KeyUp += AssociatedObject_GenericEventHandler;
                    break;
                case "LayoutUpdated":
                    AssociatedObject.LayoutUpdated += AssociatedObject_GenericEventHandler;
                    break;
                case "Loaded":
                    AssociatedObject.Loaded += AssociatedObject_GenericEventHandler;
                    break;
                case "LostFocus":
                    AssociatedObject.LostFocus += AssociatedObject_GenericEventHandler;
                    break;
                case "LostMouseCapture":
                    AssociatedObject.LostMouseCapture += AssociatedObject_GenericEventHandler;
                    break;
                case "MouseEnter":
                    AssociatedObject.MouseEnter += AssociatedObject_GenericEventHandler;
                    break;
                case "MouseLeave":
                    AssociatedObject.MouseLeave += AssociatedObject_GenericEventHandler;
                    break;
                case "MouseLeftButtonDown":
                    AssociatedObject.MouseLeftButtonDown += AssociatedObject_GenericEventHandler;
                    break;
                case "MouseLeftButtonUp":
                    AssociatedObject.MouseLeftButtonUp += AssociatedObject_GenericEventHandler;
                    break;
                case "MouseMove":
                    AssociatedObject.MouseMove += AssociatedObject_GenericEventHandler;
                    break;
                case "MouseWheel":
                    AssociatedObject.MouseWheel += AssociatedObject_GenericEventHandler;
                    break;
                case "SizeChanged":
                    AssociatedObject.SizeChanged += AssociatedObject_GenericEventHandler;
                    break;
                default:
                    break;
            }
        }
 
        protected override void OnDetaching()
        {
            base.OnDetaching();
 
            switch (TriggeringEventName)
            {
                case "BindingValidationError":
                    AssociatedObject.BindingValidationError -= AssociatedObject_GenericEventHandler;
                    break;
                case "GotFocus":
                    AssociatedObject.GotFocus -= AssociatedObject_GenericEventHandler;
                    break;
                case "KeyDown":
                    AssociatedObject.KeyDown -= AssociatedObject_GenericEventHandler;
                    break;
                case "KeyUp":
                    AssociatedObject.KeyUp -= AssociatedObject_GenericEventHandler;
                    break;
                case "LayoutUpdated":
                    AssociatedObject.LayoutUpdated -= AssociatedObject_GenericEventHandler;
                    break;
                case "Loaded":
                    AssociatedObject.Loaded -= AssociatedObject_GenericEventHandler;
                    break;
                case "LostFocus":
                    AssociatedObject.LostFocus -= AssociatedObject_GenericEventHandler;
                    break;
                case "LostMouseCapture":
                    AssociatedObject.LostMouseCapture -= AssociatedObject_GenericEventHandler;
                    break;
                case "MouseEnter":
                    AssociatedObject.MouseEnter -= AssociatedObject_GenericEventHandler;
                    break;
                case "MouseLeave":
                    AssociatedObject.MouseLeave -= AssociatedObject_GenericEventHandler;
                    break;
                case "MouseLeftButtonDown":
                    AssociatedObject.MouseLeftButtonDown -= AssociatedObject_GenericEventHandler;
                    break;
                case "MouseLeftButtonUp":
                    AssociatedObject.MouseLeftButtonUp -= AssociatedObject_GenericEventHandler;
                    break;
                case "MouseMove":
                    AssociatedObject.MouseMove -= AssociatedObject_GenericEventHandler;
                    break;
                case "MouseWheel":
                    AssociatedObject.MouseWheel -= AssociatedObject_GenericEventHandler;
                    break;
                case "SizeChanged":
                    AssociatedObject.SizeChanged -= AssociatedObject_GenericEventHandler;
                    break;
                default:
                    break;
            }
        }
 
        protected virtual void AssociatedObject_GenericEventHandler(object sender, EventArgs e)
        {
        }
    }
 
}

With that DLL referenced in a new Silverlight Class Library project, I created the DimmerBehavior class that extends FlexibleBehavior and added my Behavior specific functionality (mess with the Opacity via a Storyboard) and did not specify any specific event:

?View Code CSHARP
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media.Animation;
 
namespace DimmerBehavior
{
    [Description("Animates the Opacity of a FrameworkElement")]
    public class DimmerBehavior : FlexibleBehavior.FlexibleBehavior
    {
        private Storyboard storyboard;
        private double opacityTo = 0.2;
        private TimeSpan dimmer_duration = TimeSpan.FromSeconds(.2);
 
        // public Property needed for the Blend Properties Panel
        [Description("The Event of FrameworkElement object that triggers this Behavior")]
        public string Eventname
        {
            get { return base.TriggeringEventName; }
            set { base.TriggeringEventName = value; }
        }
 
        [Description("Value of the AssociatedObject's Opacity property to animate to")]
        public double OpacityTo
        {
            get { return opacityTo; }
            set { opacityTo = value; }
        }
 
        [Description("Duration of the animation")]
        public TimeSpan Dimmer_duration
        {
            get { return dimmer_duration; }
            set { dimmer_duration = value; }
        }
 
        protected override void OnAttached()
        {
            base.OnAttached();
        }
 
        protected override void OnDetaching()
        {
            base.OnDetaching();
        }
 
        protected override void AssociatedObject_GenericEventHandler(object sender, EventArgs e)
        {
            base.AssociatedObject_GenericEventHandler(sender, e);
 
            var doubleanimation = new DoubleAnimation();
            doubleanimation.To = opacityTo;
            doubleanimation.Duration = dimmer_duration;
 
            storyboard = new Storyboard();
            storyboard.Duration = dimmer_duration;
            storyboard.Children.Add(doubleanimation);
 
            Storyboard.SetTarget(doubleanimation, AssociatedObject);
            Storyboard.SetTargetProperty(doubleanimation, new PropertyPath(FrameworkElement.OpacityProperty));
 
            storyboard.Begin();
        }
    }
}

Creating a Silverlight Application in Blend and dragging the DimmerBehavior from the Assets Panel onto a FramerworkElement on the artboard you’ll see where the Designer can specify the name of the Event in the Properties panel (more on that below):

Blend and FlexibleBehavior

And here’s a tester Application with the MouseLeave event dialed in via Blend. Run it and see it dim when the mouse leaves the rectangle:

If you later want to use a different event, just change it in Blend – no need to wake up the developer! The code for all of this is available here.

There’s one glaring improvement that can be made here and that is to put Blend’s Design-time extensibility into play so that the Designer can not hurt himself by misspelling (or not knowing which events are available) the Event in the EventName field in the Blend Properties Panel by using a ComboBox that lists all these events for easy selection as well as precluding anything hand-typed.

But that subject (Blend design time extensibility) is a vast and somewhat confusing one as well as being somewhat of a moving target with Silverlight and WPF and Visual Studio 2008 and 2010 (with a designer!) and a new version of Blend to deal with. Its a fascinating subject and required knowledge for Custom Control authors but its not explored here. If you are interested see these links:

Cheers!

8
Jan

Promoting reuse using Behaviors: RotateRefreshBehavior

Posted By Bob Bartholomay under Silverlight. This post has 4 Comments

I needed a UI Control that enables the user to refresh the current View. When the user clicks the control it rotates as feedback.

The quickest way to do this would be to switch to the animation workspace in Blend and create a new Storyboard, set a KeyFrame and dial in a RotateTransform using the Properties Panel. What you end up with is a Storyboard in the Resources section of your XAML. You could then call the Storyboard’s Begin() method in some event handler. You could make this Animation more reusable by placing it into its own XAML resource file and then bring it into your project via MergedResources.

An even better approach to promoting reuse (as well as design time use in Blend) is to encapsulate this functionality into a Behavior. This makes it available to designers in Blend where they can just drag it from the Assets Panel onto a control on the artboard. You can then adjust the Behavior’s properties in Blend (instead of editing the XAML resource) to suit your needs and your done.

You will need to weigh a few variables to decide if the time spent coding up the Behavior is worth it in relation to your expected reuse. Programatically coding up Animations is more work than visually doing it in Blend. If you do indeed decide to make a Behavior, it will be most reusable if you create it in its own Visual Studio project ( a Silverlight Class Library project) so it lands in a separate dll that you (or the designer) can easily reference and use in future projects.

Here’s the Behavior applied to a Button that uses an Image as its Content. Hover over and click it to see the refresh animation…

The XAML is uninteresting but here’s the Behavior code: – Cheers!

?View Code CSHARP
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
 
namespace RotateRefreshBehavior
{
    public class RotateRefreshBehavior : Behavior<UIElement>
    {
        private RotateTransform rt;
        private Storyboard sb;
        private Transform origRenderTransform;
 
 
        private TimeSpan rotate_duration = TimeSpan.FromSeconds(.2);               
        private double rotate_angle = 360;
        private RepeatBehavior rotate_repeat = new RepeatBehavior(1);
        private bool rotate_autoReverse = false;
 
        private TimeSpan hover_duration = TimeSpan.FromSeconds(.1); 
        private double hover_angle = 30;
        private RepeatBehavior hover_repeat = RepeatBehavior.Forever;
        private bool hover_autoReverse = true;
 
        #region get/set
        [Description("Number of degrees to rotate on Click")]
        public double RotateAngle
        {
            get { return rotate_angle; }
            set { rotate_angle = value; }
        }
 
        [Description("Time to complete the rotation on Click")]
        public TimeSpan RotateDuration
        {
            get { return rotate_duration; }
            set { rotate_duration = value; }
        }
 
        [Description("Number of times to rotate_repeat on Click (0 is none)")]
        public RepeatBehavior RotateRepeatBehavior
        {
            get { return rotate_repeat; }
            set { rotate_repeat = value; }
        }
 
        [Description("Reverse the rotation when completed on Click")]
        public bool RotateAutoReverse
        {
            get { return rotate_autoReverse; }
            set { rotate_autoReverse = value; }
        }
 
        [Description("Number of degrees to rotate on Hover")]
        public double HoverAngle
        {
            get { return hover_angle; }
            set { hover_angle = value; }
        }
 
        [Description("Time to complete the rotation on Hover")]
        public TimeSpan HoverDuration
        {
            get { return hover_duration; }
            set { hover_duration = value; }
        }
 
        [Description("Number of times to rotate_repeat on Hover (0 is none)")]
        public RepeatBehavior HoverRepeatBehavior
        {
            get { return hover_repeat; }
            set { hover_repeat = value; }
        }
 
        [Description("Reverse the rotation when completed on Hover")]
        public bool HoverAutoReverse
        {
            get { return hover_autoReverse; }
            set { hover_autoReverse = value; }
        }
        #endregion
 
        protected override void OnAttached()
        {
            base.OnAttached();
 
            origRenderTransform = AssociatedObject.RenderTransform;
 
            AssociatedObject.MouseEnter += AssociatedObject_MouseEnter;
            AssociatedObject.MouseLeave += AssociatedObject_MouseLeave;
 
            AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
        }
 
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.RenderTransform = origRenderTransform;
 
            AssociatedObject.MouseEnter -= AssociatedObject_MouseEnter;
            AssociatedObject.MouseLeave -= AssociatedObject_MouseLeave;
 
            AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
        }
 
        private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            rt = new RotateTransform();
            AssociatedObject.RenderTransform = rt;
            AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);
 
            var da = new DoubleAnimation();
            da.To = rotate_angle;
            da.Duration = rotate_duration;
 
            sb = new Storyboard();
            sb.RepeatBehavior = RotateRepeatBehavior;
            sb.AutoReverse = RotateAutoReverse;
 
            sb.Children.Add(da);
 
            Storyboard.SetTarget(da, rt);
            Storyboard.SetTargetProperty(da, new PropertyPath(RotateTransform.AngleProperty));
 
            sb.Begin();
        }
 
        private void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
        {
            rt = new RotateTransform();
            AssociatedObject.RenderTransform = rt;
            AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);
 
            var da = new DoubleAnimation();
            da.To = hover_angle;
            da.Duration = hover_duration;
 
            sb = new Storyboard();
            sb.RepeatBehavior = HoverRepeatBehavior;
            sb.AutoReverse = HoverAutoReverse;
 
            sb.Children.Add(da);
 
            Storyboard.SetTarget(da, rt);
            Storyboard.SetTargetProperty(da, new PropertyPath(RotateTransform.AngleProperty));
 
            sb.Begin();
        }
 
        private void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
        {
            if (sb != null)
                sb.Stop();
        }
 
    }
}
3
Jan

Silverlight XAML Viewer with info callouts and links to MSDN docs

Posted By Bob Bartholomay under Silverlight. This post has 4 Comments

I’ve been messing around with a Silverlight 3 app that allows you to open and view XAML files located on your locale machine. Sure, you can do that already with your favorite editor including Visual Studio but I wanted to show more information easily so the viewer did not have to continually copy and paste or search help and loose the whole picture of the XAML file while they learn about a particular piece of it..

If you’ve worked with XAML for any length of time you develop the ability to quickly look at some XAML markup and know what’s going on. But do you remember the first time you did that? How strange it looked?

Well, this application is geared towards those who are not XAML masters and want to know what all the tags mean. As the user hovers over certain key words in the rendered XAML doc a callout pops up with some useful and concise help. If they want more information they can click on a “msdn” icon and another browser tab opens up with the Silverlight docs for that particular item.

Here’s a screenshot of it in action…

Code Display

The Callout blurbs are from a schema file named XamlPresentation2006.xsd which is from Visual Studio 2005 before Microsoft changed the way Intellisense is handled. This file has WPF related info but its as close a source of XAML ‘keyword’ information that I could find for Silverlight. This is the info that is displayed in tooltips while hovering over keywords. There is no info on some of the newer features like Visual State Manager but all in all it covers things fairly well.

Unfortunately, the XamlPresentation2006.xsd is 3.6 MB large. The app uses WebClient to download it on startup so I just can’t embed the app in this post as some may be on dialup connections.

You can run it from here if your interested. Just click the “Open XAML file” and go find a XAML file in your file system. – Cheers!

29
Oct

A Lack of Posts…

Posted By Bob Bartholomay under Uncategorized. This post has No Comments

Please excuse my absence with regards to this blog. I have been attending to aging parents in Florida while they get through some medical issues.

I’d like to thank the professional staff at the Leesburg Regional Medical Center for their most professional care and knowledge. Other than noting the use of technology in the medical profession, I have had little time to stay current or do other programming work.

But rest assured that I will be back soon and look very forward to catching up on all that has transpired. Cheers!

23
Sep

Animations and View State changes with MVVM

Posted By Bob Bartholomay under Silverlight. This post has 9 Comments

A recent question on the Silverlight forums reminded me of an issue any MVVM fanboy will face sooner or later: “Is it possible to start an animation (StoryBoard in the XAML) from the ViewModel”?

One of the major tenets of MVVM is “separation of concerns” in that the View is not supposed to know about the ViewModel (among other things). The View’s DataContext gets set on its instantiation and from there on out all it knows is that parts of it are databound to something somewhere.

Animations/Storyboards happen in the View. For example, the transition from one ViewState to Another. So how do you get a StoryBoard to begin or cause ViewState change when a Property in the ViewModel changes or is of a particular value? The poster wanted a MVVM solution that follows the mantra: “no (read little as possible) code behind for the View”.

I’ve solved this previously by using Routed Events fired from the ViewModel in response to a Command associated with a UI Control. What I hadn’t solved was how to get these View changes purely on changes to the data in the ViewModel.

I scoured the Web and found more questions than solutions but eventually identified a number of approaches (some better than others):

  1. ICommands and RoutedEvent
  2. Using an IView interface
  3. ICommand and CLR Events
  4. Using a StoryboardManager
  5. Using DataTriggers

ICommands and RoutedEvent: It goes like this: a ButtonBase has an ICommand associated with it. The Command handler in the VM sets a Property ( that implements INotifyPropertyChanged) in the ViewModel and Raises a RoutedEvent that’s listened for and handled in the View where it changes State or starts a Storyboard. This has some (little) code behind in the View.

Using an IView interface: All the Views in the app implement an interface that dictates a method implementation be specified that allows the ViewModel to “mess with” the View (via the implemented method) like changing a ViewState. Here the ViewModel knows too much about the View and “calls into it”.

ICommand and CLR Events: basically the same scenario as with RoutedEvents but should be used if all you need is the CLR event functionality.

Using a StoryboardManager: this is the solution the forum poster found and used. Its a solution created by Chris Klug which honors the separation between the View and VM by using an Attached Property. You can read about it on his blog ( link above) or see it in the example code below.

Using DataTriggers: Did I getcha? Silverlight doesn’t have a DataTrigger implementation but Peter Blois’ (again he solves the big issues!) worked one up and it solves the problem perfectly. Great separation, can be used in Blend and follows the DataTrigger XAML syntax that WPF uses.

I wrote a test app that implements all the above except the IView Interface. You can play with the app below but you’ll need to look at the code and the links referenced to get a good idea of how they work and which is best for you and your particular project.

One thing’s for sure. When there’s a “Silverlight vacuum”, sharp devs fill it quickly with elegant solutions and best of all they take the time to blog their ideas and share with the Silverlight community. – Cheers!

Visual Studio Solution download

References:

18
Sep

[screencast] Graphical skinning via NineGrid

Posted By Bob Bartholomay under Silverlight. This post has 2 Comments

My last post spoke of Peter Blois’ NineGrid.dll and how it can be used to do Nine Scale in Silverlight.

Here’s a quick video showing how I used it in case anyone is having issues. – Cheers!

link to screencast