WPF (Windows Presentation Foundation)

Microsoft's native desktop application framework for Windows. Provides XAML, data binding, rich controls, and animation features. Enables maintainable application design through MVVM pattern.

desktopC#XAMLWindows.NETMicrosoft

GitHub Overview

dotnet/wpf

WPF is a .NET Core UI framework for building Windows desktop applications.

Stars7,392
Watchers291
Forks1,216
Created:October 19, 2018
Language:C#
License:MIT License

Topics

dotnethelp-wantedwpf

Star History

dotnet/wpf Star History
Data as of: 7/15/2025, 11:10 PM

Desktop Framework

WPF (Windows Presentation Foundation)

Overview

WPF (Windows Presentation Foundation) is a Windows desktop application development framework developed by Microsoft. Provided as part of .NET Framework/.NET, it offers declarative UI definition with XAML, rich controls, data binding, MVVM pattern support, and many other features. Since its introduction in 2006, it has become the standard choice for Windows enterprise application development.

Details

Compared to traditional Win32 API development, WPF provides comprehensive features necessary for modern application development, including declarative UI definition, powerful data binding, rich layout systems, and styling and templating capabilities.

Key features include declarative UI definition with XAML, MVVM architecture pattern support, powerful data binding, rich standard controls, custom control creation capabilities, vector-based graphics, animations and transitions, and diverse layout systems.

Features

  • XAML: Declarative UI definition with separation of design and logic
  • Data Binding: Two-way data binding and property notification
  • MVVM Support: Standard support for Model-View-ViewModel pattern
  • Rich Controls: Over 100 standard UI controls
  • Customizability: Styles, templates, and custom controls
  • Graphics: Vector-based high-quality rendering

Architecture

  • MVVM Pattern: Model-View-ViewModel design pattern
  • Command Pattern: Action processing via ICommand interface
  • Dependency Properties: Advanced property system
  • Resource System: Efficient resource management and sharing
  • Layout System: Flexible and powerful layout management
  • Routed Events: Advanced event processing system

Current Status

As of 2025, it continues to be supported in the latest .NET including .NET 8/.NET 9, with full support for Windows 11 environments. Development support in Visual Studio 2022 continues, and it occupies an important position in enterprise legacy system maintenance and new Windows application development.

Pros and Cons

Pros

  • Mature Ecosystem: Over 15 years of development and operational experience
  • Rich Resources: Extensive documentation, books, and tutorials
  • Powerful Development Tools: Comprehensive support from Visual Studio and Expression Blend
  • Enterprise Ready: Features suitable for large-scale application development
  • .NET Integration: Complete integration with .NET ecosystem
  • Performance: High performance native to Windows
  • Stability: High stability from long-term proven track record
  • Customizability: Advanced UI customization and theming support
  • Designer Support: Rich visual design tools and WYSIWYG editing
  • Large Community: Extensive community support and third-party libraries

Cons

  • Windows Only: No support for platforms other than Windows
  • Learning Curve: Many concepts to master including XAML, MVVM, data binding
  • Package Size: Large .NET Framework size requirements
  • Modern Design: Difficulty implementing flat design and material design
  • Mobile Unsupported: No support for smartphones and tablets
  • Development Stagnation: Focus on maintenance rather than new feature additions
  • High DPI Issues: Display problems on 4K and high-resolution displays
  • Web Trends: Relative importance decline due to web technology proliferation
  • Deployment Complexity: Complex deployment scenarios for enterprise environments
  • Legacy Technology: Perceived as legacy compared to modern web frameworks

Reference Pages

Code Examples

