Archive for the ‘WPF’ Category.

www.wpftutorial.net – just found a new WPF Tutorial site

I just found http://www.wpftutorial.net.

Just another resource for WPF information.

A Hello World template of a WPF application using MVVM

Hey all,

I created an MVVM project and then saved it as a template.  This way when I create new projects, I can simple choose MVVM Base and save a ton of time.

You can use my template if you want.  You can download it here: MVVM Base.zip

How to add the MVVM Base template to your Visual Studio

If you want this to be available as a new project type in you Visual Studio install, follow these steps.

  1. go to this path under My Documents:Visual Studio 2010\My Exported Templates
  2. Download this template to that directory. MVVM Base.zip
  3. Create a new Visual Studio Project and choose MVVM Base from the list of C# projects.

A Progress Bar using WPF's Progress Bar Control, BackgroundWorker, and MVVM

Hey all,

WPF provides a ProgressBar control.  But there isn’t really a manual for it, especially if you want to follow MVVM.

So I am going to make a little application that counts from zero to ten and tracks the progress.  You are going to see when it is OK to use the foreground and when it is not OK but better to use BackgroundWorker.

While much of this code may be production ready, you should be aware that this code intentionally implements a foreground process that is an example of what not to do.

Prerequisites

  • Visual Studio

Step 1 – Create a new WPF Application Project

  1. In Visual Studio, create a new Solution and choose WPF Application
  2. Give it a name.
  3. Hit OK.

Step 2 – Add two base MVVM files

There are two basic classes used for MVVM.

  • RelayCommand
  • ViewModelBase

These are found on different blogs and different posts all over the internet, so I would say they are public domain, or free and unlicensed.

  1. Download them zipped here. MVVM
  2. Extract the zip file.
  3. Add the MVVM folder and the two class under it to your project.

Step 3 – Create a ProgressBarViewModel class

  1. Create a new Class called ProgressBarViewModel.
  2. Adding a using MVVM statement at the top.
  3. Make the class inherit ViewModelBase.
    class ProgressBarViewModel : ViewModelBase
    {
    }
    

This will be populated as we create our View.

Step 4 – Design the GUI in MainWindow.xaml

Ok, so lets create the GUI.

  1. Add a local reference. (Line 4)
  2. Add a ProgressBarViewModel object as a resource. (Lines 6-8)
  3. Create a StackPanel in the default Grid to put everything in. (Line 10)
  4. Add a one character label in great big text to display our number. (Line 11)
  5. Add a ProgressBar element. (Line 12)
  6. Create buttons to manipulate the label. (Lines 13-16)
  7. Configure the DataContext of each element to be the the ProgressBarViewModel using the Key PBVM we gave it when we added it as a resource. (Lines 11-16)
  8. Think of and create Binding Paths for each element. Yes, we can basically just make these Path names up and add them to the ProgressBarViewModel later. (Lines 11-16)

Here is the XAML.

<Window x:Class="WPFProgressBarUsingBackgroundWorker.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPFProgressBarUsingBackgroundWorker"
        Title="MainWindow" >
    <Window.Resources>
        <local:ProgressBarViewModel x:Key="PBVM" />
    </Window.Resources>
    <Grid>
        <StackPanel>
            <Label Content="{Binding Path=Value}" DataContext="{StaticResource ResourceKey=PBVM}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Name="labelNumberCounter" VerticalAlignment="Center" FontSize="175" />
            <ProgressBar Margin="0,3,0,3" Height="20" Name="progressBar" Value="{Binding Path=Value}" DataContext="{StaticResource ResourceKey=PBVM}" Minimum="{Binding Min}" Maximum="{Binding Max}"/>
            <Button Command="{Binding Path=IncrementBy1}" Content="Manual Count" DataContext="{StaticResource PBVM}" Height="23" IsEnabled="{Binding Path=IsNotInProgress}" Name="button1" Width="Auto" />
            <Button Margin="0,3,0,3" IsEnabled="{Binding Path=IsNotInProgress}" Command="{Binding Path=IncrementAsForegroundProcess}" DataContext="{StaticResource ResourceKey=PBVM}" Content="Count to 10 as a foreground process" HorizontalAlignment="Stretch" Height="23" Name="buttonForeground" VerticalAlignment="Top" Width="Auto" />
            <Button Margin="0,3,0,3" IsEnabled="{Binding Path=IsNotInProgress}" Command="{Binding Path=IncrementAsBackgroundProcess}" DataContext="{StaticResource ResourceKey=PBVM}" Content="Count to 10 as a background process" HorizontalAlignment="Stretch" Height="23" Name="buttonBackground" VerticalAlignment="Top" Width="Auto" />
            <Button Command="{Binding Path=ResetCounter}" Content="Reset" DataContext="{StaticResource PBVM}" Height="23" IsEnabled="{Binding Path=IsNotInProgress}" Name="buttonReset" Width="Auto" />
        </StackPanel>
    </Grid>
</Window>

Step 5 – Populate the ProgressBarViewModel

  1. Create the following member fields.
    • Double _Value;
    • bool _IsInProgress;
    • int _Min = 0;
    • int _Max = 10;
  2. Create a matching property for each member field. Make sure that in the set function of the property you call NotifyPropertyChanged(“PropertyName”).
  3. Create a function for each of the four buttons and populate these functions with the code. See the functions in the code below:
    • Increment()
    • IncrementProgressForeground()
    • IncrementProgressBackgroundWorker()
    • Reset()
  4. Create and populate the functions for the BackgroundWorker.
    • worker_DoWork
    • worker_RunWorkerCompleted()
  5. Create the following RelayCommand instances as member Fields.
    • RelayCommand _Increment;
    • RelayCommand _IncrementBy1;
    • RelayCommand _IncrementAsBackgroundProcess;
    • RelayCommand _ResetCounter;
  6. Create matching ICommand properties for each RelayCommand, instantiating the RelayCommand with the correct function.

Here is the code for the ProgressBarViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Text;
using System.Windows.Input;
using MVVM;

namespace WPFProgressBarUsingBackgroundWorker
{
    class ProgressBarViewModel : ViewModelBase
    {
        #region Member Fields
        Double _Value;
        bool _IsInProgress;
        int _Min = 0, _Max = 10;
        #endregion

