luni, 14 iunie 2010

WPF ViewTree with TreeViewItems of Different Types

[WPF][Sample]WPF ViewTree with TreeViewItems of Different Types


What I want to do

A View Tree that contains Collection of different types, but I still want to use the binding facility offer by WPF



Problem: Create a List of Views: but views are of different types

Views are of two different types:
  • Grid
  • Chart

Grid Views have the following properties:
  • Caption
  • Editable
  • ShowRowIndicator

Chart Views have the following properties:
  • Caption
  • ChartType


Classes Hierarchy


IViewBase View Interface

public interface IView
{
string Caption { get; set; }
}


IGridInterface for Grid view

public interface IGrid : IView
{
bool Editable { get; set; }
bool ShowRowIndicator { get; set; }
}

IChartInterface for Chart view

public interface IChart : IView
{
string ChartType { get; set; }
}

GridGrid View class

public class Grid : IGrid
{
#region Implementation of IView

public string Caption { get; set; }

#endregion

#region Implementation of IGrid

public bool Editable { get; set; }
public bool ShowRowIndicator { get; set; }

#endregion
}

ChartChart View class

public class Chart : IChart
{
#region Implementation of IView

public string Caption { get; set; }

#endregion

#region Implementation of IChart

public string ChartType { get; set; }

#endregion
}

ViewsCollection of IView items

public class Views : ObservableCollection<IView>
{
}

ViewCollectionCollection of a certain type of Views (Grid or Chart)

public class ViewCollection
{
public String ViewCollectionName { get; set; }
public bool IsSelected { get; set; }
public Views Views { get; set; }
}

ViewCollectionListCollection of ViewCollection items

public class ViewCollectionList : ObservableCollection<ViewCollection>
{
}




Create the collection of views with markup


<Window.Resources>
<Classes:ViewCollectionList x:Key="ViewCollectionList">
<Classes:ViewCollection ViewCollectionName="Grid Views" IsSelected="True">
<Classes:ViewCollection.Views>
<Classes:Views>
<Classes:Grid Caption="Grid 1" Editable="True" ShowRowIndicator="True" />
<Classes:Grid Caption="Grid 2" Editable="False" ShowRowIndicator="False" />
<Classes:Grid Caption="Grid 4" Editable="True" ShowRowIndicator="False" />
</Classes:Views>
</Classes:ViewCollection.Views>
</Classes:ViewCollection>
<Classes:ViewCollection ViewCollectionName="Chart Views" IsSelected="False">
<Classes:ViewCollection.Views>
<Classes:Views>
<Classes:Chart Caption="Chart 1" ChartType="Line" />
<Classes:Chart Caption="Chart 4" ChartType="Bar" />
<Classes:Chart Caption="Chart 2" ChartType="Pie" />
</Classes:Views>
</Classes:ViewCollection.Views>
</Classes:ViewCollection>
</Classes:ViewCollectionList>
</Window.Resources>

Create the collection of views in code behind file

var _list = new ViewCollectionList();
var _collection = new ViewCollection
{
ViewCollectionName = "Grid Views",
Views = new Views
{
new Grid
{
Caption = "Grid 1",
Editable = false,
ShowRowIndicator = true
},
new Grid
{
Caption = "Grid 2",
Editable = false,
ShowRowIndicator = false
},
new Grid
{
Caption = "Grid 3",
Editable = true,
ShowRowIndicator = true
}
}
};
_list.Add(_collection);

_collection = new ViewCollection
{
ViewCollectionName = "Chart Views",
Views = new Views
{
new Chart
{
Caption = "Chart 1",
ChartType = "Line"
},
new Chart
{
Caption = "Chart 2",
ChartType = "Bar"
}
}
};
_list.Add(_collection);
_tree.DataContext = _list;


Create the templates for displaying each class

<Window.Resources>

