Hallo! Ich bin Timo.

I develop software for Windows and Windows Phone.
Wieder da!

Wieder da!

Frohe Ostern!

Ich wünsche frohe Ostern gehabt zu haben. Ich habe mich zur Abwechslung mal wieder entschlossen einen Blog zu führen. Dieses Mal in Deutsch. Das erste Problem: Heißt es der Blog oder das Blog? Ich werde einfach  den Artikel verwenden, der mir gerade am besten gefällt und mich bemühen eine gleichmäßige Mischung zu erreichen.

Viel Vergnügen!

13. April 2012 0 comments Read More
WPF Tip of the Day: Inner Shadow Effect without BitmapEffects

WPF Tip of the Day: Inner Shadow Effect without BitmapEffects

I wanted to create a Border element displaying an inner shadow and an outer glow at the same time. I had to find out that this task is not that easy. WPF doesn’t support an inner shadow effect or an outer glow effect. In addition BitmapEffects are slow and deprecated in .NET 4. So I had to  look for another solution. Here is how I managed to get it done:

<Border CornerRadius="5"  BorderBrush="{StaticResource OuterBorder}" BorderThickness="1">
    <Border.Effect>
        <DropShadowEffect BlurRadius="2" Color="LightGray" Opacity="60" Direction="270" ShadowDepth="0.5" />
    </Border.Effect>

    <Grid>
        <Border x:Name="Mask" CornerRadius="5" Background="{StaticResource OuterBorderBackground}" />
    <Grid>
        <Grid.OpacityMask>
            <VisualBrush Visual="{Binding ElementName=Mask}"/>
        </Grid.OpacityMask>
            <Border CornerRadius="5" BorderThickness="1" Margin="-1" BorderBrush="{StaticResource OuterBorder}" ClipToBounds="True">
                <Border.Effect>
                    <DropShadowEffect BlurRadius="7" Color="Black" Direction="0" ShadowDepth="0" />
                </Border.Effect>
            </Border>
        </Grid>
    </Grid>                       

</Border>

The trick is to utilize the DropShadowEffect (instead of the old DropShadowBitmapEffect). The outer Border element defines a light gray drop shadow which shines around the border if the ShadowDepth property is set to 0.

To achieve the inner shadow the same procedure is used. One exception, the border used for the inner shadow does not contain a Background. This leads to a shadow reaching into both directions of the Border. In the next step the Outer Shadow must be clipped off. Another Border element is defined as a sibling to the inner-shadow-border inside a grid. this border has the same dimensions as the shadow border and is defined as an opacity mask to the grid surrounding both borders.

14. September 2010 0 comments Read More
WPF Tip of the Day: Animate a Window

WPF Tip of the Day: Animate a Window

Here is an interesting topic I found about window animation in WPF. Credits go to Chango V. from Microsoft who posted this solution here: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/fd178a78-433f-4879-9b85-a90bbb3c7282

Quote:

Window resizing is a complex problem. Its smoothness depends on having good integration between multiple layers in the system. WPF uses DirectX for rendering, and it responds to WM_PAINT asynchronously. This is one of the fundamental causes for resizing “choppiness”. There will be some incremental improvements made for window resizing at the OS level in future releases/SPs that help WPF in particular.

Another potential source of unsmoothness is the Window class API. If you try to animate more than one of Top,Left,Width,Height at the same time, we’ll be making multiple calls to the native MoveWindow() function, with coordinates that are not smoothly changing. We are looking into this problem now and will probably publish a workaround sample. You can implement this workaround easily yourself:
Declare a DependencyProperty on a class derived from Window, called WindowRect. In the property changed callback, call the Win32 MoveWindow() function with Left,Top,ActualWidth,ActualHeight as parameters.

Set up your animation like this:

 

 

<Storyboard x:Key="sb" Storyboard.TargetName="win">
    <RectAnimation Storyboard.TargetProperty="WindowRect" By="0, -200, 200, 0" Duration="0:0:4" />
</Storyboard>

Well, I wanted to have the window resized in its width, to expand for details display and contract back after removing a selection.. this was not possible with this approach because the By Property of the Storyboard doesn’t allow a negative value for the Width and Height Parameters (It’s a Rect!). But it pushed me into the right direction. So here is what I did. A lot code behind, but it works:

XAML of the MainWindow:

<Window x:Class="Timos_Window_Resizer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Timos Resizing Window" Height="350" Width="300"
        WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
        x:Name="TimosResizingWindow">
    <Grid>
        <StackPanel>
        <Button Click="Expand_Click" Height="50" Margin="10">Expand to the left</Button>
        <Button Click="Contract_Click"  Height="50" Margin="10" >Contract from left</Button>
        </StackPanel> 

    </Grid>
</Window>

C# code behind of the Window:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Animation;