        #region Member RelayCommands that implement ICommand
        RelayCommand _Increment;
        RelayCommand _IncrementBy1;
        RelayCommand _IncrementAsBackgroundProcess;
        RelayCommand _ResetCounter;
        #endregion

        #region Constructors
        /// <summary>
        /// The default constructor
        /// </summary>
        public ProgressBarViewModel()
        {
        }
        #endregion

        #region Properties
        /// <summary>
        /// Used to mark if the counter is in progress so the counter can't be started
        /// while it is already running.
        /// </summary>
        public bool IsInProgress
        {
            get { return _IsInProgress; }
            set
            {
                _IsInProgress = value;
                NotifyPropertyChanged("IsInProgress");
                NotifyPropertyChanged("IsNotInProgress");
            }
        }

        public bool IsNotInProgress
        {
            get { return !IsInProgress; }
        }

        public int Max
        {
            get { return _Max; }
            set { _Max = value; NotifyPropertyChanged("Max"); }
        }

        public int Min
        {
            get { return _Min; }
            set { _Min = value; NotifyPropertyChanged("Min"); }
        }

        /// <summary>
        /// This is the Value.  The Counter should display this.
        /// </summary>
        public Double Value
        {
            get { return _Value; }
            set
            {
                if (value <= _Max)
                {
                    if (value >= _Min) { _Value = value; }
                    else { _Value = _Min; }
                }
                else { _Value = _Max; }
                NotifyPropertyChanged("Value");
            }
        }

        #region ICommand Properties
        /// <summary>
        /// An ICommand representation of the Increment() function.
        /// </summary>
        public ICommand IncrementBy1
        {
            get
            {
                if (_IncrementBy1 == null)
                {
                    _IncrementBy1 = new RelayCommand(param => this.Increment());
                }
                return _IncrementBy1;
            }
        }

        /// <summary>
        /// An ICommand representation of the IncrementProgressForegroundWorker() function.
        /// </summary>
        public ICommand IncrementAsForegroundProcess
        {
            get
            {
                if (_Increment == null)
                {
                    _Increment = new RelayCommand(param => this.IncrementProgressForeground());
                }
                return _Increment;
            }
        }

        /// <summary>
        /// An ICommand representation of the IncrementProgressForeground() function.
        /// </summary>
        public ICommand IncrementAsBackgroundProcess
        {
            get
            {
                if (_IncrementAsBackgroundProcess == null)
                {
                    _IncrementAsBackgroundProcess = new RelayCommand(param => this.IncrementProgressBackgroundWorker());
                }
                return _IncrementAsBackgroundProcess;
            }
        }

        /// <summary>
        /// An ICommand representation of the Reset() function.
        /// </summary>
        public ICommand ResetCounter
        {
            get
            {
                if (_ResetCounter == null)
                {
                    _ResetCounter = new RelayCommand(param => this.Reset());
                }
                return _ResetCounter;
            }
        }
        #endregion ICommand Properties
        #endregion

        #region Functions
        /// <summary>
        /// This function manually increments the counter by 1 in the foreground.
        /// Because it only increments by one, the WPF control bound to Value will
        /// display the new value when this function completes.
        /// </summary>
        public void Increment()
        {
            // If we are in progress already, don't do anything
            if (IsInProgress)
                return;

            // If the value is already at 10, start the counting over.
            if (Value == 10)
                Reset();
            Value++;
        }

        /// <summary>
        /// This function starts the counter as a foreground process.
        /// This doesn't work.  It counts to 10 but the UI is not updated
        /// until the function completes.  This is especially problematic
        /// since the buttons are left enabled.
        /// </summary>
        public void IncrementProgressForeground()
        {
            // If we are in progress already, don't do anything
            if (IsInProgress)
                return;
            Reset();
            IsInProgress = true;
            Value = 0;
            for (int i = _Min; i < _Max; i++)
            {
                Value++;
                Thread.Sleep(1000);
            }
            IsInProgress = false;
        }

        /// <summary>
        /// This starts the counter as a background process.
        /// </summary>
        public void IncrementProgressBackgroundWorker()
        {
            // If we are in progress already, don't do anything
            if (IsInProgress)
                return;

            Reset();
            IsInProgress = true;
            BackgroundWorker worker = new BackgroundWorker();
            // Configure the function that will run when started
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);

            /*The progress reporting is not needed with this implementation and is therefore
            commented out.  However, in your more complex application, you may have a use for
            for this.

            //Enable progress and configure the progress function
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

            */

            // Configure the function to run when completed
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

            // Launch the worker
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// This is the function that is called when the worker is launched with the RunWorkerAsync() call.
        /// </summary>
        /// <param name="sender">The worker as Object, but it can be cast to a worker.</param>
        /// <param name="e">The DoWorkEventArgs object.</param>
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int i = _Min; i < _Max; i++)
            {
                Value++;
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// This worker_ProgressChanged function is not in use for this project. Thanks to INotifyPropertyChanged, this is
        /// completely unnecessary.
        /// </summary>
        /// <param name="sender">The worker as Object, but it can be cast to a worker.</param>
        /// <param name="e">The ProgressChangedEventArgs object.</param>
        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Does nothing yet
            throw new NotImplementedException();
        }

        /// <summary>
        /// This worker_RunWorkerCompleted is called when the worker is finished.
        /// </summary>
        /// <param name="sender">The worker as Object, but it can be cast to a worker.</param>
        /// <param name="e">The RunWorkerCompletedEventArgs object.</param>
        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            IsInProgress = false;
        }

        /// <summary>
        /// This function resets the Value of the counter to 0.
        /// </summary>
        private void Reset()
        {
            Value = Min;
        }
        #endregion
    }
}

I’m sorry that this is not the most Newbie proof post. But I tried to comment like crazy the code so you can get through it.

Now if you find a discrepancy in my walk-through, please comment. Also, if it is easier for you to just download the project, here it is:
WPFProgressBarUsingBackgroundWorker.zip

WPF databinding to methods encapulated in an ICommand

Databinding in WPF allows binding the Command property to methods encapulated in an ICommand. By creating an ICommand object to hold an event function, the Command value can bind to the event function as an ICommand.

The goal of Model-View-ViewModel is to have zero code in the code behind of a WPF Control Instead, everything the WPF Control does happens using databinding.

