Archive for the ‘Uncategorized’ Category

Path Data, Prefixes and Known Colors

September 24, 2008

I previously wrote about some fixes I made to the Baml Viewer addin for Reflector. As always happens with these kinds of things, one thing led to another and I ended up finding a few more issues and felt compelled to debug/fix them. Tonight I checked in a few more changes:

  • Xml Namespace Mapping Prefixes – While debugging the first set of issues I noticed that the xml namespace mappings weren’t being included. So when a type name was displayed it excluded the prefix – e.g. ButtonChrome instead of theme:ButtonChrome.
  • PathData – A reader posted a comment mentioning that path data was always displayed as “???”. I guess this was a placeholder but the functionality was never implemented. This was a bit involved but the baml viewer will now display the path markup notation for the path data geometry. Note, the original value won’t necessarily round trip to the exact original markup but the resulting path should be the same. So if you used m (for a relative move) instead of M (for an absolute move), you may notice that M is output instead. The absolute points were likely calculated when the original path markup was parsed so the output will contain M (i.e. absolute offsets) and the points will be absolute instead of relative.
  • Known Colors – Solid color brush values are handled specially by the baml compiler. Previously the only known color that was handled was transparent. All other known colors were output using their ARGB values – incidentally without the leading # so if you tried to use the xaml it would give you an error. The baml viewer will now map these known colors back to the known color name.

I hope I don’t find any more issues :-) but if you find something interesting I may try to look into it as time allows.

Baml Viewer Fixes

September 23, 2008

I use Reflector everyday and I’ve always wanted to give something back to Lutz for making this great utility. One of the things I use within Reflector is the BamlViewer addin but it had some problems correctly displaying all the baml I’ve tried to view. In some cases it even crashed while parsing the resource.

Since the code was in CodePlex, I decided to try and fix these issues myself. Having done so I wanted to get these incorporated into the addin so someone else encountering the same issues could get the fixes. In order to check in these changes though you have to be a developer on the project so I contacted Lutz to see if he wanted to check them in. Reflector has recently been handed over to RedGate Software so he referred me to James Moore who aside from being a coordinator on that project also heads up the .Net developer tools division at RedGate. He kindly agreed to add me on as a developer to that project so this morning I checked in my fixes.

One more change that I’d like to make is that I’d like to get it to support displaying the xml namespace prefix. I have made some changes locally to address this so when I get a chance I’ll test it out more thoroughly, clean it up and get that checked in as well.

Accessing Enum members in Xaml

September 19, 2008

Sacha posted a nice article on how to get friendly names for enums. I’ve seen this kind of approach before using the Description attribute. One of the things that he does though is create a static method to obtain the list of enum members. You can however actually get the list with pure xaml as follows:

<ObjectDataProvider MethodName=”GetValues”
               ObjectType=”{x:Type sys:Enum}”
               x:Key=”DayOfWeekValues”>
    <ObjectDataProvider.MethodParameters>
        <x:Type TypeName=”sys:DayOfWeek” />
    </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

And then you can wire it up to a combobox:

<ComboBox x:Name=”cboDayOfWeek” 
  ItemsSource=”{Binding Source={StaticResource DayOfWeekValues}}” />

The only problem though is that its verbose (as well as a little heavy for something that is just meant to return a static list). When I write a test app for a control I’m writing I tend to end up having a lot of these and it ends up cluttering the xaml. I was thinking about it and an alternative approach which combines the above as well as takes Sacha’s issue into account would be to write a markup extension that combines all this together.

    /// <summary>
    /// Markup extension that provides a list of the members of a given enum.
    /// </summary>
    public class EnumListExtension : MarkupExtension
    {
        #region Member Variables

 

        private Type _enumType;
        private bool _asString;

 

        #endregion //Member Variables

 

        #region Constructor
        /// <summary>
        /// Initializes a new <see cref=”EnumListExtension”/>
        /// </summary>
        public EnumListExtension()
        {
        }

 

        /// <summary>
        /// Initializes a new <see cref=”EnumListExtension”/>
        /// </summary>
        /// <param name=”enumType”>The type of enum whose members are to be returned.</param>
        public EnumListExtension(Type enumType)
        {
            this.EnumType = enumType;
        }
        #endregion //Constructor

 

        #region Properties
        /// <summary>
        /// Gets/sets the type of enumeration to return
        /// </summary>
        public Type EnumType
        {
            get { return this._enumType; }
            set
            {
                if (value != this._enumType)
                {
                    if (null != value)
                    {
                        Type enumType = Nullable.GetUnderlyingType(value) ?? value;

 

                        if (enumType.IsEnum == false)
                            throw new ArgumentException(“Type must be for an Enum.”);
                    }

 

                    this._enumType = value;
                }
            }
        }

 

        /// <summary>
        /// Gets/sets a value indicating whether to display the enumeration members as strings using the Description on the member if available.
        /// </summary>
        public bool AsString
        {
            get { return this._asString; }
            set { this._asString = value; }
        }
        #endregion //Properties

 

        #region Base class overrides
        /// <summary>
        /// Returns a list of items for the specified <see cref=”EnumType”/>. Depending on the <see cref=”AsString”/> property, the
        /// items will be returned as the enum member value or as strings.
        /// </summary>
        /// <param name=”serviceProvider”>An object that provides services for the markup extension.</param>
        /// <returns></returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (null == this._enumType)
                throw new InvalidOperationException(“The EnumType must be specified.”);

 

            Type actualEnumType = Nullable.GetUnderlyingType(this._enumType) ?? this._enumType;
            Array enumValues = Enum.GetValues(actualEnumType);

 

            // if the object itself is to be returned then just use GetValues
            //
            if (this._asString == false)
            {
                if (actualEnumType == this._enumType)
                    return enumValues;

 

                Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1);
                enumValues.CopyTo(tempArray, 1);
                return tempArray;
            }

 

            List<string> items = new List<string>();

 

            if (actualEnumType != this._enumType)
                items.Add(null);

 

            // otherwise we must process the list
            foreach (object item in Enum.GetValues(this._enumType))
            {
                string itemString = item.ToString();
                FieldInfo field = this._enumType.GetField(itemString);
                object[] attribs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);

 

                if (null != attribs && attribs.Length > 0)
                    itemString = ((DescriptionAttribute)attribs[0]).Description;

 

                items.Add(itemString);
            }

 

            return items.ToArray();
        }
        #endregion //Base class overrides
    }

