Showing posts with label Databinding. Show all posts
Showing posts with label Databinding. Show all posts

WPF Control: Listbox of checkbox with Search google-like

One thing that i like of WPF is the possibility of making easy-to-use controls to manage data.
A control that i use a lot of times to filter dataviews, charts, get queryes parameters and so on is a listbox of checkbox.
This isn't that special, but with ICollectionView and the possibility of having a fast way to filter results like the search box in google.com it become a really powerful tool.

I invite you to download the demo (link at the bottom of this page) to understand better.

Let's start from an example:
I have an observable collection of "Fruits", objects that contain a property "Name" and a property "Show" that indicates if the object has to be visualized or filtered.

To filter this collection i can use the ICollectionView, that permits to filter a collection and has a method Refresh() that reload the collection with the filter parameters.

So in the properties i add:
 class MyFruitCollection : ObservableCollection
    {

private ICollectionView filteredCollection;
public ICollectionView FilteredCollection { get { return filteredCollection; } }


and the filter string:

private string filter = "";
        public string Filter
        {
            get { return this.filter.ToUpperInvariant(); }
            set
            {
                if (this.filter != value)
                {
                    this.filter = value;
                    this.filteredCollection.Refresh(); //
Notice that i call Refresh() at every change of filter
                }
            }
        }


In the constructor of my collection i add some fruits(just for example) and i load the ICollectionView datasource:

        public MyFruitCollection()
        {
            this.Add(new MyFruit("Orange"));
            ...
            this.Add(new MyFruit("Watermelon"));

            this.filteredCollection = CollectionViewSource.GetDefaultView(this);
            this.filteredCollection.Filter = ContainsFilter;
        }

Then i set the filters on this method:

private bool ContainsFilter(object item)
        {
            var fruit = item as MyFruit;
            if (fruit == null)  //check if fruit is null
            {
                return false;
            }
            if (string.IsNullOrEmpty(this.Filter)) //check if search box is empty or null
            {
                return true; //show all items if there is no text in the search textbox
            }
            if (fruit.Name.ToUpperInvariant().Contains(this.Filter))
//checks if fruit.name contains the search text
            {
                return true;
            }
            return false; //if it doesn't contain anything don't show the item
        }


 Xaml is pretty simple, as usual it's all about databinding:

And this is the code behind:

    public partial class MainWindow : Window
    {

MyFruitCollection fruitCollection = new MyFruitCollection();

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = fruitCollection;
//notice that all the application is in binding
        }

...
}

The resul is pretty cool and it makes apps a lot more confortable, just try yourself :)
Download the example here:
http://mesta-automation.com/Downloads/Selection%20control.rar

Databinding #3: binding directly to a Property with INotifyPropertyChanged

Hi,
this is the last part about databinding.
You can find the 1st part here and the 2nd part here
We saw how to bind UI controls on UI elements and on elements that belongs to a collection.
We noticed also that when an observable collection changes(if one item get added or removed), is changes also the UI elements in bind with the collection; the limit of observable collection is that if i change a property in a element inside it, it doesn't update it.
To do this update of property inside elements of a collection, we need to implement an interface, called INotifyPropertyChanged, that fires an event when the property changes, updating all the elements that are in bind with it.

Let's analyse an example:
i 2 tanks, and i have a collection of 2 liquid (liquid[0] and liquid[1]).
Liquid[0] is the content inside the 1st tank, liquid[1] is the content inside the 2nd tank.
I want to change the color (or state) of content changing the property inside the class, and i want that the UI updates the color when it changes of course.
Let's write the new class for the content:


class Liquid:System.ComponentModel.INotifyPropertyChanged
{
public string Name { get; private set; }

private SolidColorBrush liquidColor;
public SolidColorBrush LiquidColor { 
get
{
return liquidColor;
}
private set 
{ 
liquidColor = value; 
this.OnPropertyChanged("LiquidColor");
}
}

public Liquid(string name, Color color) 
{
this.Name = name;
this.LiquidColor = new SolidColorBrush(color);            
}

public void Change(SolidColorBrush newColor) 
{
this.LiquidColor = newColor; 
}

public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}

This is the implementation if INotifyPropertyChanged.
In the bottom part there is the definition of the event that i throw, and inside the declaration of the property LiquidColor i throw the event every time that this the property changes.
Then i added a method Change, that changes the color with a new one.

Let's define a liquid collection:
class LiquidCollection:ObservableCollection

{

public LiquidCollection() 

{ 

this.Add(new Liquid("Liquid Silos 1", Colors.Aqua));

this.Add(new Liquid("Liquid Silos 2", Colors.Orange));

}

}


Datacontest:
public MainWindow()