While this article will show you how to do this, you be left a little fuzzy as to understanding of the implementation. It may take some time and research to fully understand everything this is doing. Understand that methods can be objects, and this is a process to turn a method object into an ICommand so it can be using in WPF for databinding.

Preparation and Prereqs

You should have Visual Studio 2008/2010.

In Visual Studio, create a new WPF Application project and give it a name.

Step 1 – Creating an new class that inherits from ICommand

  1. In your new project in Visual Studio, add a new class called RelayCommand.
    Note: It can be named anything, but since that is the name used by Microsoft when discussing MVVM, I will use the same name.
  2. Change the using statements to implement the following : System, System.Diagnostic, System.Windows.Input
  3. Make the new RelayComand class public.
  4. Make the new RelayCommand class implement ICommand.
    using System;
    using System.Windows.Input;
    
    namespace WpfDataBindingToICommand
    {
        public class RelayCommand : ICommand
        {
            #region Constructors
            public RelayCommand()
            {
            }
            #endregion
        }
    }
    
  5. Right-click on the ICommand text and choose Implement Interface | Implement Interface. This adds the following code to the bottom of your class.
            #region ICommand Members
    
            public bool CanExecute(object parameter)
            {
                throw new NotImplementedException();
            }
    
            public event EventHandler CanExecuteChanged;
    
            public void Execute(object parameter)
            {
                throw new NotImplementedException();
            }
    
            #endregion
    
  6. Create two member variables or fields that we will use to hep use inside the ICommand interface functions.
    1. Action<object>
    2. Predicate<object>

            #region Member Variables
            readonly Action<object> _ActionToExecute;
            readonly Predicate<object> __ActionCanExecute;
            #endregion
    
  7. Implement the CanExecute(object parameter) function.
            public bool CanExecute(object parameter)
            {
                return __ActionCanExecute== null ? true : __ActionCanExecute(parameter);
            }
    
  8. Implement the EventHandler CanExecuteChanged. In doing this the MVVM experts used the CommandManager, which might be worth reading about.
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
  9. Implement the Execute(object parameter) function.
            public void Execute(object parameter)
            {
                _ActionToExecute(parameter);
            }
    
  10. Create constructors that allow us to initialize the object by passing in the Action

The final class looks as follows:

using System;
using System.Windows.Input;

namespace WpfDataBindingToICommand
{
    /// <summary>
    /// This RelayCommand object is used to encapsulate function logic into an oject that inherits ICommand.
    /// </summary>
    public class RelayCommand : ICommand
    {
        #region Member Variables
        readonly Action<object> _ActionToExecute;
        readonly Predicate<object> _ActionCanExecute;
        #endregion

        #region Constructors
        /// <summary>
        /// This creates a new RelayCommand.
        /// </summary>
        /// <param name="inActionToExecute">This is the logic of the actin to execute. This objects is usually a method that returns void.</param>
        public RelayCommand(Action<object> inActionToExecute)
            : this(inActionToExecute, null)
        {
        }

        /// <summary>
        /// This creates a new RelayCommand.
        /// </summary>
        /// <param name="inActionToExecute">This is the logic of the actin to execute. This objects is usually a method that returns void.</param>
        /// <param name="inActionCanExecute">This is the logic for whether the action can execute.</param>
        public RelayCommand(Action<object> inActionToExecute, Predicate<object> inActionCanExecute)
        {
            if (inActionToExecute == null)
                throw new ArgumentNullException("execute");

            _ActionToExecute = inActionToExecute;
            _ActionCanExecute = inActionCanExecute;
        }
        #endregion

        #region ICommand Members
        public bool CanExecute(object parameter)
        {
            return _ActionCanExecute == null ? true : _ActionCanExecute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            _ActionToExecute(parameter);
        }
        #endregion
    }
}

Step 2 – Creating a ViewModelBase abstract base class

This object is used to create common logic for all objects that will be using in Binding. This object will implement INotifyPropertyChanged so it only has to be implemented once.

  1. Create a new class named ViewModelBase.
  2. Change the using statements to implement the following : System, System.CompenentModel
  3. Make the new ViewModelBase class public and abstract.
  4. Make the new ViewModelBase class implement INotifyPropertyChanged.
  5. Right-click on the INotifyPropertyChanged text and choose Implement Interface | Implement Interface. This adds the following code to the bottom of your class. Yes, it is just a one line event handler object.
            #region INotifyPropertyChanged Members
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            #endregion
    
  6. Create a function called NotifyPropertyChanged to help implement the object. Make sure it has a permission level of at least protected.
            #region Functions
            protected void NotifyPropertyChanged(String inPropertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(inPropertyName));
                }
            }
            #endregion
    
  7. Make the new ViewModelBase class public and abstract.

The final object looks as follows:

using System;
using System.ComponentModel;

namespace WpfDataBindingToICommand
{
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region Constructors
        public ViewModelBase()
        {
        }
        #endregion

        #region Functions
        protected void NotifyPropertyChanged(String inPropertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(inPropertyName));
            }
        }
        #endregion

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
}

Note: You may also want to implement IDisposable.

Step 3 – Creating the ViewModel and Model

We are going to have the ViewModel and business in the same object for this example, but sometimes you will have a separate ViewModel object that represents your data/business.

  1. Create a new class named SampleViewModel.
  2. Change the using statements to implement the following : System, System.Windows, System.Windows.Input
  3. Make the new SampleViewModel class public.
  4. Make the new SampleViewModel class inherit ViewModelBase.
    using System;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfDataBindingToICommand
    {
        public class SampleViewModel : ViewModelBase
        {
            #region Constructors
            public SampleViewModel()
            {
            }
            #endregion
        }
    }
    
  5. Create a string field and property and make sure to have the property’s set function call NotifyPropertyChanged.
        public class SampleViewModel : ViewModelBase
        {
            string _Message = "Hello. This is the default message.";
    
            public string Message
            {
                get { return _Message; }
                set
                {
                    _Message = value;
                    NotifyPropertyChanged("Message");
                }
            }
        }
    
  6. Create a simple function to show a MessageBox.
            public void ShowMessage(String inMessage)
            {
                MessageBox.Show(inMessage);
            }
    
  7. Create an ICommand field and property. Make sure the property returns a RelayCommand object that references the ShowMessage method. This is a read only property.
            RelayCommand _ShowMessageCommand;
    
            public ICommand ShowMessageCommand
            {
                get
                {
                    if (_ShowMessageCommand == null)
                    {
                        _ShowMessageCommand = new RelayCommand(param => this.ShowMessage(Message));
                    }
                    return _ShowMessageCommand;
                }
            }
    

    Note: Notice that in order to pass the ShowMessage method, instead of the return value of the function, into the RelayCommand objectwhich is void anyway, the param => syntax is used.

The final SampleViewModel looks as follows.

using System;
using System.Windows;
using System.Windows.Input;

namespace WpfDataBindingToICommand
{
    public class SampleViewModel : ViewModelBase
    {
        #region Member Variables
        string _Message = "Hello. This is the default message.";
        RelayCommand _ShowMessageCommand;
        #endregion

        #region Constructors
        public SampleViewModel()
        {
        }
        #endregion

        #region Properties
        public string Message
        {
            get { return _Message; }
            set
            {
                _Message = value;
                NotifyPropertyChanged("Message");
            }
        }

        public ICommand ShowMessageCommand
        {
            get
            {
                if (_ShowMessageCommand == null)
                {
                    _ShowMessageCommand = new RelayCommand(param => this.ShowMessage(Message));
                }
                return _ShowMessageCommand;
            }
        }
        #endregion

        #region Functions
        public void ShowMessage(String inMessage)
        {
            MessageBox.Show(inMessage);
        }
        #endregion

        #region Enums
        #endregion
    }
}

Step 4 – Using Databinding to Bind an ICommand to a WPF Control

Ok, so lets modify the XAML of the default MainWindow.xaml code that was auto-created with the project. We will keep it simple and have a text box and a button to pop up the message.

Note: For this simple program all the work we did to implement databinding for binding events to methods seems like an absurd burden. However, for large applications, this design will lead to a better way to manage your code. It will decouple your GUI from your code, making future refactoring of the GUI much easier. This also improves the ability to make minor changes to the GUI. It also makes the code more sustainable and more easily tested. Unit tests are more effective as the GUI layer is not required and most functions are in the business layer.

  1. Create a reference to the current namespace.
    <window x:Class="WpfDataBindingToICommand.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfDataBindingToICommand"
            Title="MainWindow" Height="350" Width="525">
    
  2. Add a SampleViewModel StaticResource.
        <window.Resources>
            <local:SampleViewModel x:Key="Sample" />
        </window.Resources>
    
  3. Set the DataContext of the Grid to the SampleViewModel StaticResource.
            <grid.RowDefinitions>
                <rowDefinition Height="*" />
                <rowDefinition Height="50" />
            </grid.RowDefinitions>
    
  4. Add two rows to the Grid.
        <grid DataContext="{StaticResource ResourceKey=Sample}">
    
  5. Add a TextBox and remove the sizing and alignments. Set Margin to 5. Bind the Text property to Message.
            <textBox Text="{Binding Message}" Name="textBoxMessage" Margin="5"/>
    
  6. Add a button. Set HorizontalAlignment to Right. Set the Width to Auto. Set Margin to 5. Bind the Command property to ShowMessageCommand.
    <button Command="{Binding ShowMessageCommand}" Content="ShowMessage" Grid.Row="1" Height="23" Name="buttonShowMessage" HorizontalAlignment="Right" Width="Auto" Margin="5"/>
    

You are done. The final XAML is as follows:

<window x:Class="WpfDataBindingToICommand.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfDataBindingToICommand"
        Title="MainWindow" Height="350" Width="525">
    <window.Resources>
        <local:SampleViewModel x:Key="Sample" />
    </window.Resources>
    <grid DataContext="{StaticResource ResourceKey=Sample}">
        <grid.RowDefinitions>
            <rowDefinition Height="*" />
            <rowDefinition Height="50" />
        </grid.RowDefinitions>
        <textBox Text="{Binding Message}" Name="textBoxMessage" Margin="5"/>
        <button Command="{Binding ShowMessageCommand}" Content="ShowMessage" Grid.Row="1" Height="23" Name="buttonShowMessage" HorizontalAlignment="Right" Width="Auto" Margin="5"/>
    </grid>
</window>

Notice that we never touched the code behind of MainWindow. The GUI and the code are as decoupled as possible. Not event the event functions are needed in the code behind. This decoupling or GUI and code is our goal.

Resources

WPF Apps With The Model-View-ViewModel Design Pattern
Understanding Routed Events and Commands In WPF


Copyright ® Rhyous.com – Linking to this page is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.

Tutorial – Binding to a member variable object

You have your WPF Window and you have an object that you don’t want to make a static resource. You want to declare it as a member variable in the code.