Hello World

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Hello WPF" Height="300" Width="400">
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <TextBlock Grid.Row="0" Text="Hello, WPF World!" 
                   FontSize="24" FontWeight="Bold" 
                   HorizontalAlignment="Center" Margin="0,20"/>
        
        <Button Grid.Row="1" Content="Click Me" 
                Name="HelloButton" HorizontalAlignment="Center" 
                Padding="20,10" Margin="0,20" Click="HelloButton_Click"/>
        
        <TextBlock Grid.Row="2" Name="MessageTextBlock" 
                   Text="Click the button to display a message" 
                   HorizontalAlignment="Center" VerticalAlignment="Center"
                   FontSize="14" Foreground="Gray"/>
    </Grid>
</Window>
using System.Windows;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        private int clickCount = 0;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void HelloButton_Click(object sender, RoutedEventArgs e)
        {
            clickCount++;
            MessageTextBlock.Text = $"Hello! Clicked {clickCount} time(s).";
            
            if (clickCount >= 5)
            {
                MessageBox.Show("Clicked 5 or more times!", "Message", 
                              MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }
    }
}

Data Binding and MVVM Pattern

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MVVM Data Binding Example" Height="400" Width="500">
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <TextBlock Grid.Row="0" Text="Customer Information Management" FontSize="20" FontWeight="Bold" 
                   HorizontalAlignment="Center" Margin="0,0,0,20"/>
        
        <!-- Input Form -->
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,5">
            <Label Content="Name:" Width="60" VerticalAlignment="Center"/>
            <TextBox Text="{Binding CustomerName, UpdateSourceTrigger=PropertyChanged}" 
                     Width="150" Margin="5,0"/>
            <Label Content="Age:" Width="40" VerticalAlignment="Center" Margin="10,0,0,0"/>
            <TextBox Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" 
                     Width="50" Margin="5,0"/>
        </StackPanel>
        
        <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,5">
            <Label Content="Email:" Width="60" VerticalAlignment="Center"/>
            <TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" 
                     Width="200" Margin="5,0"/>
            <CheckBox Content="VIP Customer" IsChecked="{Binding IsVip}" 
                      VerticalAlignment="Center" Margin="10,0"/>
        </StackPanel>
        
        <!-- Buttons -->
        <StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,20">
            <Button Content="Add" Command="{Binding AddCustomerCommand}" 
                    Padding="15,5" Margin="5"/>
            <Button Content="Delete" Command="{Binding DeleteCustomerCommand}" 
                    Padding="15,5" Margin="5"/>
            <Button Content="Clear" Command="{Binding ClearCommand}" 
                    Padding="15,5" Margin="5"/>
        </StackPanel>
        
        <!-- Customer List -->
        <GroupBox Grid.Row="4" Header="Customer List" Margin="0,10">
            <DataGrid ItemsSource="{Binding Customers}" 
                      SelectedItem="{Binding SelectedCustomer}"
                      AutoGenerateColumns="False" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="120"/>
                    <DataGridTextColumn Header="Age" Binding="{Binding Age}" Width="60"/>
                    <DataGridTextColumn Header="Email" Binding="{Binding Email}" Width="180"/>
                    <DataGridCheckBoxColumn Header="VIP" Binding="{Binding IsVip}" Width="50"/>
                </DataGrid.Columns>
            </DataGrid>
        </GroupBox>
    </Grid>
</Window>
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }
    }

    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private string _customerName = "";
        private int _age;
        private string _email = "";
        private bool _isVip;
        private Customer? _selectedCustomer;

        public string CustomerName
        {
            get => _customerName;
            set { _customerName = value; OnPropertyChanged(); }
        }

        public int Age
        {
            get => _age;
            set { _age = value; OnPropertyChanged(); }
        }

        public string Email
        {
            get => _email;
            set { _email = value; OnPropertyChanged(); }
        }

        public bool IsVip
        {
            get => _isVip;
            set { _isVip = value; OnPropertyChanged(); }
        }

        public Customer? SelectedCustomer
        {
            get => _selectedCustomer;
            set
            {
                _selectedCustomer = value;
                OnPropertyChanged();
                if (value != null)
                {
                    CustomerName = value.Name;
                    Age = value.Age;
                    Email = value.Email;
                    IsVip = value.IsVip;
                }
            }
        }

        public ObservableCollection<Customer> Customers { get; } = new();

        public ICommand AddCustomerCommand => new RelayCommand(AddCustomer, CanAddCustomer);
        public ICommand DeleteCustomerCommand => new RelayCommand(DeleteCustomer, CanDeleteCustomer);
        public ICommand ClearCommand => new RelayCommand(Clear);

        private void AddCustomer()
        {
            var customer = new Customer
            {
                Name = CustomerName,
                Age = Age,
                Email = Email,
                IsVip = IsVip
            };
            Customers.Add(customer);
            Clear();
        }

        private bool CanAddCustomer()
        {
            return !string.IsNullOrWhiteSpace(CustomerName) && 
                   Age > 0 && 
                   !string.IsNullOrWhiteSpace(Email);
        }

        private void DeleteCustomer()
        {
            if (SelectedCustomer != null)
            {
                Customers.Remove(SelectedCustomer);
                Clear();
            }
        }

        private bool CanDeleteCustomer()
        {
            return SelectedCustomer != null;
        }

        private void Clear()
        {
            CustomerName = "";
            Age = 0;
            Email = "";
            IsVip = false;
            SelectedCustomer = null;
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class Customer
    {
        public string Name { get; set; } = "";
        public int Age { get; set; }
        public string Email { get; set; } = "";
        public bool IsVip { get; set; }
    }

    public class RelayCommand : ICommand
    {
        private readonly Action _execute;
        private readonly Func<bool>? _canExecute;

        public RelayCommand(Action execute, Func<bool>? canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object? parameter) => _canExecute?.Invoke() ?? true;
        public void Execute(object? parameter) => _execute();

        public event EventHandler? CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

Styles and Templates

<Window x:Class="WpfApp.StyledWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Styles and Templates Example" Height="450" Width="600">
    
    <Window.Resources>
        <!-- Custom Button Style -->
        <Style x:Key="PrimaryButtonStyle" TargetType="Button">
            <Setter Property="Background" Value="#007ACC"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Padding" Value="15,8"/>
            <Setter Property="Margin" Value="5"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="Cursor" Value="Hand"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border Background="{TemplateBinding Background}"
                                CornerRadius="5" Padding="{TemplateBinding Padding}">
                            <ContentPresenter HorizontalAlignment="Center" 
                                            VerticalAlignment="Center"/>
                            <Border.Effect>
                                <DropShadowEffect ShadowDepth="2" BlurRadius="5" 
                                                Opacity="0.3" Color="Gray"/>
                            </Border.Effect>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="#005A9E"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Background" Value="#004A85"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- Card Style -->
        <Style x:Key="CardStyle" TargetType="Border">
            <Setter Property="Background" Value="White"/>
            <Setter Property="BorderBrush" Value="#E0E0E0"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="CornerRadius" Value="8"/>
            <Setter Property="Padding" Value="20"/>
            <Setter Property="Margin" Value="10"/>
            <Setter Property="Effect">
                <Setter.Value>
                    <DropShadowEffect ShadowDepth="3" BlurRadius="10" 
                                    Opacity="0.15" Color="Black"/>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- Header Style -->
        <Style x:Key="HeaderStyle" TargetType="TextBlock">
            <Setter Property="FontSize" Value="22"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="Foreground" Value="#333333"/>
            <Setter Property="Margin" Value="0,0,0,15"/>
        </Style>
        
        <!-- Animation -->
        <Storyboard x:Key="FadeInAnimation">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" 
                           From="0" To="1" Duration="0:0:0.5"/>
        </Storyboard>
    </Window.Resources>

    <Grid Background="#F5F5F5">
        <ScrollViewer>
            <StackPanel Margin="20">
                <TextBlock Text="WPF Styles and Templates" Style="{StaticResource HeaderStyle}"
                           HorizontalAlignment="Center"/>
                
                <!-- Profile Card -->
                <Border Style="{StaticResource CardStyle}">
                    <Border.Triggers>
                        <EventTrigger RoutedEvent="Loaded">
                            <BeginStoryboard Storyboard="{StaticResource FadeInAnimation}"/>
                        </EventTrigger>
                    </Border.Triggers>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        
                        <Ellipse Grid.Column="0" Width="80" Height="80" 
                                Fill="#007ACC" Margin="0,0,20,0"/>
                        
                        <StackPanel Grid.Column="1">
                            <TextBlock Text="John Smith" FontSize="18" FontWeight="Bold"/>
                            <TextBlock Text="Senior Software Engineer" 
                                     FontSize="14" Foreground="Gray" Margin="0,5"/>
                            <TextBlock Text="Developer specializing in WPF and C#. With over 10 years of experience, engaged in enterprise application design and development."
                                     TextWrapping="Wrap" Margin="0,10,0,15"/>
                            
                            <StackPanel Orientation="Horizontal">
                                <Button Content="Profile" Style="{StaticResource PrimaryButtonStyle}"/>
                                <Button Content="Contact" Style="{StaticResource PrimaryButtonStyle}"/>
                            </StackPanel>
                        </StackPanel>
                    </Grid>
                </Border>
                
                <!-- Settings Card -->
                <Border Style="{StaticResource CardStyle}">
                    <StackPanel>
                        <TextBlock Text="Application Settings" FontSize="16" FontWeight="Bold" Margin="0,0,0,15"/>
                        
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition/>
                                <RowDefinition/>
                                <RowDefinition/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="200"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            
                            <Label Grid.Row="0" Grid.Column="0" Content="Theme:"/>
                            <ComboBox Grid.Row="0" Grid.Column="1" Margin="5">
                                <ComboBoxItem Content="Light"/>
                                <ComboBoxItem Content="Dark" IsSelected="True"/>
                                <ComboBoxItem Content="Auto"/>
                            </ComboBox>
                            
                            <Label Grid.Row="1" Grid.Column="0" Content="Language:"/>
                            <ComboBox Grid.Row="1" Grid.Column="1" Margin="5">
                                <ComboBoxItem Content="English" IsSelected="True"/>
                                <ComboBoxItem Content="日本語"/>
                            </ComboBox>
                            
                            <Label Grid.Row="2" Grid.Column="0" Content="Auto Save:"/>
                            <CheckBox Grid.Row="2" Grid.Column="1" Content="Enabled" IsChecked="True" 
                                    VerticalAlignment="Center" Margin="5"/>
                            
                            <StackPanel Grid.Row="3" Grid.Column="1" Orientation="Horizontal" 
                                      HorizontalAlignment="Right" Margin="5,15,5,5">
                                <Button Content="Save" Style="{StaticResource PrimaryButtonStyle}"/>
                                <Button Content="Reset" Style="{StaticResource PrimaryButtonStyle}"/>
                            </StackPanel>
                        </Grid>
                    </StackPanel>
                </Border>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</Window>

File Operations and Dialogs

using Microsoft.Win32;
using System.IO;
using System.Windows;

namespace WpfApp
{
    public partial class FileOperationWindow : Window
    {
        public FileOperationWindow()
        {
            InitializeComponent();
        }

        private void OpenFileButton_Click(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new OpenFileDialog
            {
                Title = "Open File",
                Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*",
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
            };

            if (openFileDialog.ShowDialog() == true)
            {
                try
                {
                    string content = File.ReadAllText(openFileDialog.FileName);
                    ContentTextBox.Text = content;
                    StatusTextBlock.Text = $"File loaded: {Path.GetFileName(openFileDialog.FileName)}";
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"Failed to load file:\n{ex.Message}", "Error", 
                                  MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private void SaveFileButton_Click(object sender, RoutedEventArgs e)
        {
            var saveFileDialog = new SaveFileDialog
            {
                Title = "Save File",
                Filter = "Text Files (*.txt)|*.txt",
                DefaultExt = "txt",
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
            };

            if (saveFileDialog.ShowDialog() == true)
            {
                try
                {
                    File.WriteAllText(saveFileDialog.FileName, ContentTextBox.Text);
                    StatusTextBlock.Text = $"File saved: {Path.GetFileName(saveFileDialog.FileName)}";
                    MessageBox.Show("File saved successfully.", "Save Complete", 
                                  MessageBoxButton.OK, MessageBoxImage.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"Failed to save file:\n{ex.Message}", "Error", 
                                  MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        private void ShowCustomDialogButton_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new CustomInputDialog
            {
                Owner = this,
                WindowStartupLocation = WindowStartupLocation.CenterOwner
            };

            if (dialog.ShowDialog() == true)
            {
                MessageBox.Show($"Entered information:\nName: {dialog.UserName}\nAge: {dialog.Age}\nNotes: {dialog.Notes}", 
                              "Input Result", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }
    }

    public partial class CustomInputDialog : Window
    {
        public string UserName { get; private set; } = "";
        public int Age { get; private set; }
        public string Notes { get; private set; } = "";

        public CustomInputDialog()
        {
            InitializeComponent();
        }

        private void OkButton_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(NameTextBox.Text))
            {
                MessageBox.Show("Please enter a name.", "Input Error", 
                              MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (!int.TryParse(AgeTextBox.Text, out int age) || age < 0 || age > 150)
            {
                MessageBox.Show("Please enter a valid age (0-150).", "Input Error", 
                              MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            UserName = NameTextBox.Text;
            Age = age;
            Notes = NotesTextBox.Text;
            DialogResult = true;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = false;
        }
    }
}

Custom Controls

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfApp.Controls
{
    public class ProgressCard : Control
    {
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(ProgressCard));

        public static readonly DependencyProperty DescriptionProperty =
            DependencyProperty.Register("Description", typeof(string), typeof(ProgressCard));

        public static readonly DependencyProperty ProgressProperty =
            DependencyProperty.Register("Progress", typeof(double), typeof(ProgressCard));

        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(ImageSource), typeof(ProgressCard));

        static ProgressCard()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ProgressCard), 
                new FrameworkPropertyMetadata(typeof(ProgressCard)));
        }

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public string Description
        {
            get { return (string)GetValue(DescriptionProperty); }
            set { SetValue(DescriptionProperty, value); }
        }

        public double Progress
        {
            get { return (double)GetValue(ProgressProperty); }
            set { SetValue(ProgressProperty, value); }
        }

        public ImageSource Icon
        {
            get { return (ImageSource)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }
    }
}

Animations and Visual Effects

<Window x:Class="WpfApp.AnimationWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Animations and Visual Effects" Height="500" Width="600">
    
    <Window.Resources>
        <Storyboard x:Key="ButtonHoverAnimation">
            <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
                           To="1.1" Duration="0:0:0.2"/>
            <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
                           To="1.1" Duration="0:0:0.2"/>
        </Storyboard>
        
        <Storyboard x:Key="ButtonLeaveAnimation">
            <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
                           To="1.0" Duration="0:0:0.2"/>
            <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
                           To="1.0" Duration="0:0:0.2"/>
        </Storyboard>
        
        <Storyboard x:Key="FadeInAnimation">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" 
                           From="0" To="1" Duration="0:0:1"/>
            <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"
                           From="50" To="0" Duration="0:0:1">
                <DoubleAnimation.EasingFunction>
                    <QuadraticEase EasingMode="EaseOut"/>
                </DoubleAnimation.EasingFunction>
            </DoubleAnimation>
        </Storyboard>
        
        <Storyboard x:Key="RotateAnimation">
            <DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
                           From="0" To="360" Duration="0:0:2" RepeatBehavior="Forever"/>
        </Storyboard>
    </Window.Resources>

    <Grid Background="LinearGradientBrush">
        <Grid.Background>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                <GradientStop Color="#4A90E2" Offset="0"/>
                <GradientStop Color="#7B68EE" Offset="1"/>
            </LinearGradientBrush>
        </Grid.Background>
        
        <ScrollViewer>
            <StackPanel Margin="40">
                <TextBlock Text="WPF Animation Examples" FontSize="28" FontWeight="Bold" 
                          Foreground="White" HorizontalAlignment="Center" Margin="0,0,0,30">
                    <TextBlock.RenderTransform>
                        <TranslateTransform/>
                    </TextBlock.RenderTransform>
                    <TextBlock.Triggers>
                        <EventTrigger RoutedEvent="Loaded">
                            <BeginStoryboard Storyboard="{StaticResource FadeInAnimation}"/>
                        </EventTrigger>
                    </TextBlock.Triggers>
                </TextBlock>
                
                <!-- Hover Animation Button -->
                <Button Content="Hover for Scale Animation" 
                        Background="White" Foreground="#4A90E2" 
                        FontSize="16" FontWeight="Bold"
                        Padding="20,10" Margin="0,10" 
                        HorizontalAlignment="Center"
                        BorderThickness="0" Cursor="Hand">
                    <Button.RenderTransform>
                        <ScaleTransform/>
                    </Button.RenderTransform>
                    <Button.Triggers>
                        <EventTrigger RoutedEvent="MouseEnter">
                            <BeginStoryboard Storyboard="{StaticResource ButtonHoverAnimation}"/>
                        </EventTrigger>
                        <EventTrigger RoutedEvent="MouseLeave">
                            <BeginStoryboard Storyboard="{StaticResource ButtonLeaveAnimation}"/>
                        </EventTrigger>
                    </Button.Triggers>
                </Button>
                
                <!-- Rotation Animation -->
                <Border Background="White" Width="100" Height="100" 
                        CornerRadius="50" Margin="0,30" 
                        HorizontalAlignment="Center">
                    <Border.RenderTransform>
                        <RotateTransform/>
                    </Border.RenderTransform>
                    <Border.Triggers>
                        <EventTrigger RoutedEvent="MouseLeftButtonDown">
                            <BeginStoryboard Storyboard="{StaticResource RotateAnimation}"/>
                        </EventTrigger>
                    </Border.Triggers>
                    
                    <TextBlock Text="🎯" FontSize="40" HorizontalAlignment="Center" 
                              VerticalAlignment="Center"/>
                </Border>
                
                <!-- Progress Bar Animation -->
                <Border Background="White" CornerRadius="10" Padding="20" Margin="0,20">
                    <StackPanel>
                        <TextBlock Text="Progress Display" FontSize="16" FontWeight="Bold" 
                                  Margin="0,0,0,10"/>
                        <ProgressBar Name="AnimatedProgressBar" Height="20" 
                                   Background="#F0F0F0" Foreground="#4A90E2"/>
                        <Button Content="Start Animation" Click="StartProgressAnimation" 
                              Margin="0,10,0,0" HorizontalAlignment="Center"/>
                    </StackPanel>
                </Border>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</Window>
using System.Windows;
using System.Windows.Media.Animation;

namespace WpfApp
{
    public partial class AnimationWindow : Window
    {
        public AnimationWindow()
        {
            InitializeComponent();
        }

        private void StartProgressAnimation(object sender, RoutedEventArgs e)
        {
            var animation = new DoubleAnimation
            {
                From = 0,
                To = 100,
                Duration = TimeSpan.FromSeconds(3),
                EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseInOut }
            };
            
            AnimatedProgressBar.BeginAnimation(ProgressBar.ValueProperty, animation);
        }
    }
}