The markup extension has a Type property that can be used to indicate the enum type for which it should obtain the list. If you want it to return strings as opposed to the actual enum values and take the Description attribute into account, you just set the AsString property to true. So now the hookup is much simpler:

<ComboBox x:Name=”cboDayOfWeek”
  ItemsSource=”{Binding Source={local:EnumList {x:Type sys:DayOfWeek}}}” />

 

Note: I updated this code to use the DisplayName instead of the DescriptionAttribute after Mike Brown correctly pointed out that DisplayName is a more appropriate attribute for this scenario.

Updated: I reverted back to using the Description attribute since the DisplayNameAttribute’s usage does not allow its use on Fields. Thanks to John for pointing this out.

Hit Testing in WPF

September 16, 2008

There’s a lot that can be written about hit testing in WPF so I won’t try to cover everything but there are some subtleties that bear mentioning. A common issue that I see people encounter is that fact that the default background for many elements is null and null (at least in terms of hit testing) is treated separately from Transparent. Take the following snippet for example.

<Page
  <Page.Resources>
      <Style TargetType=”{x:Type Grid}”>
          <Style.Triggers>
              <Trigger Property=”IsMouseOver” Value=”True”>
                  <Setter Property=”Background” Value=”Yellow” />
              </Trigger>
          </Style.Triggers>
      </Style>
  </Page.Resources>
  <Grid> 
      <TextBlock
          Background=”Red”
          Text=”Test”
          TextAlignment=”Center”
          HorizontalAlignment=”Center”
          VerticalAlignment=”Center”
          Width=”100″ />
  </Grid>
</Page>
 
There is a trigger for the Grid that changes its Background to yellow when IsMouseOver is true. If you run this and move the mouse over the Grid without going over the TextBlock, the background of the Grid will remain the same. However, once you move the mouse over the TextBlock, the background of the Grid will change. Then something interesting happens – once the mouse leaves the TextBlock buts remains within the Grid the background of the Grid will remain Yellow. This basically comes back to the fact that the default background of the Grid is null. If you were to add a setter to the Style set the Background to Transparent (don’t set it explicitly or the mouse over won’t work since you’ll be providing a local value which will take predence over the style trigger) then the background would have changed to yellow as soon as the mouse entered the Grid.
 
     <Style TargetType=”{x:Type Grid}”>
          <Setter Property=”Background” Value=”Transparent” />
          <Style.Triggers>
              <Trigger Property=”IsMouseOver” Value=”True”>
                  <Setter Property=”Background” Value=”Yellow” />
              </Trigger>
          </Style.Triggers>
      </Style>

An interesting thing to note here is that the TextBlock doesn’t have this issue. So if you were to modify the original source and explicitly set the TextBlock’s Background to {x:Null} or not set it (since it defaults to null) and rerun the original test, you will find that the background of the Grid still changes to yellow when you go over the TextBlock (and not just when you go over the actual rendered text). The reason that this occurs is because the TextBlock explicitly overrides UIElement.HitTestCore and returns true if the specified point is within its rect. There are actually a few other elements that do this as well including ScrollViewer and InkCanvas. For TextBlock I think the main reason is that you probably don’t want the IsMouseOver changing as you move across the text in between characters but this is just a guess.

Another property that affects hit testing in WPF is the IsHitTestVisible. This property determines if the element and its descendants should be hidden from hit testing. I phrased it in this way because if you set IsHitTestVisible to false on the Grid in the sample above, it wouldn’t matter what the IsHitTestVisible state of the descendants is set to since the hit test that is performed to evaluate the IsMouseOver state is going to skip the Grid element and not traverse into its children.

Next time I’ll get to the real reason I started writing about hit testing today – to discuss the methods available for performing hit testing in code.

First Post

December 9, 2007

I’ve been meaning to blog for a long time but I could never find the time. Recently I had the opportunity to work with Josh Smith and Karl Shifflett on Mole II, a Visual Studio Visualizer for inspecting WPF objects, and I decided to make the time.

My available time nowadays is pretty limited – my wife and I have a young daughter with a very late sleeping schedule – that occupies much of what would previously have been my free time. I wouldn’t trade it for the world but it does mean that the time I can devote to a blog will be limited. When I do post, I expect that the majority of my posts will be related to C#, .NET, VS, WinForms and WPF as those are the areas I concentrate on the most. I sometimes help my wife with some PHP work so I may on occassion go off on a tangents into that area although it is far from my current areas of expertise.


Follow

Get every new post delivered to your Inbox.