Example 1 – Binding two TextBox controls to a Person object

  1. Create a New WPF Application Visual Studio.
  2. Create a new Class named Person.cs.
  3. Give it FirstName and a LastName properties.
  4. Configure it to implement the INotifyPropertyChanged interface.
  5. Create a NotifyPropertyChanged function that all properties can share (to avoid duplicate code in every single property).
  6. Configure the properties to call the NotifyPropertyChanged function passing in a string that is the name of the property.

    Person.cs

    using System;
    using System.ComponentModel;
    
    namespace WPFPerson
    {
        public class Person : INotifyPropertyChanged
        {
            #region Member Variables
            String _FirstName;
            String _LastName;
            #endregion
    
            #region Constructors
            /*
    		 * The default constructor
     		 */
            public Person()
            {
            }
            #endregion
    
            #region Properties
            public String FirstName
            {
                get { return _FirstName; }
                set
                {
                    _FirstName = value;
                    NotifyPropertyChanged("FirstName");
                }
            }
    
            public String LastName
            {
                get { return _LastName; }
                set
                {
                    _LastName = value;
                    NotifyPropertyChanged("LastName");
                }
            }
            #endregion
    
            #region INotifyPropertyChanged Members
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void NotifyPropertyChanged(String info)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(info));
                }
            }
            #endregion
        }
    }
    
  7. Go back tot he MainWindow.xaml.
  8. Add two labels, and two text boxes, and a button.
  9. Change the text boxes to be populated using binding by adding the following text:
    Text=”{Binding FirstName, Mode=TwoWay}”  

    MainWindow.xaml (WPF Window)

    <window x:Class="WPFPerson.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" >
        <grid Name="PersonGrid" >
            <textBox Height="23" HorizontalAlignment="Left" Margin="173,87,0,0" Name="textBoxFirstName" VerticalAlignment="Top" Width="234" Text="{Binding FirstName, Mode=TwoWay}" />
            <textBox Height="23" HorizontalAlignment="Left" Margin="173,116,0,0" Name="textBoxLastName" VerticalAlignment="Top" Width="234" Text="{Binding LastName, Mode=TwoWay}"/>
            <label Content="FirstName" Height="28" HorizontalAlignment="Left" Margin="103,85,0,0" Name="labelFirstName" VerticalAlignment="Top" />
            <label Content="LastName" Height="28" HorizontalAlignment="Left" Margin="103,114,0,0" Name="labelLastName" VerticalAlignment="Top" />
            <button Content="Defaults" Height="23" HorizontalAlignment="Left" Margin="337,199,0,0" Name="buttonDefaults" VerticalAlignment="Top" Width="75" Click="buttonDefaults_Click" />
        </grid>
    </window>
    
  10. Double-click the button to create the buttonDefaults_Click event function.
    This also conveniently takes you to the Code Behind of the MainWindow.cs file.
  11. Have the buttonDefaults_Click function update to properties of your _Person object.
    _Person.FirstName = “Jared”;
    _Person.LastName = “Barneck”;
  12. Create a field/member variable using the Person object.
    private readonly Person _Person;
  13. Now in the constructor initialize the object.
    _Person = new Person();
  14. Also in the constructor, make the DataContext for each TextBox the _Person object.
    textBoxFirstName.DataContext = _Person;
    textBoxLastName.DataContext = _Person;  

    MainWindow.cs (Code Behind)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Threading;
    
    namespace WPFPerson
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private readonly Person _Person;
    
            public MainWindow()
            {
                _Person = new Person();
                InitializeComponent();
                textBoxFirstName.DataContext = _Person;
                textBoxLastName.DataContext = _Person;
            }
    
            private void buttonDefaults_Click(object sender, RoutedEventArgs e)
            {
                _Person.FirstName = "Jared";
                _Person.LastName = "Barneck";
            }
        }
    }
    
  15. Now Now compile and make sure you don’t have any errors.

Example 2 – Forthcoming…

Example 3 – Forthcoming…

Sources:
http://www.wrox.com/WileyCDA/Section/Windows-Presentation-Foundation-WPF-Data-Binding-with-C-2005.id-305562.html

Tutorial – Binding to Resources.resx for strings in a WPF Application: A technique to prepare for localization

Introduction

Ok, so if you are going to have a string visible in your WPF application and your application can be in multiple languages, you are facing the localization problem.

Usually people as themselves two questions:

  • Do I localize or not?
  • How do I localize?

The answers are usually not now and I don’t know. So no localization work is done at first. Later, you wish you were more prepared for localization.

Well, I am here to tell you that you can at least prepare to be localized by doing a few simple steps:

  1. Centralize your strings in a publicized Resources.resx file.
  2. Add a reference to your Properties.
  3. Replacing any statically entered text with the name of the string resource.
  4. Do you best to use dynamic sizing.

Preparing your strings for localization

If you are going to have a string in your WPF application, it is a good idea to store those strings in a centralized place for localization purposes. Usually in Visual Studio, that is in Resources.resx.

Often a string is entered directly into an the WPF XAML. This is not recommended. Maybe you are thinking that you don’t need to localize your application, so this is not important to you. Ok, really what you are thinking is:

“I don’t know how to do it and if I ever get big enough to need localization, at that point, I will figure it out.”

Well, what if I told you that using Resources.resx is extremely easy?

What if I told you that it hardly takes more time at all?

If it easy and hardly time consuming at all, you would do it, right? I would. Hence this post.

Step by step guide for Preparing your strings for locaization

I have a project called LicenseAgreementManager. Right now this only needs to display a license agreement in English, but maybe someday, this will need to display a license agreement in any language.

Preparation – Create a new project or use an existing project

In Visual Studio, create a new WPF Applcation project.

I named my project LicenseAgreementManager.

Right away, you already have at least one string statically entered into your XAML, the text for the window title.

Step 1 – Add all your strings to the Resources.resx file

  1. Double-click on Resources.resx in your WPF Project. This found under the ProjectName | Properties option in your Solution Explorer tree.
  2. Change the Access Modifier drop down menu from Internal to Public.
  3. Enter your strings in the Resources.resx by giving them a unique name and a value of the desired string. A comment is also optional.

You now have a publicized Resource.resx file and a few strings inside it.

Step 2 – Add a reference to your Properties

  1. In your project, open your MainWindow.xaml file.The XAML looks as follows:
    <window x:Class="LicenseAgreementManager.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">
        <grid>
    
        </grid>
    </window>
    
  2. Add a line to reference your Properties in the Windows element.
    <window x:Class="LicenseAgreementManager.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:p="clr-namespace:LicenseAgreementManager.Properties"
            Title="MainWindow" Height="350" Width="525">
    

Step 3 – Replace static text with strings from the Resources.resx

  1. Change the Title attribute from static text to instead use access the string from your Resources.resx named EULA_Title.
    <window x:Class="LicenseAgreementManager.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:p="clr-namespace:LicenseAgreementManager.Properties"
            Title="{x:Static p:Resources.EULA_Title}"
            Height="350" Width="525">
    

That was pretty easy, wasn’t it.

As you add elements that have strings, use the Resources.resx.

