Tuesday, May 30, 2017

Freezable Objects in WPF


Freezable objects are special type of object which can be use to increase performance.
Freezable objects have two state unfrozen and frozen. In unfrozen state object is work like normal object but in frozen state object can be modified.

Freezable classes are drive from Freezable
as you can see in image SolidColorBrush class is drive from Freezable class.



In WPF mostly graphics sub-system are related to Freezable, and can help to increase performance, most of these class generate low level object to render their graphics stuffs such as background color for buttons and when their is any change in these object (e.g. Brush) these low level object again regenerated, even if there is no actual change even wpf graphics system spend some resources to monitor if there is any change.

So if object is in frozen state, WPF graphics system need not to monitor the modification andas a result it increase performance.

Let understand this with a simple example :
we have a button and we assign a SolidColorBrush object to the button background, the information what we provide to SolidColorBrush to show the background, not generate any color, for this a low level object is generate for the button and the brush and that object appear on the screen , and WPF graphic system spend resource to monitor the change , if there  is any change it again re-generate the object. so when we make the objecr Unfrozen this monitor got ignored.

example of Freezable object
Bursh, Pen, Geometry, Transform, AnimationTimeline

How to Freeze the Freezable object

Use Freeze() method to make a object Frozen

            SolidColorBrush redbrush = new SolidColorBrush(Colors.Red);
            redbrush.Freeze();

Check for Freezable object can Freeze

It is very easy to do this use CanFreeze() method to check object can freeze or not.
            if (redbrush.CanFreeze)
            {
                redbrush.Freeze();
            }

How to check object is Freeze or not
            
           if (redbrush.IsFrozen)
           {
              ...
           }

Below is complete example

            Button btnFreezable = new Button();
            SolidColorBrush redbrush = new SolidColorBrush(Colors.Red);
            btnFreezable.Foreground = redbrush;
            if (redbrush.CanFreeze && redbrush.IsFrozen)
            {
                redbrush.Freeze();
            }

            try
            {
                redbrush.Color = Colors.Yellow;
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show("Invalid operation: " + ex.ToString());

            }

Freezable Object has changed event which fire where there is any modification in Object or Object it Contains.
need example

Feature of Freezable object
  • It provide change event to notify when modification in object.
  • It can improve performance if make it UnFrozen
  • Only a Frozen Freezable object can share across the thread


This Post will continue for further topic

1) How to use Freezable from xaml
2) CloneCore
3) CloneCurrentValueCore
4) GetAsFrozenCore
5) GetCurrentValueAsFrozenCore
6) FreezeCore

Saturday, May 27, 2017

Interactive Command: How can i pass Event Argument to a command in the View Model from XAML

For Interactivity we have to use System.Windows.Interactivity dll , it is to make a command respond when WPF controls event raised without using any code behind.(This article not for how we can use Interactivity , it is for how we can send the event argument in the view model), many time we need the event argument of particular event for that control for some process, but in the MVVM we can not get the event argument directly.
lets start with a example, we have a textbox and we want to get the "TextChangedEventArgs" of method that is bind with command that we will hook with Textbox via Interactivity as the text change.

Code Download

Add the reference of  System.Windows.Interactivity.dll in the application.
Step1: The XAML is as follows, it has simply a textbox. as TextChanged event of textbox fire, we want to execute the command in view model.

<Window x:Class="Interactivity1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:IntractComm="clr-namespace:InteractivityHelper">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="124,63,0,0" Name="TextBox1"
                 Text="" VerticalAlignment="Top" Width="200">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="TextChanged">
                    <IntractComm:InteractiveCommand Command="{Binding CommandWithEventArgs}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>
    </Grid>
</Window>


Step 2: In the view model we define the command that will execute as text changed.
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;

namespace Interactivity1
{
    public class MainWindowVM
    {
        #region CommandWithEventArgs
        DelegateCommand<TextChangedEventArgs> _CommandWithEventArgs;
        /// <summary>
        /// Exposes <see cref="CommandWithEventArgs(MouseEventArgs)"/>.
        /// </summary>
        public DelegateCommand<TextChangedEventArgs> CommandWithEventArgs
        {
            get { return _CommandWithEventArgs ?? (_CommandWithEventArgs = new DelegateCommand<TextChangedEventArgs>(TextBoxTextChanged)); }
        }
        #endregion


        private void TextBoxTextChanged(TextChangedEventArgs e)
        {
            //some processimg
        }
    }
}