....
<HierarchicalDataTemplate DataType="{x:Type Classes:ViewCollection}"
ItemsSource="{Binding Path=Views}"
>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=ViewCollectionName}" FontWeight="Bold"/>
<TextBlock Text=" " />
<Border Background="LightCyan" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="Is selected: " />
<CheckBox IsChecked ="{Binding IsSelected}" />
</StackPanel>
</Border>
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type Classes:Grid}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Caption}" FontWeight="Bold"/>
<TextBlock Text=" Is Editable: " />
<CheckBox IsChecked="{Binding Path=Editable}" />
<TextBlock Text=" Show Row Indicator: " />
<CheckBox IsChecked="{Binding Path=ShowRowIndicator}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type Classes:Chart}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Caption}" FontWeight="Bold"/>
<TextBlock Text=" Chart Type: " />
<TextBlock Text="{Binding Path=ChartType}" Background="LightGreen"/>
</StackPanel>
</DataTemplate>
</Window.Resources>


Initiate the view tree

<DockPanel>
<TreeView DataContext="{StaticResource ViewCollectionList}" x:Name="_tree">
<TreeViewItem ItemsSource="{Binding}" Header="Views" />
</TreeView>
</DockPanel>



duminică, 13 iunie 2010

[WPF][9][1]Converters

[WPF][9][1]Converters


Value Converters

  • Value converters can morph the source value into a completely different target value
  • A value converter is an implementation of the IValueConverter interface, which contains two methods: Convert and ConvertBack
  • You can define your own converter. It has to implement IValueConverter
    • BooleanToVisibilityConverter

BoolToVisibilityConverter 

    [ValueConversion(typeof(bool), typeof(Visibility))]
    public class BoolToVisibilityConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((bool)value) ? Visibility.Visible : Visibility.Hidden;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

<Convertors:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
...
<Grid Visibility="{TemplateBinding IsRunning, Converter={StaticResource BoolToVisibilityConverter}}">

StringToRowSpanConverter 


      /// <summary>
    /// If the string provided is null or empty, it returns 1, else 2
    /// </summary>
    [ValueConversion(typeof(string), typeof(int))]
    public class StringToRowSpanConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (value == null || value.ToString() == string.Empty) ? 2 : 1;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

StringToVisibilityConverter 

    [ValueConversion(typeof(string), typeof(Visibility))]
    public class StringToVisibilityConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (value == null || value.ToString() == string.Empty) ? Visibility.Hidden : Visibility.Visible;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

<Convertors:StringToVisibilityConverter x:Key="StringToVisibilityConverter"/>
...
<Label Grid.Column="1" Grid.Row="1"
               VerticalContentAlignment="Center" HorizontalAlignment="Center" 
               Margin="1"
               Visibility="{Binding DetailedMessage, Converter={StaticResource StringToVisibilityConverter}}"
               ToolTip="{Binding DetailedMessage}" FontSize="9">
</Label>

DateTimeToDateConverter 


    public class DateTimeToDateConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((DateTime)value).DayOfWeek;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }

ItemCountToDescriptionConverter 


    public class ItemCountToDescriptionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // Let Parse throw an exception if the input is bad
            int num = int.Parse(value.ToString());
            return num + (num == 1 ? " item" : " items");
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }

<Window.Resources>
   <ResourceDictionary>
     <converter:ItemCountToDescriptionConverter x:Key="m_converter"/>
...

<TextBlock Grid.Row="0" Margin="10"
                Text="{Binding Path=Count, Converter={StaticResource m_converter}}" />
...

HexConverter 


public class HexConverter : IValueConverter 
{
  public object Convert( object value, Type targetType, object parameter, CultureInfo culture)
  {
   // Convert to base 16
   return ((int)value).ToString("x");
  }
  public object ConvertBack(object value, Type targetType, , object parameter, CultureInfo culture) 
  {
    // Convert from base 16
    return int.Parse((string)value, System.Globalization.NumberStyles.HexNumber);
  }
}

<Convertors:HexConverter r x:Key="hexConverter"/>
<TextBox Text="{Binding Path=StatValue, Converter={StaticResource hexConverter}}" />

vineri, 11 iunie 2010

[WPF][6] Layout

[6] Layout




Intro


This sizing and positioning of controls (and other elements) is called layout
All elemets involved in layout derive from System.Windows.UIElement