namespace Timos_Window_Resizer
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // In constructor subscribe to the Change even of the WindowRect DependencyProperty
            DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(WindowRectProperty, typeof(MainWindow));
            if (dpd != null)
            {
                dpd.AddValueChanged(this, delegate
                {
                    ResizeWindow(WindowRect);
                });
            }
        }

        #region Button Events
        public void Expand_Click(object sender, RoutedEventArgs e)
        {
            // Initialize WindowRect to the current size and position
            WindowRect = new Rect(Left, Top, ActualWidth, ActualHeight);

            // Define desired size
            Rect expandedRect = new Rect(Left, Top, ActualWidth + 200, ActualHeight);

            // Animated Resizing starts here
            StartStoryBoard(WindowRect, expandedRect);
        }

        public void Contract_Click(object sender, RoutedEventArgs e)
        {
            // Initialize WindowRect to the current size and position
            WindowRect = new Rect(Left, Top, ActualWidth, ActualHeight);

            // Define desired size - do not get below 0
            Rect contractedRect = new Rect(Left, Top, Math.Max(100, ActualWidth - 200), ActualHeight);

            // Animated Resizing starts here
            StartStoryBoard(WindowRect, contractedRect);
        }
        #endregion

        #region Window Resizing

        #region Dependency Property WindowRect
        public Rect WindowRect
        {
            get
            {
                return (Rect)GetValue(WindowRectProperty);
            }
            set
            {
                SetValue(WindowRectProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for WindowRect.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WindowRectProperty =
            DependencyProperty.Register("WindowRect", typeof(Rect), typeof(MainWindow), new UIPropertyMetadata(new Rect(0, 0, 0, 0)));
        #endregion

        #region Win32 Import of ModeWindow for better resizing without flickering
        [DllImport("user32.dll", SetLastError = true)]
        internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
        #endregion

        /// <summary>
        /// Resizes the window to the desired Rect
        /// Called when WindowRect DependencyProperty changes
        /// </summary>
        /// <param name="value">The target Rect containing size and Position</param>
        private void ResizeWindow(Rect value)
        {
            IntPtr windowPtr = new WindowInteropHelper(this).Handle;
            MoveWindow(windowPtr, (int)value.Left, (int)value.Top, (int)value.Width, (int)value.Height, true);
        }

        #endregion

        #region Resize Animation
        private void StartStoryBoard(Rect currentRect, Rect targetRect)
        {
            // Set up animation duration and behavior
            RectAnimation rectAnimation = new RectAnimation();
            rectAnimation.Duration = TimeSpan.FromSeconds(0.5);
            rectAnimation.FillBehavior = FillBehavior.HoldEnd;

            // Set the From and To properties of the animation.
            rectAnimation.From = currentRect;
            rectAnimation.To = targetRect;

            // Set the Target of the animation to the Window
            // Remember to define a name in XAML
            Storyboard.SetTargetName(rectAnimation, "TimosResizingWindow");
            Storyboard.SetTargetProperty(rectAnimation, new PropertyPath(WindowRectProperty));

            // Create a storyboard to apply the animation.
            Storyboard storyBoard = new Storyboard();
            storyBoard.Children.Add(rectAnimation);

            storyBoard.Begin(this);
        }
        #endregion
    }
}

Here is the sample project. Download: Timos_Window_Resizer.zip

8. September 2010 1 comment Read More
Reposted: Assign a Global Hotkey in C#

Reposted: Assign a Global Hotkey in C#

I had blogs before. sometimes I stumble over some old posts. the Reposted category is the place where I bring back what was interesting.

I was searching for a way to hide a dialog completely from the user and make it visible using a predefined key combination.
After some research I found one way to implement this is using invocation of native code. Here is a short example of the source code I used to make the form appear by pressing the Ctrl+Alt+L hotkey.

//Required for the example
using System.Runtime.InteropServices;

#region Hotkey
private const byte ModAlt = 1, ModControl = 2, ModShift = 4, ModWin = 8;

[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

protected override void WndProc(ref Message m)
{
    if (m.Msg == 0x0312) //This is a Hotkey Message
    {
        this.Visible = !this.Visible;
    }

    base.WndProc(ref m);
}

private void RegisterKey()
{
    byte modifiers = 0;
    modifiers += ModControl; //Add Ctrl
    modifiers += ModAlt; //Add Alt 

    byte charcode = (byte)'L';

    //You can check if the registration was successfull with the return value
    //If it returns false the HotKey is invalid or in use
    bool success = RegisterHotKey(this.Handle, this.GetType().GetHashCode(), modifiers, charcode);
}

private void UnregisterKey()
{
    UnregisterHotKey(this.Handle, this.GetType().GetHashCode());
}
#endregion
1. September 2010 0 comments Read More
WPF Tip of the Day: Draggable Windows

WPF Tip of the Day: Draggable Windows

and This post is the continuation of my last post about Glass Windows. Dragging Windows will of course work on any window, regardless of any code from my last example.

This is the window from my last example (Project zip here). Notice the large, transparent top area. This large area consists of two parts: the title bar of the window (like in every default window) and below that a transparent area which we defined in our window XAML. By default the title bar of a window can be used to drag the window around on the screen. If you try this on the transparent area below, nothing will happen. There is no border between the title bar and the transparent area which makes it even harder for the user to know where the draggable region starts. In this post I will show you how to make the entire transparent area draggable.

First the easy part; dragging the window. It’s indeed very simple to implement because the WPF Window class delivers a handy function to achieve this: DragMove();

In XAML add the MouseLeftButtonDown event to the window:

<APICodePack:GlassWindow x:Class="Timos_GlassWindow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:APICodePack="clr-namespace:Microsoft.WindowsAPICodePack.Shell;assembly=Microsoft.WindowsAPICodePack.Shell"
        Title="Timos Glass Window" MouseLeftButtonDown="GlassWindow_MouseLeftButtonDown" Loaded="GlassWindow_Loaded">
    <Grid>
     ...
    </Grid>
</APICodePack:GlassWindow>

Next open the code behind of the window and add the following event handling code:

private void GlassWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    this.DragMove();
}

That’s it. Compile and try. You will see your entire window is draggable. No matter where you try, transparent or solid background, if you hit a control or an empty area, dragging just works everywhere. But that was not what we wanted. Only transparent areas should be draggable. So how do we stop the solid background areas from being dragged? Simple!

Add another event handler to your code behind:

private void DenyMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    e.Handled = true;
}