Step 3: Add the following class that inherit TriggerAction class

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace InteractivityHelper
{
    public class InteractiveCommand : TriggerAction<DependencyObject>
    {
        protected override void Invoke(object parameter)
        {
            if (base.AssociatedObject != null)
            {
                ICommand command = this.ResolveCommand();
                if ((command != null) && command.CanExecute(parameter))
                {
                    command.Execute(parameter);
                }
            }
        }

        private ICommand ResolveCommand()
        {
            ICommand command = null;
            if (this.Command != null)
            {
                return this.Command;
            }
            if (base.AssociatedObject != null)
            {
                foreach (PropertyInfo info in base.AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, this.CommandName, StringComparison.Ordinal))
                    {
                        command = (ICommand)info.GetValue(base.AssociatedObject, null);
                    }
                }
            }
            return command;
        }

        private string commandName;
        public string CommandName
        {
            get
            {
                base.ReadPreamble();
                return this.commandName;
            }
            set
            {
                if (this.CommandName != value)
                {
                    base.WritePreamble();
                    this.commandName = value;
                    base.WritePostscript();
                }
            }
        }

        #region Command
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
        #endregion
    }
}



This article explain how we get the event argument in viewmodel of an event generate by a WPF control.

Triggers in WPF

Triggers are used to change the property value of UI elements on the basics of some condition change or some event fire.

Triggers are used in styles and allow you to dynamically change the property value of a UI element.
when some condition satisfied then trigger make changes in the property.
So we can say Trigger are used to change the visual effect/behavior of control on change of property value or some event fire, it can change the visual appearance of a framework element.

We can understand it by some simple example :

  1. We have a button in our wpf window and if mouse hover on the button then background of button should be red and as mouse hover out it revert to previous color.
  2. We have a text box in the window and when it's value is red it's background color become red other wise normal.
The properties changed by triggers are automatically reset to their previous value when the triggered condition is no longer satisfied. Triggers are optimized for transient states which are expected to change and return to original state, such as IsPressed on Button and IsSelected on ListBoxItem. The Property of interest must be a dependency property.

We must specify the property and value in trigger otherwise it throw exception.

There are main three triggers
  • Property Trigger
    • MultiTrigger
  • Data Trigger
    • MultiDataTrigger
  • Event Trigger
Property Trigger

In Property trigger,when some UIElement property i.e. dependency property of a control change then the setters inside the trigger execute.
For creating the property trigger for a control we need to create the trigger in its style.

e.g. property trigger can be used to change the foreground color of button when mouse hover over the button.


<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PropertyTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Foreground" Value="Red"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBox Name="btnColor" Text="Test Property Triggers" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Left"
                Width="150" Height="30" Margin="50"></TextBox>
    </Grid>
</Window>








in the above example trigger is created in "TriggerTextBoxStyle" style, on change in proeprty IsMouseOver when it is true the setter set the background to red.
we can put multiple setter for this trigger or we can put multiple trigger inside this trigger collection.
<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PropertyTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Foreground" Value="Red"></Setter>
                    <Setter Property="Background" Value="YellowGreen"></Setter>
                    <Setter Property="FontWeight" Value="Bold"></Setter>
                </Trigger>
                <Trigger Property="Text" Value="wpf">
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Background" Value="Red"></Setter>
                    <Setter Property="FontWeight" Value="ExtraBlack"></Setter>
                </Trigger>

            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBox Name="btnColor" Text="Test Property Triggers" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Left"
                Width="150" Height="30" Margin="50"></TextBox>
    </Grid>

</Window>



MultiTrigger

Some time we need to set the values of property when more then one conditions satisfy, MultiTrigger fulfill this feature.
MultiTrigger depends upon multiple properties and will execute when all conditions are satisfy.
E.g.




<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PropertyTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="Text" Value="wpf"></Condition>
                        <Condition Property="IsMouseOver" Value="true"></Condition>
                    </MultiTrigger.Conditions>
                    <MultiTrigger.Setters>
                        <Setter Property="Foreground" Value="White"></Setter>
                        <Setter Property="Background" Value="Red"></Setter>
                        <Setter Property="FontWeight" Value="ExtraBlack"></Setter>
                    </MultiTrigger.Setters>
                </MultiTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <TextBox Name="btnColor" Text="wpf" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Left"
                Width="150" Height="30" Margin="50"></TextBox>
    </Grid>

</Window>


DataTrigger


In property trigger we use Dependency Property in conditions but In the data Trigger are used with Property value that is bind with DP property.

e.g. TextBox has Text DP property and Text DP is bind with Data CLR property of some ViewModel so Property Trigger use Text in condition while DataTrigger use Data Property in Condition.

we can define the data trigger inside the style or in DataTemplate
Element name can also use in Data Trigger's Conditions.

Consider we have wpf window in which there is two TextBoxs first is Color Text





<Window x:Class="MVVMBasics.PropertyTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type TextBox}" x:Key="TriggerTextBoxStyle" >
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=cbColor, Path=Text}" Value="Red">
                    <Setter Property="Foreground" Value="Red"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding ElementName=cbColor, Path=Text}" Value="BlueViolet">
                    <Setter Property="Foreground" Value="BlueViolet"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding ElementName=cbColor, Path=Text}" Value="Green">
                    <Setter Property="Foreground" Value="Green"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <ComboBox Name="cbColor" SelectedIndex="0" Width="100" HorizontalAlignment="Center" Margin="0,10,0,0">
            <ComboBoxItem Content="Red"></ComboBoxItem>
            <ComboBoxItem Content="BlueViolet"></ComboBoxItem>
            <ComboBoxItem Content="Green"></ComboBoxItem>
        </ComboBox>
        <TextBox x:Name="btnColor" Text="wpf" Style="{StaticResource TriggerTextBoxStyle}" HorizontalAlignment="Center"
              Width="150" Height="30"  Margin="0,20,0,0" />
    </StackPanel>

</Window>

We can not use element name binding with property Trigger


ViewModel property in DataTrigger


<Window x:Class="MVVMBasics.DataTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="DataTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type Label}" x:Key="DataTriggerStyle" >
            <Setter Property="Background" Value="Green"></Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Age}" Value="35">
                    <Setter Property="Background" Value="Red"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <TextBox x:Name="btnAge" Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"
              Width="150" Height="30"  Margin="0,20,0,0" />
        <Label x:Name="btnColor" Style="{StaticResource DataTriggerStyle}" HorizontalAlignment="Center"
              Width="50" Height="30"  Margin="0,20,0,0" />
    </StackPanel>

</Window>


Code Behind

using System.ComponentModel;
using System.Windows;

namespace MVVMBasics
{
    /// <summary>
    /// Interaction logic for DataTriggerDemo.xaml
    /// </summary>
    public partial class DataTriggerDemo : Window, INotifyPropertyChanged
    {
        private int age;
        public int Age
        {
            get { return age; }
            set
            {
                age = value; OnPropertyChange("Age");
            }
        }
        public DataTriggerDemo()
        {
            InitializeComponent();
            this.DataContext = this;
        }
        public void OnPropertyChange(string propertyName)
        {
            PropertyChangedEventHandler propChange = PropertyChanged;
            if (propChange != null)
            {
                propChange(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}





MultiDataTrigger

In MultiDataTrigger Execute the set of setter collection on more then one condition satisfied.

<Window x:Class="MVVMBasics.DataTriggerDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MultiDataTriggerDemo" Height="168.045" Width="380.075">
    <Window.Resources>
        <Style TargetType="{x:Type Label}" x:Key="DataTriggerStyle" >
            <Setter Property="Background" Value="Green"></Setter>
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Name}" Value="wpf"></Condition>
                        <Condition Binding="{Binding Age}" Value="35"></Condition>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.Setters>
                        <Setter Property="Background" Value="Red"></Setter>
                    </MultiDataTrigger.Setters>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Label x:Name="lblName" Content="Name" HorizontalAlignment="Center"
              Width="67" Height="25"  />
            <TextBox x:Name="txtName" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"
              Width="67" Height="25"  Margin="5" />
        </StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Label x:Name="lblAge" Content="Age" HorizontalAlignment="Center"
              Width="67" Height="25"  />
            <TextBox x:Name="txtAge" Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center"
              Width="67" Height="25"  Margin="5" />
        </StackPanel>
        <Label x:Name="lblColor" Style="{StaticResource DataTriggerStyle}" HorizontalAlignment="Center"
              Width="50" Height="30"  Margin="0,20,0,0" />
    </StackPanel>
</Window>




Event Trigger

Event Trigger are basically used when some routed event raised by some framework element.
It is Used to perform some Animation
We will continue this topic(Event Trigger) with my post WPF Animation very soon.