Step 4 – Try to use dynamic sizing

  1. As best as possible, remove any dynamic sizing.

    I have just added some items and removed the sizing as best as possible. Here is my XAML.

    <window x:Class="LicenseAgreementManager.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:p="clr-namespace:LicenseAgreementManager.Properties"
            Title="{x:Static p:Resources.EULA_Title}"
            SizeToContent="WidthAndHeight"
            xml:lang="en-US">
        <grid>
            <grid.RowDefinitions>
                <rowDefinition Height="Auto"/>
                <rowDefinition Height="Auto"/>
            </grid.RowDefinitions>
    
            <richTextBox Name="_EulaTextBox" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch"/>
            <stackPanel Grid.Row="1" Margin="0,10,0,0" Name="stackPanel2" HorizontalAlignment="Stretch"  VerticalAlignment="Stretch">
                <radioButton Content="{x:Static p:Resources.EULA_Accept}" Margin="20,20,20,0" Name="radioButton1" />
                <radioButton Content="{x:Static p:Resources.EULA_NotAccept}" Margin="20,20,20,0" Name="radioButton2" />
                <button Content="{x:Static p:Resources.Next_Button}" Name="button1" Margin="20,20,35,20"  HorizontalAlignment="Right" />
            </stackPanel>
        </grid>
    </window>
    
  2. What changes did I make above that I couldn’t do through the Visual Studio GUI?
    1. I removed Height and size from almost every element.
    2. I added SizeToContent=”WidthAndHeight” to the Windows element.
    3. I added some extra size to the margins.

Conclusion

You don’t have to be localized to be prepared for easy localization. By doing the above simple steps, when it comes time to add localization, you will be ready.

If you want to go on an finish localization. You might want to read some of my sources.

Sources:

http://compositeextensions.codeplex.com/Thread/View.aspx?ThreadId=52910
http://msdn.microsoft.com/en-us/library/ms788718%28v=VS.90%29.aspx
http://msdn.microsoft.com/en-us/library/ms746621.aspx


Copyright ® Rhyous.com – Linking to this article is allowed without permission and as many as ten lines of this article can be used along with this link. Any other use of this article is allowed only by permission of Rhyous.com.

 

Tutorial – Creating a StaticResource and Binding to it

The XAML allows you to provide what are called StaticResources. Such resources can be given to a Window or to certain controls.

For this tutorial, I assume you are in Visual Studio 2008. I assume that you already know how to create a new Project and choose WPF Application. All examples assume you have a new WPF Application.

So lets get started with three examples of binding to StaticResources.

Example 1 – Making a String a StaticResource and Binding to it

This example will demonstrate instantiating a String as a StaticResource and binding a TextBox to it.

Step 1 – Add the elements

  1. Add three TextBox elements into the default Grid control.
            <listBox Margin="12,12,0,0" Name="listBox1" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" />
            <listBox Margin="138,12,20,0" Name="listBox2" Height="100" VerticalAlignment="Top" />
            <textBox Margin="12,118,0,121" Name="textBox1" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
            <textBox Margin="138,118,20,121" Name="textBox2" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
    
    

Step 2 – Add the static resources

  1. Add an xmlns reference to the System namespace. This is done by adding the xmlns:System line to as an attribute to the top Window element as shown:
    <window x:Class="StaticResourceBinding.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        Title="Window1" Height="300" Width="300">
    
  2. Create a Windows.Resources section in the XAML and add three Strings to it as StaticResources.
        <window.Resources>
            <system:String x:Key="FirstName">Jared</system:String>
            <system:String x:Key="LastName">Barneck</system:String>
            <system:String x:Key="Alias">Rhyous</system:String>
        </window.Resources>
    

Step 3 – Adding Binding to each TextBox element’s Text property

  1. Configure the three TextBox elements to bind to each String added as a StaticResource by adding a Text attribute.
            <textBox Text="{StaticResource FirstName}" Height="23" Margin="51,25,107,0" Name="textBox1" VerticalAlignment="Top" />
            <textBox Text="{StaticResource LastName}" Height="23" Margin="51,54,107,0" Name="textBox2" VerticalAlignment="Top" />
            <textBox Text="{StaticResource Alias}" Height="23" Margin="51,83,107,0" Name="textBox3" VerticalAlignment="Top" />
    

The final XAML looks as follows. No changes were made to the code behind at all.

<window x:Class="StaticResourceBinding.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    Title="Window1" Height="300" Width="300">
    <window.Resources>
        <system:String x:Key="FirstName">Jared</system:String>
        <system:String x:Key="LastName">Barneck</system:String>
        <system:String x:Key="Alias">Rhyous</system:String>
    </window.Resources>
    <grid>
        <textBox Height="23" Margin="51,25,107,0" Name="textBox1" VerticalAlignment="Top" Text="{StaticResource FirstName}"/>
        <textBox Height="23" Margin="51,54,107,0" Name="textBox2" VerticalAlignment="Top" Text="{StaticResource LastName}"/>
        <textBox Height="23" Margin="51,83,107,0" Name="textBox3" VerticalAlignment="Top" Text="{StaticResource Alias}"/>
    </grid>
</window>

Example 2 – Declaring an array as a StaticResource and Binding a ListBox to it

This example will demonstrate instantiating arrays as StaticResources and binding a ListBox to the arrays.

To show an example of building onto existing or previous learned knowledge, we are going to also implement binding each TextBox's Text properties to the ListBox's SelectedItem property.

Step 1 – Add the elements

  1. Add two ListBox and two TextBox elements into the default Grid control.
            <listBox Margin="12,12,0,0" Name="listBox1" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" />
            <listBox Margin="138,12,20,0" Name="listBox2" Height="100" VerticalAlignment="Top" />
            <textBox Margin="12,118,0,121" Name="textBox1" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
            <textBox Margin="138,118,20,121" Name="textBox2" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
    

Step 2 – Add the static resources

  1. Add an xmlns reference to the System namespace. This is done by adding the xmlns:System line to as an attribute to the top Window element as shown:
    <window x:Class="StaticResourceBinding.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        Title="Window1" Height="300" Width="300">
    
  2. Create a Windows.Resources section in the XAML and add two arrays as StaticResources: one an array of strings, and one an array of integers.
        <window.Resources>
            <x:Array x:Key="StringList" Type="System:String">
                <system:String>Line 1</system:String>
                <system:String>Line 2</system:String>
                <system:String>Line 3</system:String>
                <system:String>Line 4</system:String>
            </x:Array>
            <x:Array x:Key="IntArray" Type="System:Int32">
                <system:Int32>100</system:Int32>
                <system:Int32>200</system:Int32>
                <system:Int32>300</system:Int32>
                <system:Int32>400</system:Int32>
            </x:Array>
        </window.Resources>
    