What this event does is catching the MouseLeftButtonDown event and defines that it was handled and it does not need to raise any event handling code anymore. So to stop the dragging we need to have the DenyMouseLeftButtonDown handler called prior to the GlassWindow_MouseLeftButtonDown handler. Thanks to bubbling of events in WPF. Bubbling means if an event is not handled in a control, it moves up to the parent element in the visual tree and if it ‘s not handled there it moves further up the visual tree until the root element (e.g. a Window) is reached.

The DragMove call is made on the Window level. To make our code work we just need to raise the DenyMouseLeftButtonDown event on a level below the window on the visual tree, meaning an element within the window. We will use the Border element with the white background. This is our top most element which should not be dragged. Simply add the MouseLeftButtonDown event and use the existing handler. Her is the full XAML of the Window, see the second Border:

<APICodePack:GlassWindow x:Class="Timos_GlassWindow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:APICodePack="clr-namespace:Microsoft.WindowsAPICodePack.Shell;assembly=Microsoft.WindowsAPICodePack.Shell"
        Title="Timos Glass Window" MouseLeftButtonDown="GlassWindow_MouseLeftButtonDown" Loaded="GlassWindow_Loaded">
    <Grid>
        <Border Background="Transparent" Height="50" HorizontalAlignment="Stretch" VerticalAlignment="Top">
            <TextBlock Text="This is transparent content." />
        </Border>
        <Border Background="White" MouseLeftButtonDown="DenyMouseLeftButtonDown" Margin="0,50,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <TextBlock Text="This is solid content." />
        </Border>
    </Grid>
</APICodePack:GlassWindow>

Now compile and run. Try it and see, the transparent top area is draggable, the white background area does not respond to drag actions. Done!

Download the source code here: Timos_DraggableGlassWindow.zip

1. September 2010 0 comments Read More
WPF Tip of the Day: Glass Windows

WPF Tip of the Day: Glass Windows

Windows 7 (as well as Windows Vista, but who cares?) supports transparent, Aero style, windows. More and more applications make use of these transparency effects. Here is ho to do it in WPF:

First what wee need to create this is the Windows API CodePack, which is free and can be downloaded here: http://code.msdn.microsoft.com/WindowsAPICodePack

It has many features to make use of the Windows 7 API. I will only target transparent windows for now. What it actually does is wrapping existing Windows API Features to be used within .NET applications. This means we will not need any knowledge about the Windows API. Using Native code from .NET Languages can become very complicated.

One note regarding Backwards compatibility: If you want your application to be compatible to Windows XP, you should validate the OS Version (or its features) before calling a feature of the API CodePack. There are some best practices on how to check the Version number. Pleases refer to the documentation and the discussion area under the above link.

To begin create a new WPF Application project or use your existing. Add a Reference to the downloaded libraries of the Codepack:

  • Microsoft.WindowsAPICodePack
  • Microsoft.WindowsAPICodePack.Shell

Next you’ll need to create a WPF Window (or use and existing) in your project and modify the source XAML code.

 

