Mostefai Mohammed Amine's Blog

Say That I Was Here !

Create a Multi-Checkbox List in WPF

Hi, In this tutorial, I will show how to implement a multi-checkbox WPF list that allows the selection of multiple items of any type. For this, will use the power of templates in WPF and generics of C#. We will also exploit the very useful “INotifyPropertyChanged” interface. First, let’s create a WPF project called “TestMultiCheck”. 1- Create the “SelectionItem” class Add a new class called “SelectionItem” that have to be generic. The code of the class is as follows: /// <summary> /// an item that will be selected in the multi check box /// </summary> /// <typeparam name="T"></typeparam> public class SelectionItem<T> : INotifyPropertyChanged { #region privat fields /// <summary> /// indicates if the item is selected /// </summary> private bool _isSelected; #endregion   public SelectionItem(T element, bool isSelected) { Element = element; IsSelected = IsSelected; }   public SelectionItem(T element):this(element,false) {   }   #region public properties /// <summary> /// this UI-aware indicates if the element is selected or not /// </summary> public bool IsSelected { get { return _isSelected; } set { _isSelected = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsSelected")); } }   /// <summary> /// the element itself /// </summary> public T Element { get; set; } #endregion   #region INotifyPropertyChanged Members   public event PropertyChangedEventHandler PropertyChanged;   #endregion } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } The “SelectionItem” is a container for any element of the type “T”. The property IsSelected indicates if the item has been selected or not. Notice that the class implements the “INotifyPropertyChanged” interface to make the UI reacts if the selection is performed in code. 2- Create the “SelectionList” class Let’s add another generic class called “SelectionList” /// <summary> /// a list that will include the elements that will be selected /// </summary> /// <typeparam name="T"></typeparam> public class SelectionList<T> : List<SelectionItem<T>>, INotifyPropertyChanged { #region private fields /// <summary> /// the number of selected elements /// </summary> private int _selectionCount; #endregion   #region private methods /// <summary> /// this events responds to the "IsSelectedEvent" /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void item_PropertyChanged(object sender, PropertyChangedEventArgs e) { var item = sender as SelectionItem<T>; if ((item != null) && e.PropertyName == "IsSelected") { if (item.IsSelected) SelectionCount = SelectionCount + 1; else SelectionCount = SelectionCount - 1; } }   #endregion       public SelectionList() { }   /// <summary> /// creates the selection list from an existing simple list /// </summary> /// <param name="elements"></param> public SelectionList(IEnumerable<T> elements) { foreach (T element in elements) AddItem(element); }   #region public methods /// <summary> /// adds an element to the element and listens to its "IsSelected" property to update the SelectionCount property /// use this method insteand of the "Add" one /// </summary> /// <param name="element"></param> public void AddItem(T element) { var item = new SelectionItem<T>(element); item.PropertyChanged += item_PropertyChanged;   Add(item); }   /// <summary> /// gets the selected elements /// </summary> /// <returns></returns> public IEnumerable<T> GetSelection() { return this.Where(e => e.IsSelected).Select(e => e.Element); }   /// <summary> /// uses linq expression to select a part of an object (for example, only id) /// </summary> /// <typeparam name="U"></typeparam> /// <param name="expression"></param> /// <returns></returns> public IEnumerable<U> GetSelection<U>(Func<SelectionItem<T>, U> expression) { return this.Where(e => e.IsSelected).Select(expression); }   #endregion     #region public properties /// <summary> /// the selection count property is ui-bindable, returns the number of selected elements /// </summary> public int SelectionCount { get { return _selectionCount; }   private set { _selectionCount = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("SelectionCount")); } } #endregion   #region INotifyPropertyChanged Members   public event PropertyChangedEventHandler PropertyChanged;   #endregion } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } This class can be instantiated empty and filled using the “Additem” method. You can alternatively, use the second overload directly to create the list from an existing enumerable. The property “SelectionCount” indicates the number of selected elements. The first “GetSelection” methods returns all the selected elements. The second overload returns only a part using linq expressions. It could be very useful for database application to get directly the ids of the selected elements. 3- Create a Sample Entity To demonstrate the two classes, let’s create a sample entity called course defined as follows : public class Course { public Course() { }   public Course(int id, string name) { Id = id; Name = name; }   public int Id { get; set; }   public string Name { get; set; } } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } The tutorial will allow to select multiple courses 4- Create The XAML View In the mainwindow view, add a stackpanel, two buttons and a list box. The first button will be used to select / unselect an element in the list. The second button will be enabled only if at least one element is checked. Once clicked, it displays the names of the selected courses. The listbox will be converted using data templates to a list that displays a checkbox aside of the name of the course. For this, we will use the following data template : <DataTemplate x:Key="ListBoxItemTemplate" > <WrapPanel> <CheckBox Focusable="False" IsChecked="{Binding IsSelected}" VerticalAlignment="Center" /> <ContentPresenter Content="{Binding Element.Name, Mode=OneTime}" Margin="2,0" /> </WrapPanel> </DataTemplate> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } The default behavior of the listbox is to display vertically its items. It is not the perfect behavior that we are looking for. It would be better to display the checkboxes side by side, for this, we will used an alternative ItemsPanelTempolate based on “WrapPanels” : <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal"></WrapPanel> </ItemsPanelTemplate> </ListBox.ItemsPanel> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } To make this behavior concrete, we have to deactivate the horizontal scrolling in the listbox. The full view xaml is like follows: <Window x:Class="TestMultiCheck.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"> <Window.Resources> <DataTemplate x:Key="ListBoxItemTemplate" > <WrapPanel> <CheckBox Focusable="False" IsChecked="{Binding IsSelected}" VerticalAlignment="Center" /> <ContentPresenter Content="{Binding Element.Name, Mode=OneTime}" Margin="2,0" /> </WrapPanel> </DataTemplate> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="40" /> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal"> <Button Content="Select / Unselect Element By Code" Click="Button_Click" Margin="5"/> <Button x:Name="Save" Content="Save Selection" IsEnabled="False" Margin="5" Click="Save_Click"/> </StackPanel> <ListBox x:Name="myList" Grid.Row="1" Margin="5" ItemTemplate="{DynamicResource ListBoxItemTemplate}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal"></WrapPanel> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </Grid> </Window>   .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }5 – The Code Behind The code behind is as follows: public partial class MainWindow : Window { /// <summary> /// the selection list /// </summary> private SelectionList<Course> _list;   /// <summary> /// the list of courses /// </summary> Course[] courses = new Course[] { new Course(1, "course1"), new Course(2, "course2"), new Course(3, "course3"), new Course(4, "course4"), new Course(5, "course5")   }; public MainWindow() { InitializeComponent(); // create the list _list = new SelectionList<Course>(courses); // assign the source of the list (not necessary in an MVVM approach) myList.ItemsSource = _list; // listen to the property changed event to enable or disable the save button _list.PropertyChanged += list_PropertyChanged; }   void list_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { // the save button is enabled if at least one item is checked Save.IsEnabled = _list.SelectionCount > 0; }   private void Button_Click(object sender, RoutedEventArgs e) { // this methods checks or unchecks programmatically an item to view the UI reaction _list[1].IsSelected = !_list[1].IsSelected; }   private void Save_Click(object sender, RoutedEventArgs e) { // get the names of the selected courses IEnumerable<string> selection = _list.GetSelection(elt => elt.Element.Name); // concantenate the strings var text = string.Join(",", selection); MessageBox.Show(text); } } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } The window contains an array of courses called “courses” and a private selection list called “_list”. At the page load event we create the list, and we assign an event to the “PropertyChanged” event. We assign the list as itemssource of the listbox. In MVVM approaches, this could be performed by using bindings or conventions. The event “list_PropertyChanged” enabled or disables the “Save” button according to the number of the checked elements. The event “Button_Click” checks “programmatically an element of the list to see that the view is effectively bound to the “IsSelected” property. Finally, the “Save_Click” gets directly the names of the selected courses by using Linq expressions. Then, it displays them.             Enjoy ! The solution code can be downloaded here

Tutoriel 2.1 : Création d’une application ASP.NET à partir d’un modèle

Ceci est le premier des deux tutoriaux du module 2. Son objectif est de créer une application ASP.NET à partir du modèle fourni par Visual Studio 2012. Etape 1 – Créer une application ASP.NET L’objectif de cette étape est de créer une application ASP.NET à partir du modèle fourni avec Visual Studio. Lancez VS 2012 Choisir Fichier -> Nouveau -> Application ASP.NET Entrez « PremiereApp » dans la zone « Nom » Cliquez sur OK Examinez le contenu du projet Etape 2 : Exécution L’objectif de cette étape est de découvrir le comportement de l’application en exécution sur le navigateur. Exécutez l’application en appuyant sur « F5 »  Etape 3 : Découverte des Contrôles ASP.NET L’objectif de cette étape est de découvrir les contrôles ASP.NET dans la boîte à outils de Visual Studio. Fermez la fenêtre du navigateur Ouvrez le fichier « Default.aspx » en mode conception Examinez les différents contrôles dans la boîte à outils Etape 4 : Utilisation d’un contrôle serveur L’objectif de cette étape est d’ajouter un contrôle ASP.NET à une page existante, d’affecter des propriétés et de coder un évènement. Ouvrez la page « Contact.aspx » en mode conception Pointez le curseur à la fin puis appuyez sur « entrée » Remarquez la création d’un nouveau paragraphe « <p> » Par un glisser-déposer, insérez un composant « Libellé » dans le nouveau paragraphe Entrez votre nom dans la propriété « Text » Ajoutez un bouton après le libellé Entrez le texte « Changer » dans la propriété « Text » du bouton Double-cliquez le bouton Entrez le code suivant dans l’évènement généré ensuite exécutez l’application protected void Button1_Click(object sender, EventArgs e) { Label1.Text = DateTime.Now.ToString(); } Etape 5 : Examination des répertoires du projet L’objectif de cette étape est d’examiner la structure des répertoires d’un projet ASP.NET. Dans l’explorateur de solutions cliquez sur le bouton droit sur le projet Sélectionnez « Ouvrir dans l’explorateur de fichiers » Examinez l’arborescence des répertoires dans l’explorateur Windows Pour télécharger le code :  Tutoriel 2.1.zip (1,97 mb)