Monday, February 28, 2011

WPF - Parent & Child Window with Parent Window Grayed Out and Fade Animation


  
This example shows how to create parent/child windows with the parent window grayed out. The opacity is set with a fade in/out animation.

To recreate this example:

Step 1
Create a new project in Visual Studio and add the following items:
  1. Class named TransparentAdorner.cs
  2. Window named ParentWindow.xaml
  3. Window named ChildWindow.xaml

Step 2
Copy code to the new files:

TransparentAdorner.cs

using System.Windows;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace ParentChildWindows
{
    public class TransparentAdorner : Adorner
    {
        public TransparentAdorner(UIElement adornedElement) : base(adornedElement)
        {

        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            SolidColorBrush brush = new SolidColorBrush();
            brush.Color = Colors.Transparent;

            drawingContext.DrawRectangle(brush, null, new Rect(new Point(0, 0), DesiredSize));
            base.OnRender(drawingContext);
        }
    }
}

ChildWindow.xaml
<Window x:Class="ParentChildWindows.ChildWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ChildWindow" Height="300" Width="300" WindowStartupLocation="CenterOwner" Closing="Window_Closing">
    <Grid>
        
    </Grid>
</Window>

ChildWindow.xaml.cs
using System.Windows;

namespace ParentChildWindows
{
    public partial class ChildWindow : Window
    {
        private ParentWindow _ParentWindow;

        public ChildWindow(ParentWindow parentWindow)
        {
            InitializeComponent();
            _ParentWindow = parentWindow;
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            _ParentWindow.IsActiveWin = true;
        }
    }
}

ParentWindow.xaml
<Window x:Class="ParentChildWindows.ParentWindow"
<Window x:Class="ParentChildWindows.ParentWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ParentWindow" Height="600" Width="600" Loaded="Window_Loaded">

    <Border Name="borderWindow">
        <Grid>
            <Button Content="Open Child Window" Name="butOpenChildWindow" 
                    VerticalAlignment="Top" Width="150" Click="butOpenChildWindow_Click" />
        </Grid>
    </Border>
</Window>

ParentWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace ParentChildWindows
{
    public partial class ParentWindow : Window
    {
        enum FadeDirection
        {
            FadeIn,
            FadeOut
        }

        private TransparentAdorner _WindowAdorner;

        private bool isActiveWin = true;
        public bool IsActiveWin
        {
            get { return isActiveWin; }

            set
            {
                if (isActiveWin != value)
                {
                    isActiveWin = value;

                    if (isActiveWin == true)
                        DettachWindowAdorner();
                    else
                        AttachWindowAdorner();
                }
            }
        }

        public ParentWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            _WindowAdorner = new TransparentAdorner(borderWindow);
        }

        private void AttachWindowAdorner()
        {
            AdornerLayer parentAdorner = AdornerLayer.GetAdornerLayer(borderWindow);
            parentAdorner.Add(_WindowAdorner);

            FadeAnimation(borderWindow, FadeDirection.FadeIn);
        }

        private void DettachWindowAdorner()
        {
            FadeAnimation(borderWindow, FadeDirection.FadeOut);

            AdornerLayer parentAdorner = AdornerLayer.GetAdornerLayer(borderWindow);
            parentAdorner.Remove(_WindowAdorner);
        }

        private void FadeAnimation(Border border, FadeDirection fadeDirection)
        {
            DoubleAnimation animFade = new DoubleAnimation();

            if (fadeDirection == FadeDirection.FadeIn)
            {
                animFade.From = 0;
                animFade.To = .10;
            }
            else
            {
                animFade.From = .10;
                animFade.To = 0;
            }

            animFade.Duration = new Duration(TimeSpan.FromSeconds(0.5));

            SolidColorBrush brush = new SolidColorBrush();
            brush.Color = Colors.Black;

            brush.BeginAnimation(SolidColorBrush.OpacityProperty, animFade);

            border.Background = brush;
        }

        private void butOpenChildWindow_Click(object sender, RoutedEventArgs e)
        {
            ChildWindow childWindow = new ChildWindow(this);
            IsActiveWin = false;
            childWindow.Owner = this;
            this.IsEnabled = false;
            childWindow.ShowDialog();
            this.IsEnabled = true;
        }
    }
}

Step 3
In App.xaml, change the StartupUri to ParentWindow.xaml

3 comments: