Showing posts with label WPF. Show all posts
Showing posts with label WPF. Show all posts

Saturday, June 5, 2010

WPF DockingManager :- AvalonDock

Some days ago , I was in need of a docking panel for a WPF project. I needed the collapse and expand functionality , floating windows etc . I was familiar with the DockingManager component from DevExpress for Win forms and wanted same type of functionality for my WPF project. So while searching I came across a open source initiative AvalonDock on CodePlex, it was quite the thing that I wanted.
I implemented the DockingManager of AvalonDock and got my Window working with several floating and dockable windows.

After making my main window have many dockable and floating windows , I needed another functionality , that was to make visibility off for close buttton on Dockablepane , apart from that I also wanted to style the Documentpane and Dockablepane . To make the close button visibility off for Dockablepane and Documentpane, there's the property IsCloseable on DocumentContent and DockableContent.

Using this property we can change the close button's visibility. To disable the floating of windows in DocumentPane , there is another property IsFloatingAllowed on DocumentContent . But there is no property to disable the floating of DockablePane yet. To style the DocumentPane and DockablePane I relied upon the Expression Blend. After opening my project in Expression blend , I navigated to the DockablePane and DocumentPane in Visual Tree and used the option "Edit Copy of Template". This option make's the default style of DocumentPane and DockablePane available to us, Now you are free to edit the style as you like. The default style contains the Control template for both DockablePane and DocumentPane in their respective styles. We can edit them to get our desired look .

But there is one issue , after we save our project in Expression Blend with edited styles, it seems that Expression Blend removes the command binding from the style of DockablePane for Close Button and AutoHide Button. So if we run the application you will notice that close and autohide button on DocakblePane no longer works. The solution is to reintroduce the command binding for close and autohide button by specifying Command="ad:DockablePane.ToggleAutoHideCommand" and Command="ad:DockablePane.CloseCommand" in the respective xaml Button tags.


<ad:DockingManager x:Name="dockManager" RenderTransformOrigin="0,0">
<ad:ResizingPanel Orientation="Vertical" >
<ad:ResizingPanel Orientation="Horizontal" >
<ad:DockablePane
x:Name="story" Style="{DynamicResource DockablePaneStyleMosaic}">
<ad:DockableContent StateChanged="Live_StateChanged"
IsCloseable="False" DockableStyle="DockableToBorders" Title="Live">
</ad:DockableContent>
</ad:DockablePane>

<ad:DocumentPane Style="{DynamicResource DocumentPaneStyleMosaic}" >
<ad:DocumentContent Title="Recorded"
IsFloatingAllowed="False" IsCloseable="False">
</ad:DocumentContent>
</ad:DocumentPane>

<ad:DockablePane Style="{DynamicResource DockablePaneStyleMosaic}">
<ad:DockableContent
StateChanged="Live_StateChanged"
DockableStyle="DockableToBorders" IsCloseable="False" Title="Reports">
</ad:DockableContent>
</ad:DockablePane>

</ad:ResizingPanel>
</ad:ResizingPanel>
</ad:DockingManager>



.
There is another catch , all the edited style that we have applied on DockablePane gets removed once the DockablePane is in floating state . So once the DockablePane is dragged in floating state , all the style is lost. To get around this problem we can use StateChanged event fired by the DockablePane whenever the state is changed from Docked to floating and vice-versa.



private void Live_StateChanged(object sender,
AvalonDock.DockableContentState state)
{
try
{

AvalonDock.DockableContent panel =
sender as AvalonDock.DockableContent;

if(state == AvalonDock.DockableContentState.Docked )
{
(panel.Parent as AvalonDock.DockablePane).Style =
this.FindResource("DockablePaneStyleMosaic") as Style;

}

//Floating
if (state == AvalonDock.DockableContentState.DockableWindow )
{
(panel.Parent as AvalonDock.DockablePane).Style =
this.FindResource("DockablePaneStyleMosaic") as Style;
}
}
catch (Exception ex)
{
LogWriter.WriteLog("", ex);
}
}




As long as Avalon dock fulfills the requirement of my project , I am going to stick with it.
http://avalondock.codeplex.com/

Saturday, February 20, 2010

WPF- Model-View-ViewModel

When it comes to WPF development, WPF provides us with its wide range of features to use. WPF is rich in features and give us more power to develop highly detailed and quailty UI 's. It give us more power and control over our development. On the other hand I came to WPF development from Windows Forms and it did really helps to start fresh with WFP and leave the Win Form concepts for Win Forms. But as I got deeper in WPF , I realized the power it has to offer. The features like Data Templating, Control Templating, Command Binding, Routed Events, Styles , Resources etc give us the exact power to create a line of bussiness
application with rich UI's.


One thing that brings all the features of WPF to there full powress is building the WPF apps with the use of Model-View-ViewModel pattern This pattern combines all the features of WPF and utilizes them to create the application that has clear seperation between the UI and Logic . Application is loosly coupled and testable when developed using the MVVM pattern.



















MVVM seperates the application design in three parts, Model, ViewModel, Views. Model act as the datarepositry and has the database connectivity or database mapped classes. It can be anything Linq-2-Sql, Entity Framework or any other ORM classes. Model are there and are not aware of anything (View Model or Views).



Next are the ViewModel classes that holds the logic for the actions that are done on Views . ViewModel classes are used to set up as the DataContext of the Views. In WPF , setting up datacontext of a control means that child element's also has its datacontext set as that of parent, if not exclusivly defined otherwise. By setting up the ViewModel as datacontext for a View we can set several datasources for various elements in Views .

void MainView_Loaded(object sender, RoutedEventArgs e)
{
_mainVM = new MainWinViewModel();
_mainVM.OnCloseEvent += new Action(_mainVM_OnCloseEvent);
this.DataContext = _mainVM;
}


View Model also simply encapsulate the Model classes. But its the CommandBinding feature of WPF that is utilized to communicate from Views to the ViewModel. As of the pattern, Views actually contains no code but only the xaml. That means we have to setup command binding in xaml for any user action to be delivered to the ViewModel to act upon. For this we define Commands in ViewModel and after setting it as the datacontext of the view , we bind the commands to various elements in View. These commands are known as Delegated Command or Relayed Command.


public class CustomersViewModel : ViewModelBase,
IDataErrorInfo
{
private Customer_Mst _custMst = null;
public string CustomerName
{
get
{
return _custMst.CustomerName;
}
set
{
_custMst.CustomerName =
value;OnPropertyChanged("CustomerName");
}
}



public class CustomersMgrViewModel :ViewModelBase
{
private ICommand _saveCommand = null;
private ICommand _deleteCommand = null;
private ICommand _updateCommand = null;
private ICommand _searchCommand = null;
private CustomersViewModel _customer =null;
public event Action OnReloadDataSource;

public ICommand SaveCommand
{
get
{
if(_saveCommand == null)
{
_saveCommand = new
DelegatedCommand(p => Save(), p => CanSave());
}
return _saveCommand;
}
}
private void Save()
{
try
{
using(CustomersDataContext context
= new CustomersDataContext())
{
Customer_Mst custMst = new Customer_Mst();
custMst.CustomerId = Customer.CusomerId;
custMst.CustomerName = Customer.CustomerName;
custMst.OrderId = Customer.OrderId;
context.Customer_Msts.InsertOnSubmit(custMst);
context.SubmitChanges();

if(this.OnReloadDataSource != null)
{
this.OnReloadDataSource();
}
ClearAll();
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.Message,"Error");
}
}


Delegated/Relayed Command simply take delegate for Execute and CanExecute methods . ViewModel handles the action for these commands and perform any logic using Model classes .

public class DelegatedCommand : ICommand
{
readonly Action<-object> _execute;
readonly Predicate<-object> _canexecute;

public DelegatedCommand(Action<-object> execute)
: this(execute, null)
{
}
public DelegatedCommand(Action<-object> execute,
Predicate<-object> canexecute)
{
if (execute == null)
{
throw new ArgumentNullException("ExecuteNull");
}
this._execute = execute;
this._canexecute = canexecute;
}
public bool CanExecute(-object parameter)
{
return _canexecute == null ? true :
_canexecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public void Execute(-object parameter)
{
_execute(parameter);
}
}
}



View 's are simply the xaml file whose data context is set up as the relative ViewModel class. ViewModel provide the datasources for various elements in the View . View leverages the powerful features like styling , data templating, Resources, Control Templating etc to create unique UI's for the data from ViewModel data sources. Commands for the View Model act as the bridge between the View and the ViewModel.

There is no hard dependency between View and ViewMoldel, so ui designer can work independently and developer can code the logic. As previously said there is no code in Views and all the interaction code are handled by the ViewModel.



<-listbox name="lstCustomers" itemssource="{Binding}" issynchronizedwithcurrentitem="True">

<-stackpanel orientation="Horizontal" row="3" horizontalalignment="Right">
<-button name="btnSave" content="Save" width="70" command="{Binding Path= SaveCommand}">
<-button name="btnDelete" content="Delete" width="70" command="{Binding Path= DeleteCommand}">
<-button name="btnUpdate" content="Update" width="70" command="{Binding Path= UpdateCommand}">
<-button name="btnSearch" content="Search" width="70" command="{Binding Path= SearchCommand}">





Other resources. Book on MVVM by Josh Smith