Step 3 – Adding Binding

  1. Configure one ListBox's Text property to bind to the String array and the other ListBox's Text property to bind to the Int32 array.
            <listBox ItemsSource="{StaticResource StringList}" Margin="12,12,0,0" Name="listBox1" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" />
            <listBox ItemsSource="{StaticResource IntArray}" Margin="138,12,20,0" Name="listBox2" Height="100" VerticalAlignment="Top" />
    
  2. We will also add binding to show you how you can combine binding to StaticResources and binding to another element’s property.Bind one TextBox to the listBox1.SelectedItem property and bind the other to the listBox2.SelectedItem.
            <textBox Text="{Binding ElementName=listBox1, Path=SelectedItem}" Margin="12,118,0,121" Name="textBox1" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
            <textBox Text="{Binding ElementName=listBox2, Path=SelectedItem}" Margin="138,118,20,121" Name="textBox2" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
    
  3. Build your application and run it. Notice as you select an item in the list, it displays.

The final XAML looks as follows. No changes were made to the code behind at all.

<window x:Class="StaticResourceBinding2.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    Title="Window1" Height="300" Width="300">
    <window.Resources>
        <x:Array x:Key="StringList" Type="System:String">
            <system:String>Line 1</system:String>
            <system:String>Line 2</system:String>
            <system:String>Line 3</system:String>
            <system:String>Line 4</system:String>
        </x:Array>
        <x:Array x:Key="IntArray" Type="System:Int32">
            <system:Int32>100</system:Int32>
            <system:Int32>200</system:Int32>
            <system:Int32>300</system:Int32>
            <system:Int32>400</system:Int32>
        </x:Array>
    </window.Resources>
    <grid>
        <listBox ItemsSource="{StaticResource StringList}" Margin="12,12,0,0" Name="listBox1" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" />
        <listBox ItemsSource="{StaticResource IntArray}" Margin="138,12,20,0" Name="listBox2" Height="100" VerticalAlignment="Top" />
        <textBox Text="{Binding ElementName=listBox1, Path=SelectedItem}" Margin="12,118,0,121" Name="textBox1" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
        <textBox Text="{Binding ElementName=listBox2, Path=SelectedItem}" Margin="138,118,20,121" Name="textBox2" Width="120" IsReadOnly="True" HorizontalAlignment="Left" />
    </grid>
</window>

Example 3 – Adding Resources to a Control

In the previous two examples, we added the resources to the main Window object. However, a resource can be added to a control.

This example will demonstrate instantiating an array as a StaticResources for a control. We will then bind a TabControl’s ItemSource property to this array. This will cause a Tab to be created for each item in the array.

Step 1 – Add the elements

  1. Add a TabControl into the default Grid control.
            <tabControl Name="tabControl1">
    

Step 2 – Add the static resources

  1. Add an xmlns reference to the System namespace. This is done by adding the xmlns:System line to as an attribute to the top Window element as shown:
    <window x:Class="StaticResourceBinding.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        Title="Window1" Height="300" Width="300">
    
  2. Create a Grid.Resources section in the XAML and add an array as a StaticResource under the Grid control.
            <grid.Resources>
                <x:Array x:Key="TabList" Type="System:String">
                    <system:String>Tab 1</system:String>
                    <system:String>Tab 2</system:String>
                    <system:String>Tab 3</system:String>
                </x:Array>
            </grid.Resources>
    

Step 3 – Adding Binding to the TabControl’s ItemSource Property

  1. Bind the TabControl's ItemSource property to bind to the String array.
            <tabControl Name="tabControl1" ItemsSource="{StaticResource TabList}">
    

The final XAML looks as follows. No changes were made to the code behind at all.

<window x:Class="StaticResourceBinding3.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    Title="Window1" Height="300" Width="300">
    <grid>
        <grid.Resources>
            <x:Array x:Key="TabList" Type="System:String">
                <system:String>Tab 1</system:String>
                <system:String>Tab 2</system:String>
                <system:String>Tab 3</system:String>
            </x:Array>
        </grid.Resources>
        <tabControl Name="tabControl1" ItemsSource="{StaticResource TabList}">
        </tabControl>
    </grid>
</window>

Hey, there is nothing wrong with more examples, so if you have an example of your own feel free to add it as a comment.


Copyright ® Rhyous.com – Linking to this post is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.

A WPF Progress Bar

Today I needed a progress bar for as I was creating a c# tool that FTPs a file.  I wanted to show progress as the FTP file was uploaded.

I found a good solution at Mikes Code Blog. He has a post and a follow-up post.

WPF Progress Bar code

WPF Progress Bar Revisited

I created the progress bar as described and it worked really well. Here is a screen shot:

Thanks Mike!

Tutorial – Binding one element property to another

The properties of WPF elements can be bound to properties of other WPF Elements. Lets do some simple examples of binding one element to another.

For this tutorial, I assume you are in Visual Studio 2008.  I assume that you already know how to create a new Project and choose WPF Application.  All examples assume you have a new WPF Application.

I am the believer that one example isn’t enough, so I am going to give you three examples:

Example 1 – Binding and Element’s property to CheckBox.IsChecked

This example will demonstrate binding a Button‘s IsEnabled property to a CheckBox‘s IsChecked property.

Step 1 – Add the elements

  1. Add two items from the Toolbox:
    • CheckBox
    • Button

    The Button is named button1 and the CheckBox is named checkBox1.

  2. Change the text of the checkBox1 to “Enable button”.  This can be done either in the Properties or in the XAML.

Step 2 – Adding Binding to the Button

  1. In the XAML, locate the button1 element.
  2. Add the following to the button1 element:IsEnabled="{Binding ElementName=checkBox1, Path=IsChecked}"In your project, ElementName could be any item. In this example, we only have two elements so far: button1, and checkBox1.The XAML now looks like this (only two new lines exist):
    <Window x:Class="BindingATextBoxToASlider.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <Button Content="Button" Height="23" Margin="12,34,416,0" Name="button1" VerticalAlignment="Top" Width="75" IsEnabled="{Binding ElementName=checkBox1, Path=IsChecked}"/>
            <CheckBox Content="CheckBox" Height="16" Margin="12,12,408,0" Name="checkBox1" VerticalAlignment="Top" />
        </Grid>
    </Window>
    
  3. Compile and run your program.
  4. Check and uncheck the box an watch the binding do its work as it enables and disables the button.

Ok, so that was pretty cool. We have a simple example of binding one Element to another.