<APICodePack:GlassWindow x:Class="Timos_GlassWindow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:APICodePack="clr-namespace:Microsoft.WindowsAPICodePack.Shell;assembly=Microsoft.WindowsAPICodePack.Shell"
        Title="Timos Glass Window" Loaded="GlassWindow_Loaded">
    <Grid>
    </Grid>
</APICodePack:GlassWindow>

To get the glass effect we have to derive our Window class from GlassWindow instead of deriving from Window. To do so add the line

xmlns:APICodePack="clr-namespace:Microsoft.WindowsAPICodePack.Shell;assembly=Microsoft.WindowsAPICodePack.Shell"

to the namespace definition section. Thats already done in the code above.

Next modify the root tag. Change

<Window></Window>

to

<APICodePack:GlassWindow></APICodePack:GlassWindow>

Notice the GlassWindow_Loaded event. This event will help us set up the glass rendering in code behind. Switch to the code behind of your window.

First thing here is to remove the : Window after the class declaration. We derived from GlassWindow in XAML and because the code behind class is a partial part we don’t need to declare this again here. Here is the code:

using Microsoft.WindowsAPICodePack.Shell;
using System;
using System.Windows;

namespace Timos_GlassWindow
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void GlassWindow_Loaded(object sender, RoutedEventArgs e)
        {
            if (IsVistaOrHigher())  // this should work on Vista and 7
            {
                // This event is to detect when the user switches aero off
                // e.g. in control panel appearance options
                AeroGlassCompositionChanged += Shell_AeroGlassCompositionChanged;

                // Trying to enable aero glass
                try
                {
                    // Is Aero Glass switched on?
                    if (AeroGlassCompositionEnabled)
                    {
                        // Enable Glass
                        SetAeroGlassTransparency();
                    }
                    else // Aero Glass is switched off
                    {
                        // Set UI to non-aero mode
                    }
                }
                catch (Exception ex)
                {
                    // Aero could not be initialized... continuing without it
                    // Here you could let the user know that an error occured.
                    System.Diagnostics.Debug.WriteLine("Error enabling Aero Glass: " + ex.ToString());
                }
            }
            else // XP or older
            {
                // Set UI to non-aero mode
            }
        }

        private bool IsVistaOrHigher()
        {
            // There are more posibilities to check for the correct version.
            // This might not be the best.
            return (Environment.OSVersion.Version.Major >= 6);
        }

        void Shell_AeroGlassCompositionChanged(object sender, AeroGlassCompositionChangedEvenArgs e)
        {
            // When the desktop composition mode changes the background color
            // and window exclusion must be changed appropriately.
            if (e.GlassAvailable)
            {
                ResetAreoGlass();  // doesn't work without reset first!
                SetAeroGlassTransparency();
                InvalidateVisual();
            }
            else
            {
                // Set UI to non-aero mode
            }
        }
    }
}

The magic happens in the GlassWindow_Loaded method. We begin checking for the OS version. Next we register an event (offered by the API CodePack) to get notified if the user switches Aero Glass on or off while our application is running. This gives us the chance to define two different layout options for the window. We could for instance define a nice gradient as background when Aero Glass is disabled. The property AeroGlassCompositionEnabled of the GlassWindow base class lets us know if Aero Glass is currently enabled. When calling SetAeroGlassTransparency(); Aero Glass is finally enabled.

 

You can now add content to your GlassWindow. To create solid Background content simply define a background color or use a Border. To define transparent areas, define the Background color as Transparent.

Sample content of the GlassWindow:

<Border Background="Transparent" Height="50" HorizontalAlignment="Stretch" VerticalAlignment="Top">
    <TextBlock Text="This is transparent content." />
</Border>
<Border Background="White" Margin="0,50,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <TextBlock Text="This is solid content." />
</Border>

In the next part of this post I will show how to make the transparent parts draggable. Stay tuned..-

30. August 2010 0 comments Read More
WPF Tip of the Day: Nice Header Style

WPF Tip of the Day: Nice Header Style

This is a really nice Border with a label in it. The label has a small shadow, which makes it even nicer to look at.

Try it. Here are the styles:

Here is a really cool Brush for the Background:

<LinearGradientBrush x:Key="Background" StartPoint="0,0" EndPoint="0,1">
    <GradientStop Color="#FF8CCEF9" Offset="0" />
    <GradientStop Color="#FF4B93C8" Offset="1" />
</LinearGradientBrush>

This is a shadowed label style for the headline:

<Style x:Key="HeadlineLabelStyle" TargetType="{x:Type Label}">
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="FontSize" Value="25" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Label}">
                <Grid>
                    <TextBlock x:Name="Shadow" Text="{TemplateBinding Content}" Foreground="#FF6AA4CB" />
                    <TextBlock x:Name="Text" Text="{TemplateBinding Content}" Margin="0,1,0,0" Foreground="White" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
27. August 2010 0 comments Read More