WPF elements tend to size to their content, meaning that they try to be large enough to fit their content and no larger.
Layout occurs in two phases: measure and arrange:
  • first controls are ask for space that they require
    • This is calculated base on children space required
  • arrange is about how much space we have
    • In this phase is decided what to put and where to put
In order to create a custom panel we have to override the MeasureOverride and ArrangeOverride methods
We pass in an infinite size when calling Measure on each child in order to use its preferred size.

child.Measure( new Size( double.PositiveInfinity,
double.PositiveInfinity )



Height and Width

  • They are common to all FrameworkElements
  • See, also, MinHeight, MaxHeight, MinWidth, and MaxWidth properties
  • You should avoid setting explicit sizes unless absolutely necessary: two reasons font settings, language
  • FrameworkElement’s Height and Width have a default value of Double.NaN (Not a Number), meaning that the element will only be as large as its content needs it to be
  • DesiredSize (inherited from UIElement) - calculated base on Width, Height, MinXXX, and MaxXXX properties
  • RenderSize (inherited from UIElement) - final size of an element after layout is complete
  • ActualHeight and ActualWidth
  • LayoutUpdated event (inherited from UIElement)
  • UpdateLayout method to force any pending layout updates to finish synchronously


Margin and Padding


  • Margin controls how much extra space gets placed around the outside edges of the element
  • Padding controls how much extra space gets placed around the inside edges of the element
  • They are of type are of type System.Windows.Thickness
  • The unit of measurement is device-independent pixels. It is a "logical pixel"
    • it represents 1/96th of an inch
    • it gets resolution independence

Visibility

  • it is a three-state System.Windows.Visibility enumeration
  • possible values: Visible, Collapsed, Hidden

Aligment

HorizontalAlignment and VerticalAlignment properties enable an element to control what it does with any extra space given to it by its parent panel.
  • HorizontalAlignment: Left, Center, Right, and Stretch
  • VerticalAlignment: Top, Center, Bottom, and Stretch
  • When an element uses Stretch alignment (horizontally or vertically), an explicit Height or Width setting still takes precedence

HorizontalContentAlignment and VerticalContentAlignment properties determine how a control’s content fills the space within the control.
FlowDirection is a property on FrameworkElement (and several other classes) that can reverse the way an element’s inner content flows. I has two values: LeftToRight and RightToLeft

Transforms


All FrameworkElements have two properties of type Transform that can be used to apply such transforms:
  • LayoutTransform, which is applied before the element is laid out
  • RenderTransform (inherited from UIElement), which is applied after the layout process has finished (immediately before the element is rendered)
RenderTransformOrigin is a property that represents the starting point of the transform. with the help of System.Windows.PointConverter, the value for RenderTransformOrigin can
be specified in XAML with two comma-delimited numbers

There are five built-in 2D transforms:

  • RotateTransform
    • It rotates an element according to the values of three double properties:
      • Angle—Angle of rotation, specified in degrees (default value = 0)
      • CenterX—Horizontal center of rotation (default value = 0)
      • CenterY—Vertical center of rotation (default value = 0)
    • The default (CenterX,CenterY) point of (0,0) represents the top-left corner
    • For the common case of transforming an element around its middle, the relative (0.5,0.5) RenderTransformOrigin is easy to specify in XAML.
  • ScaleTransform
    • it enlarges or shrinks an element horizontally, vertically, or in both directions.
    • Properties:
      • ScaleX—Multiplier for the element’s width (default value = 1)
      • ScaleY—Multiplier for the element’s height (default value = 1)
      • CenterX—Origin for horizontal scaling (default value = 0)
      • CenterY—Origin for vertical scaling (default value = 0)
    • A ScaleX value of 0.5 shrinks an element’s rendered width in half, whereas a ScaleX value of 2 doubles the width
    • FrameworkElement’s ActualHeight and ActualWidth properties are not affected by ScaleTransform properties.
  • SkewTransform
    • SkewTransform slants an element according to the values of four double properties
      • AngleX—Amount of horizontal skew (default value = 0)
      • AngleY—Amount of vertical skew (default value = 0)
      • CenterX—Origin for horizontal skew (default value = 0)
      • CenterY—Origin for vertical skew (default value = 0)
  • TranslateTransform
    • TranslateTransform simply moves an element according to two double properties:
      • X—Amount to move horizontally(default value = 0)
      • Y—Amount to move vertically (default value = 0)
  • MatrixTransform
    • It is a low-level mechanism that can be used to create custom 2D transforms.
    • MatrixTransform has a single Matrix property (of type System.Windows.Media.Matrix) representing a 3x3 affine transformation matrix

TransformGroup is just another Transform-derived class whose purpose is to combine child Transform objects.
Elements hosting content that isn’t native to WPF do not support transforms



miercuri, 9 iunie 2010

[WPF][5][3]Application object

[5][3]Application object

  • It is an interface between your application and the system
  • It is accessible from within all WPF .NET projects and provides an interface between your application and the system
  • It is the entry point of a WPF application
    • Threads in a WPF application must run in a singlethreaded apartment (STA)
    • Main must be marked with an STAThread attribute.
  • In the WPF sense, an application is a singleton object that provides services for UI components and UI programmers in the creation and execution of a WPF program.
  • It works the same for both WPF XBAP and WPF Window Applications
  • Application defines a Run method that keeps the application alive and dispatches messages appropriately

  • [STAThread]
    public static void Main()
    {
    Application app = new Application();
    MainWindow window = new MainWindow();
    window.Show();
    app.Run(window);
    }

  • Application also defines a StartupUri property that provides an alternate means of showing the application’s first Window.

    [STAThread]
    public static void Main()
    {
    Application app = new Application();
    Application.Current.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
    Application.Current.Run();
    }

  • It offers the possibility to hook into events and override virtual methods for your application
  • It acts similar to how the global.asax file manages contextual session and application information for ASP.NET applications
    • Activated event /OnActivated virtual method: A window activated by the system
    • Deactivated/Deactivated : A window deactivated by the system
    • SessionEnding/OnSessionEnding: Raised when a user session ends or the operating, system terminates (i.e., logoff or shutdown)
      • ReasonSessionEnding enumeration
    • Exit/OnExit: Raised after all windows are destroyed
    • Startup/OnStartup: Occurs prior to any windows being created or navigations being performed
  • The Application object is defined by the MyApp.xaml file and its corresponding code-behind file.
  • System.Windows.Application.Current
    • the instance of application
    • it is available once it is created
  • The use of the Application object to share variables across pages is fundamental to its purpose
    • Application.Current.Properties["MyName"] = "George Lache";
  • Application defines a readonly Windows collection to give you access to all open Windows.
  • MainWindow property
    • A WPF application’s main window is the top-level window that is set in the MainWindow property of the Application object.
    • This property is set by default when the first instance of the Window class is created and the Application.Current property is set
      • This setting can be overrided
  • Application.Current.Windows
    • The Application object’s Windows property get a list of each top-level Window
  • ShutdownMode property
    • OnLastWindowClose = 0 - it is the default one
    • OnMainWindowClose = 1
    • OnExplicitShutdown = 2
      • an application can also be shut down manually by calling the Application object’s Shutdown method
      • Application.Current.Shutdown()
  • How can I create a single-instance application using WPF?

bool mutexIsNew;
using (System.Threading.Mutex m = new System.Threading.Mutex(true, uniqueName, out mutexIsNew))
{
if (mutexIsNew)
// This is the first instance. Run the application.
else
// There is already an instance running. Exit!
}

  • A typical WPF application has a single UI thread and a render thread.
    • The render thread is an implementation detail that is never directly exposed to developers. It runs in the background and handles low-level tasks such as composition
    • DispatcherObject defines a Dispatcher property (of type Dispatcher) containing several overloads of Invoke (a synchronous call) and BeginInvoke (an asynchronous call).


ApplicationSettingsBase

  • it can be used to manage user and application settings between application sessions
  • supports data change notifications
  • we can bind to settings data just like any other data

  • <Window ... >
    ...
    <TextBlock ...
    Text="{Binding Path=LastView,
    Source={x:Static local:Properties.Settings.Default}}" />
    ...
    </Window>