WPF NotifyIcon – Bugfix and WinForms Support

September 22nd, 2009

I released an update to my WPF NotifyIcon, which fixes two issues:

  • Interactive Popups should now fully support all control types.
  • The control can now be used in Windows Forms projects, if you need more functionality than the built-in component.

The solution now comes with an additional WinForms sample project, which shows how to display a WPF user control as an interactive popup.

image

     

    Download link and further information can be found on the control’s home page:
    http://www.hardcodet.net/wpf-notifyicon

    Tags:

    NetDrives 1.0.1 Fixes Settings Bug

    September 22nd, 2009

    I updated NetDrives, which fixes a registry issue when it comes to saving the application settings. Functionality is still the same, though.

    Project Page: http://www.hardcodet.net/netdrives

    Tags:

    Snippet Time: Helper Libraries for C# / WPF

    September 14th, 2009

    I just made a few minor updates to two libraries which assemble as set of helper classes for C# and WPF and thought: Why not share them? The libraries aren’t really intended to be used directly in your code, but you might find one or another helper method or snippet that might make a nice addition to your own toolbox :)

     

    Hardcodet.Commons (C#, .NET 3.5)

    Common helper classes and snippets (simple base classes, file management, weak events, extension methods etc.)

     

    Hardcodet.Wpf.Commons (C#, .NET 3.5)

    Stuff I commonly use in WPF projects, such as checking for design time, base classes for commands and converters, data binding helpers and other stuff.

     

    I’ll keep these libraries up-to-date, version history will be posted here.

     

    History:

    2009.09.14  Initial blog release

    Tags: , ,

    Linked Images in WPF Projects – Bad Idea?

    August 10th, 2009

    I discovered today that images that are included in a VS project as links are compiled differently than images that are stored as part of the project. This one might cost you quite some time, so here’s a few observations on the issue…

    Look at this simple project that contains two image files. One file is part of the project (physically stored in the Images folder), the other one added as a link. Both files have the same build action (Resource):

    image

     

    Now, if you declare these two images the same way, everything appears to be fine in the designer (both Visual Studio and Blend):

    <Window x:Class="WpfApplication2.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="150" Width="150">
        <StackPanel VerticalAlignment="Center">
          <Image Source="/Images/Add-Item.png" Stretch="None" />
          <Image Source="/Images/Remove-Item.png" Stretch="None"/>
        </StackPanel>
    </Window>

     

    image

     

    However, as soon as you compile and start your application, the linked image does not appear – obviously, the runtime could not resolve it at runtime:

     

    image

     

    I was quite surprised about this until I reverted to Reflector, which reveals that the linked image was embedded differently than the other one. Here’s the resource entries of the compiled WPF application:

    image

     

    As you can see, the linked image (Remove-Item.png) was included without the folder name, in lower case. Accordingly, I had to adjust the image source in XAML as follows:

    <Window x:Class="WpfApplication2.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="150" Width="150">
        <StackPanel VerticalAlignment="Center">
          <Image Source="/Images/Add-Item.png" Stretch="None" />
          <Image Source="/remove-item.png" Stretch="None"/>
        </StackPanel>
    </Window>

     

    This one works at runtime. BUT it breaks the designer. I’m not too happy about that one – whether a file is linked to or not should not affect the outcome of the compiled build all. I’m not too sure whether this was a conscious decision or a bug, but it sure is a major pain.

    Update: Microsoft confirmed this to be a bug, which should be fixed in the upcoming version of the framework / VS2010. So for now, linking is out of the picture for me.

    Tags:

    Finding Elements in the WPF Tree - Both Ways

    June 25th, 2009

    A while ago I posted a helper method to traverse a (visual or logical) tree in order to find an element’s parent of a given type. The corresponding blog entry is here.

    This time, I needed to search the other way: I wanted to find all descendants (direct or indirect childs) of a given element that match a given type. As a result, I came up with a complementary extension method that does the job for me:

    //get all TextBox controls within the grid:
    Grid container;
    IEnumerable<TextBox> editors = container.FindChildren<TextBox>();

     

    Usage Sample

    As a sample, let’s use a window dialog which contains several images:

    • Images that were pasted into a RichTextBox control.
    • Images that are part of the UI, nested within the control hierarchy of a ribbon.

    editor

     

    In order to find all these Image elements you can see on the screenshot, this will do:

    //start a the root (the window itself)
    Window window = this;
    foreach (Image img in window.FindChildren<Image>())
    {
      Console.WriteLine("Image source: " + img.Source);
    }

     

     

    …the above snippet produces the following output:

    Image source: pack://payload:,,wpf1,/Xaml/Image1.png

    Image source: pack://payload:,,wpf1,/Xaml/Image2.png

    Image source: pack://application:,,,/Shared/Images/Ribbon/Paste_32×32.png

    Image source: System.Windows.Media.Imaging.FormatConvertedBitmap

    Image source: System.Windows.Media.Imaging.FormatConvertedBitmap

    Image source: pack://application:,,,/Shared/Images/Ribbon/EditUndo.png

    Image source: pack://application:,,,/Shared/Images/Ribbon/EditRedo.png

    Image source: pack://application:,,,/Shared/Images/Ribbon/Bold.png

    Image source: System.Windows.Media.Imaging.BitmapFrameEncode

    […]

     

    Accordingly, in order to analyze only the contents of the rich text editor, just start on a lower level of the tree:

    //only examine the contents of the editor
    RichTextBox editor = this.txtContent;
    foreach (Image img in editor.FindChildren<Image>())
    {
      Console.WriteLine("Image source: " + img.Source);
    }

     

    Implementation


    (Download link at the end of the posting)

    
    /// <summary>
    /// Analyzes both visual and logical tree in order to find all elements
    /// of a given type that are descendants of the <paramref name="source"/>
    /// item.
    /// </summary>
    /// <typeparam name="T">The type of the queried items.</typeparam>
    /// <param name="source">The root element that marks the source of the
    /// search. If the source is already of the requested type, it will not
    /// be included in the result.</param>
    /// <returns>All descendants of <paramref name="source"/> that match the
    /// requested type.</returns>
    public static IEnumerable<T> FindChildren<T>(this DependencyObject source)
                                                 where T : DependencyObject
    {
      if (source != null)
      {
        var childs = GetChildObjects(source);
        foreach (DependencyObject child in childs)
        {
          //analyze if children match the requested type
          if (child != null && child is T)
          {
            yield return (T) child;
          }
    
          //recurse tree
          foreach (T descendant in FindChildren<T>(child))
          {
            yield return descendant;
          }
        }
      }
    }
    
    /// <summary>
    /// This method is an alternative to WPF's
    /// <see cref="VisualTreeHelper.GetChild"/> method, which also
    /// supports content elements. Do note, that for content elements,
    /// this method falls back to the logical tree of the element.
    /// </summary>
    /// <param name="parent">The item to be processed.</param>
    /// <returns>The submitted item's child elements, if available.</returns>
    public static IEnumerable<DependencyObject> GetChildObjects(
                                                this DependencyObject parent)
    {
      if (parent == null) yield break;
      
    
      if (parent is ContentElement || parent is FrameworkElement)
      {
        //use the logical tree for content / framework elements
        foreach (object obj in LogicalTreeHelper.GetChildren(parent))
        {
          var depObj = obj as DependencyObject;
          if (depObj != null) yield return (DependencyObject) obj;
        }
      }
      else
      {
        //use the visual tree per default
        int count = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < count; i++)
        {
          yield return VisualTreeHelper.GetChild(parent, i);
        }
      }
    }
    

     

    For your convenience, I’ve put together a simple helper class that contains the helper methods to search for both children and parent elements in the tree:

    http://www.hardcodet.net/uploads/2009/06/UIHelper.cs

     

    Happy coding :)

    Tags:

    Beginner’s Tutorial: 3D Line and Border Effects in XAML

    May 28th, 2009

    This mini-tutorial might be for you if you’re having troubles finding the right line colors to achieve simple 3D effects like these:

    linesamples

     

    The solution to this very problem is actually pretty simple, and it always takes the same three ingredients:

    • A white line
    • A black line
    • Reduced opacity

    Basically, to get an edged line on a green background, you don’t need to fiddle with different shades of green. Just use white and black lines and play with the opacity. Here’s the settings in Blend for one of the white lines in the above screenshot:

    highlighted-line-settings

     

    …and this is the corresponding XAML for the two vertical lines:

    <Grid Background="Green">
      <Path Stretch="Fill" Stroke="#5A000000" Margin="25,62,0,0"
            Width="1" Height="100" Data="M130,176 L130,303.03543"/>
      <Path Stretch="Fill" Stroke="#5AFFFFFF" Margin="26,62,0,0"
            Width="1" Height="100" Data="M130,176 L130,303.03543"/>
    </Grid>

     

    Tip: Hiding Blend’s Handles

    If you’re trying to format a line, Blend’s handles don’t help much, as the basically hide the whole content:

    blend-handles

    However - you can easily hide / show them by pressing the F9 button.

     

    Tutorial: Creating a 3D Toggle Button Style

    Another usage of white and black lines is a 3D effect for borders. Let’s put this to action and create a reusable style that can be applied to a ToggleButton control:

    toggle-buttons 

    Rather than joining four lines for each button state, I’ll use two Border controls with the same dimensions for each state, taking advantage that the BorderThickness property can be set independently for every edge. Here’s the borders for the unchecked state:

    <Grid x:Name="uncheckedState">
      <Border BorderBrush="#49FFFFFF" BorderThickness="1,1,0,0"/>
      <Border BorderBrush="#49000000" BorderThickness="0,0,1,1"/>
    </Grid>

     

    …and here’s the borders for the checked state. Note that its Visibility property of the surrounding grid is set to Collapsed in order to hide the borders:

    <Grid x:Name="checkedState" Visibility="Collapsed">
      <Border BorderBrush="#49000000" BorderThickness="1,1,0,0"/>
      <Border BorderBrush="#49FFFFFF" BorderThickness="0,0,1,1"/>
    </Grid>  

     

     

    I put these borders together in a simple style, which uses a trigger to switch the visibility of the two borders as soon as the IsChecked property of the ToggleButton changes:

    <Style TargetType="{x:Type ToggleButton}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ToggleButton}">
            <Grid x:Name="mainGrid" Margin="0,0,1,1">
    
              <Grid x:Name="uncheckedState">
                <Border BorderBrush="#49FFFFFF" BorderThickness="1,1,0,0"/>
                <Border BorderBrush="#49000000" BorderThickness="0,0,1,1"/>
              </Grid>
    
              <Grid x:Name="checkedState" Visibility="Collapsed">
                <Border BorderBrush="#49000000" BorderThickness="1,1,0,0"/>
                <Border BorderBrush="#49FFFFFF" BorderThickness="0,0,1,1"/>
              </Grid>   
    
              <!--
                WPF needs a background to toggle IsChecked
                if the ContentPresenter does not fill the whole area
              -->
              <Border Background="#00000000" />
    
              <ContentPresenter VerticalAlignment="Center"
                                HorizontalAlignment="Center" />
    
            </Grid>
    
            <!-- triggers toggle visual appearance -->
            <ControlTemplate.Triggers>
              <Trigger Property="IsChecked" Value="True">
                <Setter TargetName="checkedState"
                        Property="Visibility"
                        Value="Visible" />
                <Setter TargetName="uncheckedState"
                        Property="Visibility"
                        Value="Collapsed" />
                <Setter TargetName="mainGrid"
                        Property="Margin"
                        Value="1,1,0,0"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

     

     

    With the style in place, you can easily declare a ToggleButton like this:

    <ToggleButton Width="100" Height="24" Content="hello world" />

    Tags: