Thursday, February 10, 2011

Combo Box drop down on Mouse Leave/ Mouse Enter in XAML

Want your combobox to drop when you hover on it? And hide items when leave combobox? You are at the right place to find the answer.

Download sample project here.

Achieving this is not straight forward. You need to do some tweaking with the Combox style itself. In Expression Blend create a copy of the combobox template and rename it to comboboxstyle

image

You see a template structure created. Below are the parts.

image

So, you need On MainGrid MouseEnter = Popup.Open; On MainGrid.MouseLeave = Popup.Close. Below is the code which does that.

<Grid x:Name="MainGrid" SnapsToDevicePixels="true">
<
Grid.ColumnDefinitions
>
<
ColumnDefinition Width
="*"/>
<
ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width
="0"/>
</
Grid.ColumnDefinitions
>
<
i:Interaction.Triggers>
<
i:EventTrigger EventName
="MouseEnter">
<
ei:ChangePropertyAction TargetObject="{Binding ElementName=PART_Popup}" PropertyName="IsOpen" Value
="True"/>
</
i:EventTrigger
>
<
i:EventTrigger EventName
="MouseLeave">
<
ei:ChangePropertyAction TargetObject="{Binding ElementName=PART_Popup}" PropertyName="IsOpen" Value
="False"/>
</
i:EventTrigger
>
</
i:Interaction.Triggers
>
<
Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
<
Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName
=MainGrid}">
<
Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors
.WindowBrushKey}}">
<
ScrollViewer x:Name
="DropDownScrollViewer">
<
Grid RenderOptions.ClearTypeHint
="Enabled">
<
Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width
="0">
<
Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName
=DropDownBorder}"/>
</
Canvas
>
<
ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels
}"/>
</
Grid
>
</
ScrollViewer
>
</
Border
>
</
Microsoft_Windows_Themes:SystemDropShadowChrome
>
</
Popup
>
<
ToggleButton BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxReadonlyToggleButton
}"/>
<
ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment
}"/>
</
Grid
>

Enumeration (Enum) in XAML

This post describes how to use C# Enumerations in XAML. There are multiple usages exposing enumerations in XAML.

Download sample application here.

Declare the enumeration outside a class in a namespace XXX.

namespace ApplicationWithEnumeration
{
/// <summary>
///
Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
}

public enum Person
{
None1,
Patient1,
Employee1,
Doctor1,
Nurse1
}
}
Use the namespace in the XAML side.
xmlns:local="clr-namespace:ApplicationWithEnumeration"
- OR -
xmlns:XXX="clr-namespace:****"
Done! now you can use it with below declaration.
{x:Static local:Person.Patient1}"

Example,

<ComboBoxItem Content="Patient" Style="{DynamicResource SimpleComboBoxItem}" Tag="{x:Static local:Person.Patient1}" />
- OR - 
<Label Content="{x:Static local:Person.Patient1}" Margin="52.2,0,68.2,46.04" Style="{DynamicResource SimpleLabel}" VerticalAlignment="Bottom" Background="#006F5A5A"/>

Similarly, you can use it iin ChangePropertyAction as parameter dependency and InvokeCommandAction as CommandParamters.


Folks, if you are aware of other usages, please post in the Comments section. I can append to the post later.

Sunday, February 6, 2011

Using ViewModel in Views (The MVVM way)

The article says how to use one/more ViewMiodels in a View. Also, multiple Views using same ViewModel. Read this post to create a ViewModel.

There are several ways of using ViewModel in a XAML file based on the different scenarios.

Case 1: Initialize a ViewModel without any constructor parameters.

Read this post. This article also expects the reader to be familiar with Expression Blend.

Case 2: Initialize a ViewModel with constructor parameters.

xmlns:local="clr-namespace:****your namespace***"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<ObjectDataProvider ObjectType="{x:Type local:ViewModel}" x:Key="theViewModel">            <ObjectDataProvider.ConstructorParameters>
<
sys:String>Uday</sys:String>
<
sys:Int32>25</sys:Int32>
</
ObjectDataProvider.ConstructorParameters>
</
ObjectDataProvider>

Notice the System namespace declaration. We can use any data type from System namespace as a constructor parameter. If you have custom data types you can pass them too as a constructor parameter; by declaring namespace in XAML file.


Case 3: In the above two cases, the object can be accessed on the C# side (as a Resource). However, if you update the object in C# side, the ViewModel values are NOT reflected on the XAML side. Now what??!  We can declare a ViewModel object on the C# side and declare it as DataContext for the XAML side. Here is how to do it.

public partial class MainWindow : Window
{
private ViewModel theViewModel = new ViewModel();

public MainWindow()
{
InitializeComponent();
this.DataContext = theViewModel;
}

private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
theViewModel.FirstName = "I am still typing";
}
}

In this way, any updates from XAML side would be seen on C# side too. But, if you use Expression Blend, the ViewModel is not seen in the designer, so you have to write the binding code manually. I wouldn’t suggest this way, but sometime its not up to your choice!

Saturday, February 5, 2011

View Model data binding to the View(XAML) using Expression Blend 4

This tutorial uses Expression Blend 4. Refer to my previous post for creating ViewModel and data binding.

In E Blend, create a link for the viewModel structure as below:

image

Edit a name for the DataSource; rename it ‘theViewModel’

SNAGHTML27cf514

After the adding the data source, you can see theViewModel section under ‘Data’. All the properties and methods are exposed in expression blend.

image


Create some UI elements on the View.

image

Ready to create some bindings??

image

image

image

Done?!  Did you notice the value is seen under the Text property immediately . All data bound UI elements show values at design time.

image

Binding with the variables is simple; however calling ViewModel’s method on button click (or on other events) needs some additional work. From behaviors section, drag ‘CallMethodAction’ and drog on the ‘Update Info’ Button.

image

This action adds references to ‘Microsoft.Expression.Interactions.dll’ This action will create a CallMethodAction as child to the button. Edit its Properties as shown below.

image

DONE! now, when you click the button, the Update Method is called. Editing the textboxes will update the view model variables instantaneously.

Download sample application here. Here is the code for it:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ViewModelDatabinding" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" mc:Ignorable="d" x:Class="ViewModelDatabinding.MainWindow"
Title="MainWindow" Height="350" Width="525">
<
Window.Resources>
<
local:ViewModel x:Key="theViewModel" d:IsDataSource="True"/>
</
Window.Resources>
<
Grid DataContext="{Binding Source={StaticResource theViewModel}}">
<
TextBox HorizontalAlignment="Left" Margin="42.4,43.2,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="153.953" Text="{Binding FirstName}"/>
<
TextBox HorizontalAlignment="Left" Margin="42.4,92,0,0" TextWrapping="Wrap" Text="{Binding LastName}" VerticalAlignment="Top" Width="153.953"/>
<
Slider x:Name="slider" HorizontalAlignment="Left" Margin="42.4,148,0,144" d:LayoutOverrides="Height" Width="153.953" Maximum="100" Minimum="1" SmallChange="1" IsSnapToTickEnabled="True" Value="{Binding Age}"/>
<
Label Content="{Binding Value, ElementName=slider}" HorizontalAlignment="Left" Margin="213.6,148,0,140.04" d:LayoutOverrides="Height"/>
<
Button Content="Update Info" HorizontalAlignment="Left" Margin="58.4,0,0,32.04" VerticalAlignment="Bottom" Width="95.8" Height="78.76">
<
i:Interaction.Triggers>
<
i:EventTrigger EventName="Click">
<
ei:CallMethodAction TargetObject="{Binding Mode=OneWay}" MethodName="Update"/>
</
i:EventTrigger>
</
i:Interaction.Triggers>
</
Button>
</
Grid>
</
Window>

View Model 101

A View Model(VM) is a .cs file containing all the data required for the XAML file. It is like a code behind for a XAML file which holds all the data logic, data variables and methods required for the XAML UI layer(also referred as ‘View’) to show data.

Then, what's in the MainWindow.cs??

If you have a perfect VM design, thenMainWindow.cs should have ONLY the constructor with InitializeComponent() method. But, we cant achieve this most of the time. It often includes some complex event handler call back functions.

Here are some examples';

To achieve MainWindow.cs VM
On selecting a record from a datagrid full of patients; should show a Message Box with patient Info. On RecodActivated call back method with Message Box functionality. A datatable containing all the patient info.
On a button.click event, load information from a file and also enable the associated datagrid Enable the datagrid A method to load information from file.

Most of the event handling can be done through XAML; Expression Blend 4 is mature enough to enable/disable/converter values using data binding.


Before we start, read about Properties and INotifyPropertyChanged.

ONLY the public Properties and public methods of VM are accessible by the View/XAML file. You can create Properties with code snippets prop or propfull

Sample VM,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace ViewModelDatabinding
{
public class ViewModel : INotifyPropertyChanged
{

#region Property Changed Event

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}

#endregion

private string
firstName;
public string FirstName
{
get { return firstName; }
set { firstName = value; OnPropertyChanged("FirstName"); }
}

private string lastName;
public string LastName
{
get { return lastName; }
set { lastName = value; OnPropertyChanged("LastName");}
}

private double age;
public double Age
{
get { return age; }
set { age = value; }
}

public ViewModel()
{
FirstName = "Uday";
LastName = "Thummalapalli";
Age = 25;
}

public void Update()
{
FirstName = "Dr. Uday";
LastName = "Genius";
Age = 29;
}

}
}

What is Data Binding in WPF? how is it used?

In Windows Forms, developer creates the UI and updates the UI elements’ content and states based on the certain conditions. For example, in the designer we create a textbox  and write a logic to update the content of the textbox.

image

For the button1 and button2 Click event; we write a call  back function.

private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "User Uday";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            textBox1.Text = "User Kiran";
        }

Now, when we click button1; textbox1 changes to “User Uday” and “User Kiran”.

In a real world situation, we have to execute the code

textBox1.Text = "User ****";

when the a user is selected from a huge list. Imagine 50 such textboxes and 100 labels and update logic in the code behind. so many lines of code, isn't it?


WPF allows data binding where the textbox1 keeps monitoring on a particular variable/string. Whenever the value of the variable/string updates; the textbox1.Text also updates. Now, wouldn’t that be nice that all the elements in the UI update keeps monitoring(binding) on a set of variables?

Here is an example. draw textBox using designer. Click here to download the sample applicatiion.

image

Write the data binding for the text property to the Windows width property in xaml,

<Window x:Name="window" x:Class="SampleTextBoxBinding.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Sample TextBox Binding" Height="188" Width="273">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="62,65,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Width, ElementName=window}" />
    </Grid>
</Window>

Now, if the increase the window size the value updates during runtime;

SNAGHTML2a3294

GREAT!

Now, how cam I do this functionality to make an application? Click here for sample application

SNAGHTML6c0178

Below is the code for it.

<Window x:Class="SalutaionName.MainWindow"
        xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="DataBinding Example" Height="256.4" Width="633.8">
    <Grid>
        <CheckBox x:Name="checkBox" Content="Salutation" HorizontalAlignment="Left" Margin="13.4,46.6,0,0" VerticalAlignment="Top" FontFamily="Times New Roman" FontSize="16"/>
        <CheckBox x:Name="checkBox1" Content="First Name" HorizontalAlignment="Left" Margin="13.4,78.6,0,0" VerticalAlignment="Top" FontFamily="Times New Roman" FontSize="16"/>
        <CheckBox x:Name="checkBox2" Content="Last Name" HorizontalAlignment="Left" Margin="13.4,110.6,0,0" VerticalAlignment="Top" FontFamily="Times New Roman" FontSize="16"/>
        <TextBox x:Name="textBox" Margin="115.8,78.6,8,0" TextWrapping="Wrap" VerticalAlignment="Top" IsEnabled="{Binding IsChecked, ElementName=checkBox1}" FontFamily="Times New Roman" FontSize="16" Text="FName"/>
        <TextBox x:Name="textBox1" Margin="115.8,107.6,8,0" TextWrapping="Wrap" VerticalAlignment="Top" IsEnabled="{Binding IsChecked, ElementName=checkBox2}" FontFamily="Times New Roman" FontSize="16" Text="LName"/>
        <ComboBox x:Name="comboBox" Margin="115.8,46.6,8,0" VerticalAlignment="Top" IsEnabled="{Binding IsChecked, ElementName=checkBox}" FontFamily="Times New Roman" FontSize="16" SelectedIndex="0">
            <sys:String>Mr</sys:String>
            <sys:String>Dr</sys:String>
            <sys:String>Majesty</sys:String>
            <sys:String>Highness</sys:String>           
        </ComboBox>
        <TextBlock Margin="13.4,157,8,8" TextWrapping="Wrap" FontFamily="Times New Roman" FontSize="16">
        <TextBlock.Text>
            <MultiBinding StringFormat="{}{0}. {1} {2}">
                  <Binding ElementName="comboBox" Path="SelectedValue" Mode="OneWay"/>
                <Binding ElementName="textBox" Path="Text" Mode="OneWay"/>
                <Binding ElementName="textBox1" Path="Text" Mode="OneWay"/>
    </MultiBinding>
  </TextBlock.Text>
        
        </TextBlock>
       
    </Grid>
</Window>

Wednesday, April 28, 2010

Deploying Custom made Visual Studio prerequisites using Bootstrapper Manifest Generator

Do you want your setup installer install Software 'X' before the actual program is installed, using Visual Studio Development?

The Software 'X' is called a prerequisite and can be Java Run Time, DirectX, 3rd party plugin installation etc.

Checker >> There are in-built prerequisite supported by Visual Studio. Open a Setup and Deployment project in Visual Studio... From the menu, select Project >> Properties...; or Hit Alt + F7.

Select Prerequisites...

Now, you would see a list of prerequisites listed here.

You can add a custom prerequisite of your choice. Here is how to do it,

Things to download:
1) Bootstrapper Manifest Generator (BMG)

Click here to download.

2) I want to create a prerequisite fir Visual J# 2.0. I have downloaded the required setup files for 32-bit and 64-bit.

32-bit
64-bit

Instructions:
1) Install BMG, Visual J# 32-bit and 64-bit.

2) Open BMG, create a new file. Select Package Manifest...

3) Rename the Product name, Product Code to Visual J

4) I have to install the particular version of Visual J# based on the OS bit version and if it is installed. To accomplish this, I have made some Install checks and OS checks. Please read about registry checks if you need to install software based on the existing version.

Select the System Checks tab and select the MSI product check... As you have already installed the 32-bit and 64-bit Visual J#, you will find them in this list. Name them with a property which you will be using in future.

5) Add Install File... Browser to the downloaded Visual J# 32-bit and 64-bit .exe files.
Select vjredist.exe. Rename the Display Name. Select Install Conditions...

Add these two conditions...
BypassIf >> ProcessorArchitecture = AMD64
BypassIf >> VJInstall > 2


this means you want to skip this installer if the OS is 64 bit and Visual J is already installed (> 2).

Select the Exit Codes and set them..
0 >> Success
1641 >> Success, Reboot Needed
3010 >> Success, Reboot Needed

Similarly select conditions for vjredist64.exe

Add these two conditions...
BypassIf >> ProcessorArchitecture = AMD64
BypassIf >> VJInstall > 2

Set the same Exit Codes as before..

6) Save and the Package Manifest file and build it...

7) Go to Document and you will find a folder named Visual J. Copy this folder to C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bootstrapper\Packages .

8) Repeat Checker and now you will find the Visual J here. Select it. Uninstall Visual J# 32 - bit and 64 - bit. Trying running the setup file after you compile your Visual Studio project. The installer detects you do not have Visual J and gives your an option to install.

Cheers.