You can shoot yourself in the foot or Don’t be stupid!

Yes, you can shoot yourself in the foot by doing something stupid.

You could bind an element to itself. Let’s try it just so you can see it happen.

Add the same binding you added to button1 to checkBox1.

Compile and see what happens.

Example 2 – Binding and Element’s property to Slider.Value

This example uses a Slider and a TextBox.

Step 1 – Add the elements

  1. Add two items from the Toolbox:
    • TextBox
    • Slider

    The Slider is named slider1 and the TextBox is named textBox1.

Step 2 – Adding Binding to the TextBox

  1. In the XAML, locate the textBox1 element.
  2. Add the following to the textBox1 element:Text="{Binding ElementName=slider1, Path=Value}"ElementName can be any item. In this example, we only have two elements so far: slider1, and textBox1.The XAML now looks like this (only two new lines exist):
    <Window x:Class="BindingATextBoxToASlider.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
           <TextBox Height="23" Margin="79,62,99,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding ElementName=slider1, Path=Value}"/>
            <Slider Height="22" Margin="79,34,99,0" Name="slider1" VerticalAlignment="Top" />
        </Grid>
    </Window>
    
  3. Compile and run your program.
  4. Slide the slider and watch the binding do its work as its value is displayed in the textBox1 as it changes.

Calculations in XAML Bindings are Unsupported

Ok, so maybe you want to try to do calculations in the XAML Binding. It doesn’t work.

You can enter this and while it will compile, the Binding won’t work:

Text="{Binding ElementName=slider1, Path=(int)Value}"

You can enter this and while it will compile, the Binding won’t work:

Text="{Binding ElementName=slider1, Path=Value + 1}"

Example 3 – Binding and Element’s property to CheckBox.IsChecked

Ok, lets do a slight more complex example. We are going to have more than two elements. We are going to have a ListBox that contains a list of items (ListBoxItems). We are going to have a TextBox that displays the content of the selected item.

Step 1 – Add the elements

  1. Add two items from the Toolbox:
    • TextBox
    • ListBox
  2. Add multiple items to listBox1. This can be done either in the XAML or by clicking on the button for Items in the Properties of the listBox1.

Step 2 – Adding Binding to the TextBox

  1. In the XAML, locate the textBox1 element.
  2. Add the following to the textBox1 element:Text="{Binding ElementName=listBox1, Path=SelectedItem.Content}"Notice that we are using a property of a property for the Path. This is allowed. SelectedItem is a property of listBox1, and Content is a property of SelectedItem.The XAML now looks like this (only two new lines exist):
    <Window x:Class="BindingATextBoxToAListBoxSelectedItem.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <TextBox Height="23" Margin="12,23,12,0" Name="textBox1" VerticalAlignment="Top" Text="{Binding ElementName=listBox1, Path=SelectedItem.Content}"/>
            <ListBox Margin="12,52,12,110" Name="listBox1">
                <ListBoxItem>c:</ListBoxItem>
                <ListBoxItem>d:</ListBoxItem>
                <ListBoxItem>e:</ListBoxItem>
                <ListBoxItem>f:</ListBoxItem>
                <ListBoxItem>g:</ListBoxItem>
                <ListBoxItem>h:</ListBoxItem>
            </ListBox>
        </Grid>
    </Window>
    
  3. Compile and run your program.
  4. Select different items in the list and watch the textBox1 change to display the content of the selected item.

Copyright ® Rhyous.com – Linking to this post is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.

WPF Data Binding Tutorial

Introduction

This document assumes that you understand the concepts of object oriented programming and more specifically with C# programming, such as Classes or Objects, Methods, Properties, Events, etc. If not, it will be much harder to follow along.

This tutorial will cover the basics of data Binding in a WPF application. When you are done with this tutorial, you should be able to create a basic WPF-based graphical program that uses Binding. We will cover the different types of data Binding as well as what works and sometimes what doesn’t.

What is data Binding?

The idea of data Binding is to link a variable of any Type (int, string, object, etc…) to a graphical object’s Property that has the same type.

For example, lets say you have a Button object called myButton in your GUI like this: . The words “Click Me!” is a string property in the Button object: myButton.Text.

Imagine you have a string variable called strProperty in some part of your code that on its own has no way to interact with your GUI code. Lets say you want to change the myButton.Text property to match that string variable. Binding allows the button’s text string to always match a string property in some other object not really related to your GUI so if you change strProperty to equal “Enable” your button text will look like . If you then change the strProperty to “Disable” the button text will automatically change to be without out your back end code having to make any interaction with the GUI on its own.

Without Binding, you would have to write code yourself that would interact with the GUI and update the myButton.Text property when ever you update the string in code. In order to do this without Binding, you would also have to intermingle your background code with your GUI code. This can make it difficult to update or modify your GUI because GUI code is strung throughout all parts of your application. You don’t just have to update your GUI, you have to update all your code that interacts with the GUI.

So Binding allows you to have a back end code that is independent of the GUI. This is especially useful when the GUI needs to be updated or improved or when multiple GUIs exists (skins) and you can switch between them.

There are programming styles associated with developing a GUI separate from the back-end. Two of which are Model-View-Control (MVC) or Model-View-ViewModel (MVVM). This tutorial is not going to cover these, however, it is probably wise for you become familiar with these.

However, there is no reason you are limited to Binding to back end code. You can bind to code that is in the WPF GUI and very powerful applications can be written with little to no back end code.

Requirements for data Binding in WPF

In order to using data Binding, you should have the following requirements:

  1. Your project should be a WPF Application, or your project should include a WPF Window or WPF Control.
  2. Objects your elements bind to should implement System.ComponentModel.INotifyPropertyChanged.

Types of data Binding and resources

There is are multiple types of Binding. Elements bind to some type of resource and there are multiple types of resources. Static and Dynamic resource binding which uses the StaticResource Markup Extension or the DynamicResource Markup Extension.

The Binding source can also be “any public property, including properties of other controls, common language runtime (CLR) objects, XAML elements, ADO.NET DataSets, XML Fragments, and so forth.” (Reference: http://msdn.microsoft.com/en-us/magazine/cc163299.aspx).

Go to next: 1.1 Binding one element property to another


Copyright ® Rhyous.com – Linking to this page is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.