Friday, June 20, 2008

[Silverlight, C#] User Controls and Namespaces

In working with my user controls I started creating elements dynamically which were then moved back and forth from user control to user control depending on the actions the user was taking. I then ran into some naming problems: I had a function that would check for the existence of a name before I added the element to the DOM, however, I was getting some unexpected results.

So then I asked myself the question... how is this even working? I have multiple copies of a user control, how come I am not seeing naming convention issues when I use the same control twice in my application?

I did a little test regarding User Controls and the names of objects inside them and determined: User Controls create an implicit new namespace so that the elements within it may continue to be named the same. This means you cannot 'find' an element name that does not DIRECTLY belong to the user control namespace you are searching in.

Check out the screen shot of the application I whipped up, and hopefully it will make sense.

.

Monday, June 16, 2008

[C#, Silverlight] Access to Resources

A little background... I want to be able to load up a XAML element from a file that may or may not contain an animation associated with its resources, and then start the animation when I mouseover this newly created element.

Here is exactly what I *want* to do:
  • Load up a snippet of XAML code [read from a xaml file retrieved from my server] via XAMLReader.Load(). This XAML object may contain a storyboard in it's resources:

    • < Rectangle name="myRect" fill="Blue" width="50" height="20">
        
          < Storyboard x:Name="myRect_Storyboard" >
            < DoubleAnimation Storyboard.TargetName="myRect" ... / >
          < /Storyboard >
        < /Rectangle.Resources >

  • Call the Begin() function for the storyboard when I load up the XAML snippet.
  • Here is my problem though... I do not know the NAME of the storyboard when loading up the XAML snippet, or if a storyboard even exists.

A few notes:
  • As of Silverlight 1.1... elements in a ResourceDictionary [including Storyboard] must have their x:Name set.
  • Each resource property element within each ResourceDictionary must have a unique value for the x:key [name?], which serves as the unique key when values are retrieved from the ResourceDictionary.
  • We can set the "Name" property... but can we set the "x:Name" property in code behind?
  • XAML syntax does not include an element for the ResourceDictionary class. This is an example of XAML implicit collection syntax; a tag representing the collection element can be omitted. The elements that are added as items to the collection are specified as child elements of a property element of a property whose underlying type supports a collection Add method. [MSDN]
  • Every framework-level element (FrameworkElement or FrameworkContentElement) has a Resources property, which is the property that contains the resources (as a ResourceDictionary) that a resource defines. You can define resources on any element. However, resources are most often defined on the root element, which is Page in the example. [Taken from MSDN.]
  • As of Silverlight beta 2, the Application.ResourcesProperty is private.

I'll come back to this later... this was just a dumping ground for things I have found so far.

EDIT: I was trying to enumerate through the ResourceDictionary [FrameworkElement.Resources], however in Beta 2 this was always showing as 0 after the XAML snippet was loaded.

Turns out - it's a bug! So I'm just going to have to wait until it's solved unless I can think of some other way to get access to the resources without knowing their names.

Thursday, June 12, 2008

[C#] Custom User Control Constructors [No Arguments]

So I was playing around with the new custom user controls I created for my ProgressBar etc... and I noticed that when I was trying to inject them into another XAML page that is in my project that the intellisense wasn't picking it up. It was like the control was not valid even though I was using the correct namespace, and could see my OTHER custom controls.

I started playing around and I noticed that I had ONE constructor for the control, and it took one parameter [I was setting a property or something with this parameter]. When I removed the argument from the function call [ie. public ProgressBar() {...}] - BAM - I could see the control via intellisense!

Again, this may be common knowledge, but it leads me to think that:
  • All custom user controls MUST contain a constructor with no arguments?
I'm guessing this is due to how inheritance is implemented, and had I REALLY thought about this earlier, I should have known this to be the case.

[Silverlight B2, C#] Custom User Controls "Overlap" in StackPanel...???

Ok, so I'm going to put money on the fact that I am doing something wrong... but I have no clue what. Here's the run down:
  • I created a User Control for a ProgressBar
    • XAML consists of a Canvas, border Rectangle, fill Rectangle, and a TextBlock.
    • C# code simply allows for the "percentComplete" which will change the width of the fill bar and the text accordingly. It's really rather simple.
  • I created a User Control for a ProgressArea
    • XAML consists of a StackPanel that will contain one or more ProgressBars.
    • C# code has an "AddBar" function which will create a new ProgressBar and then add it into the StackPanel.
Seems simple... however, when I add more then one ProgressBar they "overlap" each other. It's like the StackPanel has no idea about the width/height of each control. I know that they are overlapping because if I set the margin to something like "20,20,0,0" I can SEE both of them.

When I add multiple standard controls to the StackPanel [like TextBlock] they stack fine. Obviously I am not setting something correctly in my custom control... just have no idea what. Once again my google search has turned up nothing.

So if anyone is ACTUALLY reading this, and knows what's up... PLEASE let me know!!! I will like love you forEVAR :)


EDIT: Ok so... I'm not certain exactly what happened. I was playing around with getting around this problem by setting the margin of each ProgressBar to be just a smidge bigger then the height of the bar. And after setting it and then removing it... the stack panel seems to work fine now. My controls are stacking on top of each other just fine WITHOUT my margin setting.

/Shrug. No idea. But I'm not going to complain.


.

Tuesday, June 10, 2008

[Silverlight B2] No more "MouseLeftButtonDown" event on Button?

Whee! More problems!

I have been using the "MouseLeftButtonDown" event to register all of my events that may pertain to a click. I've been doing this in practice because some of my objects differentiate between clicking down and clicking up [like for drag/drop]... so I just always extended this into my other object's event handlers... like buttons.

So before I had something like this:

[Button x:Name="Group" FontFamily="Arial" Content="Group" MouseLeftButtonDown="Group_MouseLeftButtonDown"]

But when Beta 2.0 dropped, that event no longer seemed to fire or was not getting registered correctly... I'm not actually sure since I couldn't find any documentation in the Breaking Changes page. I imagine it is tied to the changes made to event bubbling in 2.0.

To fix this I simply needed to change my buttons to use Click:

[Button x:Name="Group" FontFamily="Arial" Content="Group" Click="Group_Click" Margin="2"]

I still think that as an application designer we should be able to apply different event handlers to both the mousedown and mouseup events on a button, so maybe a solution will present itself in time. For now though, it was acceptable for me to simple switch to registering the Click event.

I just wanted to blog this as being an issue for me, in case anyone else ran into the same thing - or had some more info.

NOTE
Through the intellisense on VS2008, it came to my attention that:
  • Click is a RoutedEventHandler
  • MouseLeftButtonDown/Up events are MouseButtonEventHandler(s)
  • Each have their own respective argument types
I didn't realize there was a difference between mouseup/down and click... and perhaps this could point to part of the problem I was having.

NOTE
This blog gives a decent explanation of the bubbling changes that have occurred.

.

Converting from Silverlight Beta 1 to Beta 2

As usual, the transition from one beta to the next brings breaking changes... just going to list the ones I had here, and how I got around them:

SetValue Only Accepts the Correct Types (No Conversions)
Before I was passing in Strings for colors when manually creating my xaml elements, or I was using strings for some other properties where I shouldn't have been.
For example:
Beta1: myRect.setValue(Rectangle.FillProperty, "red");
Beta 1: myRect.setValue(Rectangle.StrokeThicknessProperty, "2");

This was nice because all the conversion to a SolidColorBrush was done for me... but alas they caught on to my laziness. So now I must do something like this:
Beta 2: myRect.setValue(Rectangle.FillProperty, new SolidColorBrush(Colors.Red);
Beta 2: myRect.setValue(Rectangle.StrokeThicknessProperty, 2.0);

I imagine I will also run into some issues when I need to convert from a HEX color, but I'll cross that bridge when I get there.


WebClient and HttpWebRequest Changes
This one really eluded me. This manifested in my code in the following way: I was using HttpWebRequest to get a xaml string directly from a file on my server, and then I was loading that xaml via xamlReader.load... BUT... I was now getting a Invalid cross-thread access" [System.UnauthorizedAccessException] exception.

Loading the EXACT same xaml from the page_loaded function worked fine... what the heck? From the advice of my project manager, I checked the Thread.CurrentThread.ManagedThreadId [System.Threading] of both the page_loaded and my httpWebRequest callback function and BAM... they are now in different threads.

Turns out there were a few things I was unaware of with Beta 2:
  • HttpWebRequest delegates were changed to return on a background thread.

  • HttpWebRequest is callable on a background thread

Also, what I wasn't aware of was this [which given the HttpWebRequest changes was brought to my attention]:
Solution?
Following the example shown on the Breaking Changes documentation I switched to using WebClient, which is now a much more robust class in beta 2.

My project manager also suggested I check out creating my own BackgroundWorker threads which would do any consuming processing I may need in the future, and then do a callback to my main thread when completed with the processed data that the main thread could use to create the desired XAML. I'm guessing BackgroundWorker will be my next blog post XD


More to follow I imagine...

Monday, June 9, 2008

Silverlight 2 Beta 2 is out!

Get it here.

1. Uninstall your old SDK and VS2008 toolkit.
2. Install Beta 2 via the silverlight_chainer file.
3. Checkout the Breaking changes from Beta 1 to Beta 2:
Download: Beta 2 Documentation
or
Online: On MSDN

BAM

[C#] Creating Custom Attached Properties

I'd been looking into creating custom attached properties to xaml elements so that I could store relative information regarding our "Object Linking" that will need to be implemented in my project. The concept was a little muddled to me, and I came close to getting it working last Friday, I was just missing a key step!

This is the HOW-TO article that helped me get it all together this morning:
Attached-Properties-in-Silverlight

Thursday, June 5, 2008

[WPF] Preview vs. Non-Preview Events

So in my reading travels today I started looking up animations, which took me to triggers, which took me to event handling, and I then bumped into the concept of preview vs. non-preview events [the mind is a wonderful thing]. This is particularly interesting to me since I have been using event handling in my current project, but don't fully understand how the model works.

So first of all... some definitions yoinked from MS because they make more sense then I ever could:

Taken from MSDN
Routed Event: A routed event is a type of event that can invoke handlers on multiple listeners in an element tree, rather than just on the object that raised the event.

A typical WPF application contains many elements. Whether created in code or declared in XAML, these elements exist in an element tree relationship to each other. The event route can travel in one of two directions depending on the event definition, but generally the route travels from the source element and then "bubbles" upward through the element tree until it reaches the element tree root (typically a page or a window). This bubbling concept might be familiar to you if you have worked with the DHTML object model previously.

Routing Strategies:

  • Bubbling: Event handlers on the event source are invoked. The routed event then routes to successive parent elements until reaching the element tree root. Most routed events use the bubbling routing strategy. Bubbling routed events are generally used to report input or state changes from distinct controls or other UI elements.
  • Direct: Only the source element itself is given the opportunity to invoke handlers in response. This is analogous to the "routing" that Windows Forms uses for events. However, unlike a standard CLR event, direct routed events support class handling (class handling is explained in an upcoming section) and can be used by EventSetter and EventTrigger.

  • Tunneling: Initially, event handlers at the element tree root are invoked. The routed event then travels a route through successive child elements along the route, towards the node element that is the routed event source (the element that raised the routed event). Tunneling routed events are often used or handled as part of the compositing for a control, such that events from composite parts can be deliberately suppressed or replaced by events that are specific to the complete control. Input events provided in WPF often come implemented as a tunneling/bubbling pair. Tunneling events are also sometimes referred to as Preview events, because of a naming convention that is used for the pairs.



Using routed events properly means that you can setup a common event listener to catch multiple events triggered from multiple objects. This concept is probably not new, but I found it interesting.
Routed event listeners and routed event sources do not need to share a common event in their hierarchy. Any UIElement or ContentElement can be an event listener for any routed event. Therefore, you can use the full set of routed events available throughout the working API set as a conceptual "interface" whereby disparate elements in the application can exchange event information. This "interface" concept for routed events is particularly applicable for input events.
So for example you can setup something like this:

< StackPanel Background="LightGray"
Orientation="Horizontal"
Button.Click="CommonClickHandler" >
< Button Name="YesButton" Width="Auto" >Yes
< Button Name="NoButton" Width="Auto" >No
< Button Name="CancelButton" Width="Auto" >Cancel
< /StackPanel >


and then use one handler like this:

private void CommonClickHandler(object sender, RoutedEventArgs e)
{
FrameworkElement feSource = e.Source as FrameworkElement;
switch (feSource.Name)
{
case "YesButton":
// do something here ...
break;
case "NoButton":
// do something ...
break;
case "CancelButton":
// do something ...
break;
}
e.Handled=true;
}
Routed events can also be used to communicate through the element tree, because the event data for the event is perpetuated to each element in the route. One element could change something in the event data, and that change would be available to the next element in the route.

FOR CRYING OUT LOUD... WHAT DOES THIS HAVE TO DO WITH PREVIEW EVENTS???
Gosh, weren't you reading? Tunneling events are referred to as "Preview" events. This is due to the fact that in WPF the naming convention to call such events are prefixed with the word Preview. Preview events are fired in the tunneling phase, and give a 'preview' of the state of the objects - however note that you cannot actually 'handle' the event in this phase, and thus you cannot set the event as being handled.

All other non-preview events are just as we expect. They are triggered in the bubbling phase and allow you to properly set the event as being handled.

Silverlight Note:
I am uncertain if Silverlight supports preview events yet. From the documentation I have seen, these events are prefixed with "Preview" [like "PreviewKeyDown" vs. "KeyDown"] and I cannot seem to access them via the VS2008 intellisense.

Why Use Preview Events?:
Use preview events if you wish to log some logic before any event handling occurs.
This forum post talks a little about the purpose of Preview Events.

Wednesday, June 4, 2008

[VS2008, Silverlight] "The project type is not supported by this installation"

So I spent the last 5 hours trying to get my VS2008 [which I had to do a re installation on] to recognize and open my silverlight projects. After uninstalling and reinstalling I was faced with the error message when trying to open my Silverlight project:
"The project type is not supported by this installation"
I figured that there was an issue with the Beta Toolkit for Visual Studio 2008, so I began my journey of uninstalling those components, reinstalling them, running into issues, hacking the registry, and cursing a lot. After all this was said and done... I reinstalled the Tools only to get the exact same error again.

Searching this error I found a webpage that instructed me to do the following:

Launch a command window, navigate to C:\Program Files\Microsoft Visual Studio x\Common7\IDE (where x is the version number) and run:

devenv /setup
That's it. That's all. Works perfect now. Thank you Andrew Gunn... I love you.

ps. I was curious about devenv /setup so I looked it up... it appears to merge menus, toolbars, command groups etc from all packages available. Not exactly sure what this means FULLY, but I imagine it tells VS2008 about all the packages [including the Silverlight package] that are available to it and that somehow in my re installation this package was missed.

/shrug.

Tuesday, June 3, 2008

[C#, WPF] Dependency Properties, Objects and Attached Properties [Oh my!]

Ok wow... I opened up a can of worms looking up "attached properties" this morning. I need another coffee. Here goes though - it appears that WPF introduced a few new key concepts, including Dependency Properties [and thus Dependency Objects, and Attached Properties].

Dependency Properties
Dependency Properties [called DPs from now on because I am lazy] were introduced throughout the WPF platform to help enable styling, databinding, animation and more. Quite literally, a DP depends on multiple different providers to determine it's value at any given point in time. The main reason behind this structure is to allow for rich functionality to be enabled directly from the markup [XAML] instead of relying on any procedural code.

Because of this 'dynamic determination of values', the WPF infrastructure must be setup to know and deal with DPs correctly. DPs have a very specific implementation structure that must be adhered to if one wishes to create a DP. They have a special naming convention ( [propertyName]Property --> MyDPProperty) and are public static. They must be registered so that WPF knows how to perform the callbacks when specific events occur on the property. I'm not going to go into the details of registering a DP as it is a little more in depth then I'd like to go today, but please see my links below for more info.

Excellent Reference for DPs [en.csharp-online.net]


Dependency Objects
If creating class that you wish to add DPs to, you must derive from DependencyObject so that WPF knows to enable it's property system services on it. The property system service is what WPF uses to calculate the value of a dependency property based on the multiple providers that may exist for a DP.

My focus for today is more on the DPs and attached properties, so I will leave any explaination about DO's short... namely because *I* haven't really read up on them in much detail ;)

MSDN DependencyObject
Support for multiple providers


Attached Properties
Finally... this is where I started. An Attached Property [AP] is a special form of a DP that can be attached to arbitrary objects that may not actually support the given property. Sounds weird right? It makes more sense when you look at the use of these properties to give styles to an element and it's associated children via "property value inheritance".

The term property value inheritance (or property inheritance for short) doesn't refer to traditional object oriented class-based inheritance, but rather the
flowing of property values down the element tree.

So in other words, if you set a property in a parent element, the children will also recieve the same value unless specifically specified in the child element. But what happens if you wish to set up this property inheritance on a parent object that doesn't natively support that property? Say you have a StackPanel and you want all children of the StackPanel to have the same FontSize? This is where attached properties because very useful.

< StackPanel TextElement.FontSize="22" >
< Button >Button1 </Button >
< Button >Button2 </Button >
< Button >Button3 </Button >
</ StackPanel >


All buttons will have FontSize of 22 since none have been overridden.

For this to work, an attached property provider must be used [in this case TextElement], which provides access to the get/set accessors for the attached property. Calls to the Get/SetValue methods are actually applied on the passed-in DependancyObject, rather then the current instance. [Ie. on TextElement, not on StackPanel].

The all too familiar property of Canvas.Left/Top on elements such as a Rectangle [if I am understanding this correctly] is actually an attached property then! This makes more sense now looking at how things are syntactically set up.

Again, there are more complexities with attached properties to go into but I am not going that deep today. Need to let all this sink in first :)

Attached Properties [en.csharp-online.net]

Monday, June 2, 2008

[C#] Using TooltipService

NOTE: As of Silverlight 2 Beta 2, this seems to be borked. Not sure why yet... I'll have a look later.

Today I was trying to add a simple tooltip to a bunch of small Canvas' in my Silverlight project. After a little digging I found that
  • (a) there is a .NET class called Tooltip which does this functionality for me and
  • (b) many controls lack a ToolTip property [such as TextBox, TextBlock, Canvas etc...]
To add a ToolTip to these controls, we are able to use the ToolTip attached property via ToolTipService. I am unfamiliar with attached properties, and I will be going over them in detail soon, however, for now I'm just going to drone on about using the ToolTipService in C# since it took me a little digging to find any kind of example [most were examples in XAML only].
  // Create a Tooltip
ToolTip nameTip = new ToolTip();

// Set the content [here I use text, but apparently it can be more complex]
nameTip.Content = "Testing ToolTipService";

// Use ToolTipService to attach the ToolTip to my Canvas.
ToolTipService.SetToolTip(myCanvas, nameTip);
Note, you may need to add the System.Windows.Controls reference to your project for this to work... I can't recall if that assembly is added by default when you create a project in VS2008.

ToolTipService Documentation

[Silverlight] Events on a Canvas with no set background color...

It's funny, both myself and another girl at work bumped into this same issue today while working on unrelated projects.

It seems that if you wish to set up events on a Canvas then you MUST set the Background property for the event to trigger when clicking ANYWHERE on the Canvas. If you do not setup a background, then the only time the event will be registered on the Canvas is if the user happens to click on a visible child of that Canvas.

By default the Canvas.Background property is set to null. Now, I imagine that this has the possibility to be rendered differently depending on what is interpreting the xaml. I noted that you can set the background to "transparent" [which is different then null], and while the Canvas will look identical to the default null value, the events will be correctly registered when you click anywhere within the canvas.

Canvas eventWrap = new Canvas();
eventWrap.Background = new SolidColorBrush(Colors.Transparent);
eventWrap.MouseEnter += new MouseEventHandler(showTooltip);
eventWrap.MouseLeave += new MouseEventHandler(hideTooltip);
eventWrap.Children.Add(myWeirdShapedPolygon);
This makes sense when you think about it, since it may be the case that you do not want the events to trigger when mousing over 'unused' portions of the canvas space. I just thought it was interesting to note that ((Background == null) != (Background == Colors.Transparent))