{

InitializeComponent();



LiquidCollection liquids = new LiquidCollection();

ellipseSilos1.DataContext = liquids[0];

ellipseSilos2.DataContext = liquids[1];

}


and 2 button's callbacks that change colors to each silos:
private void btnChangeS1_Click(object sender, RoutedEventArgs e)

{

((Liquid)ellipseSilos1.DataContext).Change(colors[i]);

if (i < 10) i++; else i = 0;

}



private void btnChangeS2_Click(object sender, RoutedEventArgs e)

{

((Liquid)ellipseSilos2.DataContext).Change(colors[i]);

if (i < 10) i++; else i = 0;

}


UI Databinding now refers directly to the property that changes:

And we have the UI update when property changes inside the collection.



As usual the complete solution can be found here: 
http://www.mesta-automation.com/Downloads/Databinding3.rar

Next post i'll make a simple project in wpf where i connect an opc server to the UI through databinding.

Databinding #2 and ItemsTemplate: why we use observable collection and the 1st try to give a representation of an object

This is the 2nd article about databinding.
The 1st can be found here and the 3rd here.
As the name says, observable collection is a collection that send an event when items are added or removed from it.
This is really useful in automation for manage recipes for examples, but basically you can manage everything: it can be also a collection of machines, a collection of silos, and so on.
I use observable collection a lot for charts and to manage big lists of similar items.

This is an example on how to use an observable collection:
Let's suppose that i have my usual tank, like in the previous example, and i want to add some new liquids to the listbox, and i want also to remove them.
Of course i want to see changes in real time, and i want to write as less code as possible.

So as usual i define my data class:
class Liquid
    {
        public string Name { get; private set; }
        public SolidColorBrush LiquidColor { get; private set; }        
        public Liquid(string name, Color color) 
        {
            this.Name = name;
            this.LiquidColor = new SolidColorBrush(color);            
        } 

And my observable collection of liquids, with 3 samples :
    class LiquidCollection : ObservableCollection
    {
        public LiquidCollection() 
        {  
            this.Add(EmptyCilinder());
            ...
            this.Add(OrangeLiquid());      
        }
        private Liquid EmptyCilinder()
        {  return new Liquid("Empty Cilinder", Colors.Gray);  }
       ...
        private Liquid OrangeLiquid()
        {  return new Liquid("Orange liquid", Colors.Orange); }        
    }

Then i add a custom color collection where i cover all the colors:
class CustomColorCollection : ObservableCollection
    {
        public CustomColorCollection() 
        {
            this.Add(new SolidColorBrush(Colors.Aqua));
            ....
            this.Add(new SolidColorBrush(Colors.Gold));
        }
    }

Then i place 2 listbox, 1 textbox and 2 buttons in the User Interface, in the code behing as usual i set the datacontext:
public MainWindow()
        {
            InitializeComponent();
            lstSelectColor.DataContext = new LiquidCollection();
            lstLiquidColors.DataContext = new CustomColorCollection();
        }

and the 2 buttons callback:
private void btnAddLiquid_Click(object sender, RoutedEventArgs e)
        {
((LiquidCollection)lstSelectColor.DataContext).Add(new Liquid(txtNameNewLiquid.Text,    ((SolidColorBrush)lstLiquidColors.SelectedItem).Color));
}

        private void btnRemoveLiquid_Click(object sender, RoutedEventArgs e)
        {
((LiquidCollection)lstSelectColor.DataContext).Remove((Liquid)lstSelectColor.SelectedItem);
}

And this is the UI (to binding items refere at the post of databinding #1):

Compiling and running i obtain what i want, so i have a list of colors and a list of liquids that i can update, adding or removing.


The only problem is that the list of color sux. In this case we need to use an ItemTemplate to give a representation of an object Color in the listbox.

A good way can be represent it on a rectangle, and this could be done in this way:
If we compile and debug we obtain something better, that it's similar to this:

I think that doing this with winforms it's really hard, but with WPF and a bit of imagination it will take not so much time, and the final users will be happier than to see a listbox with "Green - Dark Green - Light Green - Purple - and so on..."

As usual you can find the full solution here:
http://mesta-automation.com/Downloads/databinding2.rar

Why WPF for automation? Databinding #1

This is the 1st article of 3 about DataBinding.
Check the 2nd here and the 3rd here.
It's clear that WPF has a better graphic and appearence, with all of those gradients, animations and so on, but what are the real benefits for a programmer ?
The Page-Switch application was a good start, but why should we learn xaml (that is also a new concept and quite hard) instead of using our loved winforms and GDI ?
I think that the best reason to learn WPF is that it permits to build easy-to-use and self-explained interfaces for operators, with really little code-writing.
Let's suppose that i wanted to display lisbox of radiobuttons, or treeview of checkbox... it would be hard to write this controls in winforms and they would have a lot of bugs inside.
That's why winforms got a lot of custom control (not free of course) around the ne.
In WPF, thanks to a pattern that separates graphics from code-behind, it's possible to have complex controls with not many troubles.
Model - View - View Model is the pattern that permit to developpers to separate physically the User Interface part from the code behind, and this is possible because of a powerful concept on wich WPF is based: DataBinding.

Basically Model - View - View Model consist in this:
Model : all the codebehind, services and so on  that permit to the application to run (like the code that was written in winforms)
View: the User Interface, all the code that we write in XAML.
View Model: this is new, this is the layer between UI and code behind, it's based on data binding and it save us a lot of code that can have a lot of bugs, and it's usually the code that connects the UI with business objects. One important fact to keep in mind is that in automation we have tons of controls to display tons of values, infact usually little scada and HMI displays timers, analogic values, alarms and some output status, but in bigger ones there are a lot of other factor too, like keeping track of values while time changes and so on. View Model permit to connect the User Interface with Objects, that can come for example from an OPC Client, with really little code.

To explain it better i'll make an example:
I want to fill a tank (here is designed really poorly) with a liquid that i select from a listbox, and i want to see the tank changing color when i change its content.
I don't want to use events and a lot of code to do this thing, also i want to define a class Liquid and a collection of them, because they can change during production, and i would like to update them easily.

So let's write the liquid class:
using System.Windows.Media;
namespace SilosSample.Data
{
    class Liquid
    {
        public string Name { get; private set; } //name of liquid       
        public LinearGradientBrush LiquidColor { get; private set; } //color
       

        public Liquid(string name, GradientStopCollection _gradStopCollection)
        {
            this.Name = name;
            this.LiquidColor = new LinearGradientBrush(_gradStopCollection);
        }
    }
}


Then fill the collection (in reality members would be taken from a database, with more parameters than a name and a color)
using System.Collections.ObjectModel;
using System.Windows.Media;
using SilosSample.Data;
namespace SilosSample.ViewModel
{
    class LinearGradientCollection : ObservableCollection
    {
        public LinearGradientCollection()
        {
            this.Add(EmptyCilinder());
            this.Add(Water());
            this.Add(OrangeLiquid());           
        }
        private Liquid EmptyCilinder()
        {
            GradientStopCollection gradStopCollection = new GradientStopCollection();      
            gradStopCollection.Add( new GradientStop(Colors.LightGray,0));
            gradStopCollection.Add(new GradientStop(Colors.Black, 0.992));
            gradStopCollection.Add(new GradientStop(Colors.DarkGray, 0.125));
            gradStopCollection.Add(new GradientStop(Colors.Gray, 0.802));
            return new Liquid("Empty Cilinder", gradStopCollection);
        }
        private Liquid Water()
        {
                GradientStopCollection gradStopCollection = new GradientStopCollection();
                gradStopCollection.Add(new GradientStop(Colors.LightCyan, 0));
                gradStopCollection.Add(new GradientStop(Colors.DarkBlue, 0.992));
                return new Liquid("Water", gradStopCollection);
        }
        private Liquid OrangeLiquid()
        {
                GradientStopCollection gradStopCollection = new GradientStopCollection();
                gradStopCollection.Add(new GradientStop(Colors.LightCoral, 0));
                gradStopCollection.Add(new GradientStop(Colors.Orange, 0.992));
                return new Liquid("Orange liquid", gradStopCollection);
        }
    }
}

And now i want to connect(to bind) my user interface to the collection.
this is done in this way:
define a datacontext (it's the datasource, in this case my collection of colors) in the codebehind  for the listbox:
public partial class MainWindow : Window
    {     
        public MainWindow()
        {
            InitializeComponent();
            lstSelectColor.DataContext = new LinearGradientCollection();
//my collection    
        }
    }

Then write the User Interface and bind the properties that you want to control directly with XAML:
in this case i wanted that my listbox contains the collection (so datasource was in bind with all the datacontext), i wanted to display only the name (displayMemberPath is always the same as old one), and i wanted to synchronize the current element with the rest of the window, so i can update my controls without writing a single line of code.
Then to fill the silos there, i just need to bind the property "Fill" at the selected item of the listbox, just as it's written in the code.


This is really a simple example, but it's amazing how powerful it is WPF and how little code you have to write to obtain sophisticated controls.
In a future post i'll cover also the interface "INotifyPropertyChanged", that permit to update an item in a collection and also the items in bind with it (example: i have a collection of silos and i want to update the color of one of them).

As usual i add the complete solution:http://www.megaupload.com/?d=IQUX2NVX

To see more about ObservableCollection, INotifyPropertyChanged and normal collections, see this post: http://www.codeproject.com/KB/silverlight/SLListVsOCollections.aspx