Posted by: Zeeshan Amjad | November 19, 2014

Convert Event to Command using Blend SDK


We saw an example of how to change the controls event into command using attached dependency property here and here. Microsoft Expression Blend SDK provide another simple way to do this.

The first step is to include the reference of System.Windows.Interactivity.dll. On 64 bit Windows, it can be find in the following location.

C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.5\Libraries

or

C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries

Lets make a simple example of ListBox and convert the SelectionChanged event into command. At first step Let’s create a ViewModel. The ViewModel contains the ObservableCollection to populate the Listbox, SelectedItem property to store the currently selected item and SelectedCommand property.

Code Snippet
    public class CitiesViewModel : ViewModelBase
    {
        private ObservableCollection<string> _cities;
        private string _selectedItem;

        public CitiesViewModel()
        {
            Cities = new ObservableCollection<string>
            { "Boston", "Los Angeles", "Houston", "New York", "Chicago", "Philadelphia" };

            SelectedItemCommand = new DelegateCommand<string>(SelectionChange, () => true);
        }

        private void SelectionChange(string value)
        {
            SelectedItem = value;
        }

        public ObservableCollection<string> Cities
        {
            get { return _cities; }
            set
            {
                if (Equals(value, _cities)) return;
                _cities = value;
                OnPropertyChanged();
            }
        }

        public string SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (value == _selectedItem) return;
                _selectedItem = value;
                OnPropertyChanged();
            }
        }

        public ICommand SelectedItemCommand
        {
            get; set;
        }
    }

 

Now first include the reference of System.Windows.Interactivity in XAML.

Code Snippet
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

 

Here is a XAML code to use expression interactivity to convert SelectionChanged event into command and bind it with SelectedItemCommand defined in CitiesViewModel. In addition it also passes the SelectedItem as a command parameter.

Code Snippet
<i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged">
        <i:InvokeCommandAction Command="{Binding SelectedItemCommand}"
            CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

 

Here is complete XAML code of the program.

Code Snippet
<Window x:Class="IntractivitySample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        Title="Event Trigger" Height="300" Width="400">
    <Grid DataContext="{Binding}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ListBox Grid.Column="0" Margin="5" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Cities}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding SelectedItemCommand}"
                        CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>

        </ListBox>
        <TextBlock Grid.Column="1" Margin="5" Text="{Binding SelectedItem}"/>
    </Grid>
</Window>

 

And here is complete C# code of the program.

Code Snippet
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;

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

            DataContext = new CitiesViewModel();
        }
    }

    public class DelegateCommand<T> : ICommand
    {
        private Action<T> _action;
        private Func<bool> _predicate;

        public DelegateCommand(Action<T> _action, Func<bool> _predicate)
        {
            this._action = _action;
            this._predicate = _predicate;
        }

        private void Execute(T parameter)
        {
            if (_action != null)
            {
                _action(parameter);
            }
        }

        public bool CanExecute(object parameter)
        {
            if (_predicate != null)
            {
                return _predicate();
            }

            return true;
        }

        public void Execute(object parameter)
        {
            if (_action != null)
            {
                _action((T)parameter);
            }
        }

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

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }        
    }
    public class CitiesViewModel : ViewModelBase
    {
        private ObservableCollection<string> _cities;
        private string _selectedItem;

        public CitiesViewModel()
        {
            Cities = new ObservableCollection<string>
            { "Boston", "Los Angeles", "Houston", "New York", "Chicago", "Philadelphia" };

            SelectedItemCommand = new DelegateCommand<string>(SelectionChange, () => true);
        }

        private void SelectionChange(string value)
        {
            SelectedItem = value;
        }

        public ObservableCollection<string> Cities
        {
            get { return _cities; }
            set
            {
                if (Equals(value, _cities)) return;
                _cities = value;
                OnPropertyChanged();
            }
        }

        public string SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                if (value == _selectedItem) return;
                _selectedItem = value;
                OnPropertyChanged();
            }
        }

        public ICommand SelectedItemCommand
        {
            get; set;
        }
    }
}

 

And this is the output of the program.

EventTrigger

Posted by: Zeeshan Amjad | November 9, 2014

Debug data binding


Sometimes debugging data binding is very time consuming. There can be several reason for data binding to not work. I came across one situation where the property is private.

Here is a small tip to debug the data binding. We can use Debugger.Break() method to put the break point and uses the converter to do this. Here is a small utility class to do this.

Code Snippet
namespace DebugBinding
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Windows.Data;
    using System.Windows.Markup;

    [ValueConversion(typeof(object), typeof(object))]
    public class DebugDataBindingExtension : MarkupExtension, IValueConverter
    {
        #region IValueConverter

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Debugger.Break();
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Debugger.Break();
            return value;
        }

        #endregion

        #region MarkupExtension

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }

        #endregion
    }
}

 

And here is a XAML to use this markup extension.

Code Snippet
<ListBox Margin="5" ItemsSource="{Binding Converter={local:DebugDataBinding}}"/>

Posted by: Zeeshan Amjad | May 20, 2014

Using Tuple in ListBox


Tuple is a very handy generic utility class in .net that be very useful specially in lookup data situation. Let’s work on a simple example of displaying currency in the list box. In official ISO 4217 standard of currency code, there are currency code, number and the currency name. We can store this information in Tuple.

Code Snippet
public ObservableCollection<Tuple<string, int, string>> Currencies =
    new ObservableCollection<Tuple<string, int, string>>();

 

Now let’s store some currencies information in it.

Code Snippet
Currencies.Add(new Tuple<string, int, string>("AED", 784, "United Arab Emirates"));
Currencies.Add(new Tuple<string, int, string>("AUD", 036, "Australian Dollar"));
Currencies.Add(new Tuple<string, int, string>("CAD", 124, "Canadian Dollar"));
Currencies.Add(new Tuple<string, int, string>("EUR", 978, "Euro"));
Currencies.Add(new Tuple<string, int, string>("GBP", 826, "Pound Sterling"));
Currencies.Add(new Tuple<string, int, string>("JPY", 392, "Japanese Yen"));
Currencies.Add(new Tuple<string, int, string>("MXN", 484, "Mexican Peso"));
Currencies.Add(new Tuple<string, int, string>("NZD", 554, "New Zeland Dollar"));
Currencies.Add(new Tuple<string, int, string>("QAR", 634, "Qatar Riyal"));
Currencies.Add(new Tuple<string, int, string>("SAR", 682, "Saudi Riyal"));
Currencies.Add(new Tuple<string, int, string>("USD", 840, "US Dollar"));

 

Using of Tuple in Listbox is very straight forward. We just bind Item1, Item2 etc in the Listbox. Here is complete XAML code of the program.

Code Snippet
<Window x:Class="WpfListBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="Tuple in Listbox" Height="300" Width="400">
    <Grid>
        <ListBox Margin="5,10,4.6,0.4" ItemsSource="{Binding}"
                 HorizontalContentAlignment="Stretch">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" Text="{Binding Item1}"/>
                        <TextBlock Grid.Column="1" Text="{Binding Item2}"/>
                        <TextBlock Grid.Column="2" Text="{Binding Item3}"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

 

Here is complete C# code of the program.

Code Snippet
using System;
using System.Collections.ObjectModel;
using System.Windows;

namespace WpfListBox
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public ObservableCollection<Tuple<string, int, string>> Currencies =
            new ObservableCollection<Tuple<string, int, string>>();

        public MainWindow()
        {
            InitializeComponent();

            Currencies.Add(new Tuple<string, int, string>("AED", 784, "United Arab Emirates"));
            Currencies.Add(new Tuple<string, int, string>("AUD", 036, "Australian Dollar"));
            Currencies.Add(new Tuple<string, int, string>("CAD", 124, "Canadian Dollar"));
            Currencies.Add(new Tuple<string, int, string>("EUR", 978, "Euro"));
            Currencies.Add(new Tuple<string, int, string>("GBP", 826, "Pound Sterling"));
            Currencies.Add(new Tuple<string, int, string>("JPY", 392, "Japanese Yen"));
            Currencies.Add(new Tuple<string, int, string>("MXN", 484, "Mexican Peso"));
            Currencies.Add(new Tuple<string, int, string>("NZD", 554, "New Zeland Dollar"));
            Currencies.Add(new Tuple<string, int, string>("QAR", 634, "Qatar Riyal"));
            Currencies.Add(new Tuple<string, int, string>("SAR", 682, "Saudi Riyal"));
            Currencies.Add(new Tuple<string, int, string>("USD", 840, "US Dollar"));

            DataContext = Currencies;
        }
    }
}

 

Here is the output of the program.

TupleListBox

Posted by: Zeeshan Amjad | April 22, 2014

Fibonacci Word


I came across an interesting concept Fibonacci word. It is formed by repeated concatenation of symbols, usually two alphabets, using the Fibonacci numbers way.

For sample lets start with the symbol “a” and “ab”.

Here are the first few words

F0 = a

F1 = ab

F2 = aba

F3 = abaab

F4 = abaababa

F5 = abaababaabaab

Let’s do this coding but first make a integer version of the program.

Code Snippet
static int[] Fibonacci(int no)
{
    var fib = new int[no];

    fib[0] = 0;
    fib[1] = 1;

    for (var i = 2; i < no; i++)
    {
        fib[i] = fib[i - 1] + fib[i - 2];
    }

    return fib;
}

 

Now let’s make the string version of the program.

Code Snippet
static string[] FibonacciString(int no)
{
    var fib = new string[no];

    fib[0] = "a";
    fib[1] = "b";

    for (var i = 2; i < no; i++)
    {
        fib[i] = fib[i - 1] + fib[i - 2];
    }

    return fib;
}

 

The integer version and the string version of the programs are very similar to each other. Let’s try to make a generic  function. This is our first attempt.

Code Snippet
static T[] Fibonacci<T>(int no)
{
    var fib = new T[no];

    fib[0] = 0;
    fib[1] = 1;

    for (var i = 2; i < no; i++)
    {
        fib[i] = fib[i - 1] + fib[i - 2];
    }

    return fib;
}

 

This program has two problem. First the initialization of the first and second elements of Fibonacci word. It can be easily solved by passing the initial values as a parameter. Here is a modified version of the program.

Code Snippet
static T[] Fibonacci<T>(int no, T first, T second)
{
    var fib = new T[no];

    fib[0] = first;
    fib[1] = second;

    for (var i = 2; i < no; i++)
    {
        fib[i] = fib[i - 1] + fib[i - 2];
    }

    return fib;
}

 

But there is still another problem. There is still a compilation error.

Error    1    Operator ‘+’ cannot be applied to operands of type ‘T’ and ‘T’   

We can solve this problem with the dynamic keyword of C#. We can convert the last and second last item of the Fibonacci word using dynamic keyword before applying the concatenation words.

Here is a modified version of Fibonacci word.

Code Snippet
static T[] FibonacciGeneric<T>(int no, T first, T second)
{
    if (no < 2)
        return null;

    var fib = new T[no];

    fib[0] = first;
    fib[1] = second;

    for (var i = 2; i < no; i++)
    {
        dynamic last = fib[i - 1];
        dynamic secondlast = fib[i - 2];

        fib[i] = last + secondlast;
    }

    return fib;
}

Posted by: Zeeshan Amjad | March 12, 2014

Mutual recursion with C++ lambda function


We already saw an example of doing recursion with C++ lambda function here. Here we saw that how can we use std::function to store the function pointer to call lambda function recursively, because lambda function doesn’t have any name.

Things are bit interesting in case of mutual recursion. In case of mutual recursion there are more than one functions calls each other. It means that now we need not one but two function pointers stored in C++ wrapper.

Let’s start with our first attempt to create a simple even and odd function.

Here is a simple equation of mutual recursion.

Even_Function_Equation

In first step let’s create two wrappers for function.

Code Snippet
std::function<bool(int)> isEven;
std::function<bool(int)> isOdd;

 

Now lets create a function for this.

Code Snippet
isEven = [&isEven](int n) -> bool
{
    if (0 == n)
        return true;

    else
        return isOdd(n – 1);
};

isOdd = [&isOdd](int n) -> bool
{
    if (0 == n)
        return false;

    else
        return isEven(n – 1);
};

 

And we got the following error message.

error C3493: ‘isOdd’ cannot be implicitly captured because no default capture mode has been specified

error C3493: ‘isEven’ cannot be implicitly captured because no default capture mode has been specified

Now we have to specify the other lambda function in the lambda capture. Here is a modified version of the lambda function which implement mutual recursion.

Code Snippet
std::function<bool(int)> isEven;
std::function<bool(int)> isOdd;

isEven = [&isEven, &isOdd](int n) -> bool
{
    if (0 == n)
        return true;

    else
        return isOdd(n – 1);
};

isOdd = [&isOdd, &isEven](int n) -> bool
{
    if (0 == n)
        return false;

    else
        return isEven(n – 1);
};

 

Let’s see another example of mutual recursion. Here is a mutual recursive function for baby and adult rabbit pair in fibonacci sequence.

Mutual_Recursion

Here is a C++ lambda function of this.

Code Snippet
std::function<int(int no)> babyPair;
std::function<int(int no)> adultPair;

babyPair = [&babyPair, &adultPair](int no) -> int
{
    if (no == 1)
        return 1;
    else
        return adultPair(no – 1);
};

adultPair = [&adultPair, &babyPair](int no) -> int
{
    if (no == 1)
        return 0;
    else
        return adultPair(no – 1) + babyPair(no – 1);
};

Posted by: Zeeshan Amjad | March 1, 2014

Radio button in MVVM


Using the check box or any other control with MVVM is comparatively easy, because we usually bind one control with one property. But radio button is an interesting control, here we bind more than one control with one property.

When we are creating a radio button, we can defined different groups and all the radio button in one group work independent of other. And we usually bind one property to all radio button control in one group.

At our first step we bind all the radio button controls in one group to one variable, but the problem is how do we know which radio button is clicked. Let’s say we have a radio button group of direction. We have an enumerator for it.

Code Snippet
public enum Direction
{
    North,
    Easth,
    West,
    South
}

 

Which radio button is clicked we can achieve this in different ways. We can use the Converter and Converter Parameter to identify the radio button. We can even make that converter as a markup extension, so we even don’t have to create an object of it in XAML.

Here is a code of our simple enum to boolean convertor markup extension.

Code Snippet
[ValueConversion(typeof(bool), typeof(Enum))]
public class EnumToBoolExtension : MarkupExtension, IValueConverter
{
    #region IValueConverter
    
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return parameter.Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((bool) value) == true ? parameter : DependencyProperty.UnsetValue;
    }

    #endregion

    #region MarkupExtension

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    #endregion
}

 

And we can use this markup extension with radio button in this way.

Code Snippet
<RadioButton Grid.Row="0" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="North"
             IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.North}}"/>
<RadioButton Grid.Row="1" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="East"
             IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.Easth}}"/>
<RadioButton Grid.Row="2" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="West"
             IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.West}}"/>
<RadioButton Grid.Row="3" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="South"
             IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.South}}"/>

 

Rest of the things are very easy. We can create a enum Direction type property in our view Model to use radio button in MVVM.

Here is a complete C# code of the project.

Code Snippet
namespace WpfRadioButton
{
    using System;
    using System.ComponentModel;
    using System.Globalization;
    using System.Windows;
    using System.Windows.Data;
    using System.Windows.Markup;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ViewModel vm = new ViewModel();
        public MainWindow()
        {
            InitializeComponent();

            DataContext = vm;
        }
    }

    [ValueConversion(typeof(bool), typeof(Enum))]
    public class EnumToBoolExtension : MarkupExtension, IValueConverter
    {
        #region IValueConverter
        
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return parameter.Equals(value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return ((bool) value) == true ? parameter : DependencyProperty.UnsetValue;
        }

        #endregion

        #region MarkupExtension

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }

        #endregion
    }

    public enum Direction
    {
           North,
        Easth,
        West,
        South
    }

    public class ViewModel : INotifyPropertyChanged
    {
        public Direction direction;

        public Direction Direction
        {
            get
            {
                return this.direction;
            }

            set
            {
                this.direction = value;
                this.RaisePropertyChanged("Direction");
            }
        }

        #region NotifyPropertyChanged Methods

        public void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

 

And here is complete XAML code of the project

Code Snippet
<Window x:Class="WpfRadioButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        xmlns:local="clr-namespace:WpfRadioButton"
        Title="RadioButton" Height="200" Width="300">
    <Grid DataContext="{Binding}">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <RadioButton Grid.Row="0" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="North"
                     IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.North}}"/>
        <RadioButton Grid.Row="1" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="East"
                     IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.Easth}}"/>
        <RadioButton Grid.Row="2" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="West"
                     IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.West}}"/>
        <RadioButton Grid.Row="3" GroupName="directionText" Margin="5" VerticalAlignment="Center" Content="South"
                     IsChecked="{Binding Direction, Converter={local:EnumToBool}, ConverterParameter={x:Static local:Direction.South}}"/>
        <TextBlock Grid.Row="4" Margin="5" VerticalAlignment="Center" Text="{Binding Direction}"/>
    </Grid>
</Window>

 

This is an output of the program.

WpfRadioButtonMVVM

Posted by: Zeeshan Amjad | January 26, 2014

FileDialogViewModel revisited


We saw the first very simple implementation of FileDialogViewModel here. There is still a room of improvement in this class. The first obvious improvement is to get the name of open file. In previous version, we don’t have any indication on the screen that which file is currently open. Now let’s add this functionality.

The first step is to add the property in our FileService helper class because that class actually uses the OpenFileDialog and SaveFileDialog classes. Here is an updated version of our class.

Code Snippet
public sealed class FileService
{
    public string FileName
    {
        get;
        set;
    }

    public Stream OpenFile(string defaultExtension, string filter)
    {
        OpenFileDialog fd = new OpenFileDialog();
        fd.DefaultExt = defaultExtension;
        fd.Filter = filter;
        fd.Multiselect = false;

        bool? result = fd.ShowDialog();
        this.FileName = fd.FileName;

        return result.Value ? fd.OpenFile() : null;
    }

    public Stream SaveFile(string defaultExtension, string filter)
    {
        SaveFileDialog fd = new SaveFileDialog();
        fd.DefaultExt = defaultExtension;
        fd.Filter = filter;               

        bool? result = fd.ShowDialog();
        this.FileName = fd.FileName;

        return result.Value ? fd.OpenFile() : null;
    }        
}

 

Now we have to add this property in our FileDialogViewModel too. Here is our updated version of FileDialogViewModel class.

Code Snippet
public class FileDialogViewModel : ViewModelBase
{
    private string extension;
    private string filter;
    private string fileName;

    public FileDialogViewModel()
    {
        this.SaveCommand = new RelayCommand(this.SaveFile);
        this.OpenCommand = new RelayCommand(this.OpenFile);            
    }

    #region Properties

    public Stream Stream
    {
        get;
        set;
    }

    public string Extension
    {
        get
        {
            return this.extension;
        }

        set
        {
            this.extension = value;
            this.RaisePropertyChanged("Extension");
        }
    }

    public string Filter
    {
        get
        {
            return this.filter;
        }

        set
        {
            this.filter = value;
            this.RaisePropertyChanged("Filter");
        }
    }

    public string FileName
    {
        get
        {
            return this.fileName;
        }

        set
        {
            this.fileName = value;
            this.RaisePropertyChanged("FileName");
        }
    }

    public ICommand OpenCommand
    {
        get;
        set;
    }

    public ICommand SaveCommand
    {
        get;
        set;
    }

    #endregion

    private void OpenFile()
    {
        FileService fileServices = new FileService();
        this.Stream = fileServices.OpenFile(this.Extension, this.Filter);
        this.FileName = fileServices.FileName;
    }

    private void SaveFile()
    {
        FileService fileServices = new FileService();
        this.Stream = fileServices.SaveFile(this.Extension, this.Filter);
        this.FileName = fileServices.FileName;
    }
}

 

Now we can use this new property in another view model or even in XAML. In our previous example, we are creating an instance of FileDialogViewModel inside the MainViewModel. Let’s use the same approach and use this new property.

Code Snippet
public class MainViewmodel : ViewModelBase
{
    private string text;
    private string fileName;

    public MainViewmodel()
    {
        this.SaveCommand = new RelayCommand(this.SaveFile);
        this.OpenCommand = new RelayCommand(this.OpenFile);            
    }

    #region Properties

    public string Text
    {
        get
        {
            return this.text;
        }

        set
        {
            this.text = value;
            this.RaisePropertyChanged("Text");
        }
    }

    public string FileName
    {
        get
        {
            return string.IsNullOrEmpty(this.fileName) ? "No file selected" : this.fileName;
        }

        set
        {
            this.fileName = value;
            this.RaisePropertyChanged("FileName");
        }
    }

    public ICommand OpenCommand
    {
        get;
        set;
    }

    public ICommand SaveCommand
    {
        get;
        set;
    }

    #endregion

    private void OpenFile()
    {
        FileDialogViewModel fdvm = new FileDialogViewModel();
        fdvm.Extension = "*.txt";
        fdvm.Filter = "Text documents (.txt)|*.txt";

        fdvm.OpenCommand.Execute(null);

        if (fdvm.Stream == null)
            return;

        this.FileName = fdvm.FileName;

        using (StreamReader sr = new StreamReader(fdvm.Stream, Encoding.ASCII))
        {
            this.Text = sr.ReadToEnd();
        }
    }

    private void SaveFile()
    {
        FileDialogViewModel fdvm = new FileDialogViewModel();
        fdvm.Extension = "*.txt";
        fdvm.Filter = "Text documents (.txt)|*.txt";

        fdvm.SaveCommand.Execute(null);

        if (fdvm.Stream == null)
            return;

        this.FileName = fdvm.FileName;

        using (StreamWriter sw = new StreamWriter(fdvm.Stream, Encoding.ASCII))
        {
            sw.Write(this.Text.ToString(CultureInfo.InvariantCulture));    
        }           
    }
}

 

In XAML we just bind the new property to the tile of the main window to display the currently open file name in the title bar. Here is our XAML code of updated simple text editor.

Code Snippet
<Window x:Class="WpfFileDialog.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="{Binding FileName}" Height="350" Width="525">
    <Grid DataContext="{Binding}">
        <Grid.RowDefinitions>
            <RowDefinition Height="4*"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="10"
                 TextWrapping="Wrap" AcceptsReturn="True"
                 HorizontalScrollBarVisibility="Auto"
                 VerticalScrollBarVisibility="Auto"
                 Text="{Binding Text}"/>
        <Button Grid.Column="0" Grid.Row="2" Margin="10"
                Command="{Binding OpenCommand}">
            Open
        </Button>
        <Button Grid.Column="1" Grid.Row="2" Margin="10"
                Command="{Binding SaveCommand}">
            Save
        </Button>
    </Grid>
</Window>

 

This is a screen shot of the program. Notice the file name is displayed at the title bar.

FileDialogViewModel2

Posted by: Zeeshan Amjad | January 25, 2014

File Dialog ViewModel


During one of my WPF application, I came across a situation to display the File dialog to open and save the file. My first abstraction is to make a ViewModel for File dialog so I can reuse it. Although I can use the OpenFileDialog and SaveFileDialog classes from the FileViewModel, but I want to make the user interface logic separate from the ViewModel. To make the user interface logic separate, I created a small utility or helper class to to wrap the OpenFileDialog and SaveFileDialog functionality. Here is my class.

Code Snippet
public sealed class FileService
{
    public Stream OpenFile(string defaultExtension, string filter)
    {
        OpenFileDialog fd = new OpenFileDialog();
        fd.DefaultExt = defaultExtension;
        fd.Filter = filter;

        bool? result = fd.ShowDialog();

        return result.Value ? fd.OpenFile() : null;
    }

    public Stream SaveFile(string defaultExtension, string filter)
    {
        SaveFileDialog fd = new SaveFileDialog();
        fd.DefaultExt = defaultExtension;
        fd.Filter = filter;

        bool? result = fd.ShowDialog();

        return result.Value ? fd.OpenFile() : null;
    }        
}

 

Now my next step is to FileDialogViewModel. Assuming that I already have a ViewModelBase class that implements the INotifyPropertyChanged interface, here is a simple implementation of FileDialogViewModel.

Code Snippet
public class FileDialogViewModel : ViewModelBase
{
    public FileDialogViewModel()
    {
        this.SaveCommand = new RelayCommand(this.SaveFile);
        this.OpenCommand = new RelayCommand(this.OpenFile);            
    }

    #region Properties

    public Stream Stream
    {
        get;
        set;
    }

    public string Extension
    {
        get;
        set;
    }

    public string Filter
    {
        get;
        set;
    }
    public ICommand OpenCommand
    {
        get;
        set;
    }

    public ICommand SaveCommand
    {
        get;
        set;
    }

    #endregion

    private void OpenFile()
    {
        FileService fileServices = new FileService();
        this.Stream = fileServices.OpenFile(this.Extension, this.Filter);
    }

    private void SaveFile()
    {
        FileService fileServices = new FileService();
        this.Stream = fileServices.SaveFile(this.Extension, this.Filter);
    }
}

 

Because the return type of Execute method in ICommand interface doesn’t return anything, therefore, we created a Stream property to store the stream of file. This small FileDialogViewModel class encapsulate the functionality of opening and saving file without knowing anything about the user interface.

Now comes to our main view model that uses the FileDialogViewModel. Here is a simple implementation of our main view model that uses the FileDialogViewModel to open and save the file to make a simple text editor.

Code Snippet
public class MainViewmodel : ViewModelBase
{
    private string text;

    public MainViewmodel()
    {
        this.SaveCommand = new RelayCommand(this.SaveFile);
        this.OpenCommand = new RelayCommand(this.OpenFile);            
    }

    #region Properties

    public string Text
    {
        get
        {
            return this.text;
        }

        set
        {
            this.text = value;
            this.RaisePropertyChanged("Text");
        }
    }

    public ICommand OpenCommand
    {
        get;
        set;
    }

    public ICommand SaveCommand
    {
        get;
        set;
    }

    #endregion

    private void OpenFile()
    {
        FileDialogViewModel fdvm = new FileDialogViewModel();
        fdvm.Extension = "*.txt";
        fdvm.Filter = "Text documents (.txt)|*.txt";

        fdvm.OpenCommand.Execute(null);

        using (StreamReader sr = new StreamReader(fdvm.Stream, Encoding.ASCII))
        {
            this.Text = sr.ReadToEnd();
        }
    }

    private void SaveFile()
    {
        FileDialogViewModel fdvm = new FileDialogViewModel();
        fdvm.Extension = "*.txt";
        fdvm.Filter = "Text documents (.txt)|*.txt";

        fdvm.SaveCommand.Execute(null);

        using (StreamWriter sw = new StreamWriter(fdvm.Stream, Encoding.ASCII))
        {
            sw.Write(this.Text.ToString(CultureInfo.InvariantCulture));    
        }           
    }
}

 

Here is a complete XAML code of the program.

Code Snippet
<Window x:Class="WpfFileDialog.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        Title="FileViewModel" Height="350" Width="525">
    <Grid DataContext="{Binding}">
        <Grid.RowDefinitions>
            <RowDefinition Height="4*"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="10"
                 TextWrapping="Wrap" AcceptsReturn="True"
                 HorizontalScrollBarVisibility="Auto"
                 VerticalScrollBarVisibility="Auto"
                 Text="{Binding Text}"/>
        <Button Grid.Column="0" Grid.Row="2" Margin="10"
                Command="{Binding OpenCommand}">
            Open
        </Button>
        <Button Grid.Column="1" Grid.Row="2" Margin="10"
                Command="{Binding SaveCommand}">
            Save
        </Button>
    </Grid>
</Window>

And here is a complete C# code of this simple text editor using FileDialogViewModel

Code Snippet
namespace WpfFileDialog
{
    using System;
    using System.ComponentModel;
    using System.Globalization;
    using System.IO;
    using System.Text;
    using System.Windows;
    using System.Windows.Input;
    using Microsoft.Win32;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainViewmodel mvm = new MainViewmodel();

        public MainWindow()
        {
            InitializeComponent();

            DataContext = mvm;
        }
    }

    public class MainViewmodel : ViewModelBase
    {
        private string text;

        public MainViewmodel()
        {
            this.SaveCommand = new RelayCommand(this.SaveFile);
            this.OpenCommand = new RelayCommand(this.OpenFile);            
        }

        #region Properties

        public string Text
        {
            get
            {
                return this.text;
            }

            set
            {
                this.text = value;
                this.RaisePropertyChanged("Text");
            }
        }

        public ICommand OpenCommand
        {
            get;
            set;
        }

        public ICommand SaveCommand
        {
            get;
            set;
        }

        #endregion

        private void OpenFile()
        {
            FileDialogViewModel fdvm = new FileDialogViewModel();
            fdvm.Extension = "*.txt";
            fdvm.Filter = "Text documents (.txt)|*.txt";

            fdvm.OpenCommand.Execute(null);

            if (fdvm.Stream == null)
                return;

            using (StreamReader sr = new StreamReader(fdvm.Stream, Encoding.ASCII))
            {
                this.Text = sr.ReadToEnd();
            }
        }

        private void SaveFile()
        {
            FileDialogViewModel fdvm = new FileDialogViewModel();
            fdvm.Extension = "*.txt";
            fdvm.Filter = "Text documents (.txt)|*.txt";

            fdvm.SaveCommand.Execute(null);

            if (fdvm.Stream == null)
                return;

            using (StreamWriter sw = new StreamWriter(fdvm.Stream, Encoding.ASCII))
            {
                sw.Write(this.Text.ToString(CultureInfo.InvariantCulture));    
            }           
        }
    }

    public class FileDialogViewModel : ViewModelBase
    {
        public FileDialogViewModel()
        {
            this.SaveCommand = new RelayCommand(this.SaveFile);
            this.OpenCommand = new RelayCommand(this.OpenFile);            
        }

        #region Properties

        public Stream Stream
        {
            get;
            set;
        }

        public string Extension
        {
            get;
            set;
        }

        public string Filter
        {
            get;
            set;
        }
        public ICommand OpenCommand
        {
            get;
            set;
        }

        public ICommand SaveCommand
        {
            get;
            set;
        }

        #endregion

        private void OpenFile()
        {
            FileService fileServices = new FileService();
            this.Stream = fileServices.OpenFile(this.Extension, this.Filter);
        }

        private void SaveFile()
        {
            FileService fileServices = new FileService();
            this.Stream = fileServices.SaveFile(this.Extension, this.Filter);
        }
    }

    public sealed class FileService
    {
        public Stream OpenFile(string defaultExtension, string filter)
        {
            OpenFileDialog fd = new OpenFileDialog();
            fd.DefaultExt = defaultExtension;
            fd.Filter = filter;

            bool? result = fd.ShowDialog();

            return result.Value ? fd.OpenFile() : null;
        }

        public Stream SaveFile(string defaultExtension, string filter)
        {
            SaveFileDialog fd = new SaveFileDialog();
            fd.DefaultExt = defaultExtension;
            fd.Filter = filter;

            bool? result = fd.ShowDialog();

            return result.Value ? fd.OpenFile() : null;
        }        
    }

    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region NotifyPropertyChanged Methods

        public void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }

    public sealed class RelayCommand : ICommand
    {
        private Action function;

        public RelayCommand(Action function)
        {
            this.function = function;
        }

        public bool CanExecute(object parameter)
        {
            return this.function != null;
        }

        public void Execute(object parameter)
        {
            if (this.function != null)
            {
                this.function();
            }
        }

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

 

Here is an output of the program.

FileDialogViewModel

Posted by: Zeeshan Amjad | November 26, 2013

Logical Multivalue Converter with LINQ


We just studied the logical multivalve converter here. Now we are going to do the same thing but instead of doing it manually traversing every values and apply the “AND” or “OR” logical operation, we can achieve the same thing with LINQ. We can use the Extension methods “All” and “Any” defined for IEnumerable type to do the same thing.

Here is an updated version of our Logical And converter.

Code Snippet
using System.Linq;

namespace MyConverter
{
    using System.Windows.Data;

    [ValueConversion(typeof(bool), typeof(bool))]
    public class AndConverter : IMultiValueConverter
    {
        public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return values.Cast<bool>().All(value => value);
        }

        public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
}

 

Similarly here is an updated version of Logical Or operator.

Code Snippet
using System.Linq;

namespace MyConverter
{
    using System.Windows.Data;

    [ValueConversion(typeof(bool), typeof(bool))]
    public class OrConverter : IMultiValueConverter
    {
        public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return values.Cast<bool>().Any(value => value);
        }

        public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
}

 

Rest of the code of this application and out put is exactly the same as previous program. Here is our C# code.

 

Code Snippet
namespace MyConverter
{
    using System.Linq;
    using System.ComponentModel;

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new MyConditions();
        }
    }

    public class MyConditions : INotifyPropertyChanged
    {
        private bool _condition1;

        #region NotifyPropertyChanged Methods

        public void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        public bool Condition1
        {
            get
            {
                return _condition1;
            }

            set
            {
                _condition1 = value;
                RaisePropertyChanged("Condition1");
            }
        }

        public bool Condition2
        {
            get
            {
                return _condition1;
            }

            set
            {
                _condition1 = value;
                RaisePropertyChanged("Condition2");
            }
        }

        public bool Condition3
        {
            get
            {
                return _condition1;
            }

            set
            {
                _condition1 = value;
                RaisePropertyChanged("Condition3");
            }
        }

        public bool Condition4
        {
            get
            {
                return _condition1;
            }

            set
            {
                _condition1 = value;
                RaisePropertyChanged("Condition4");
            }
        }
    }
}

 

And here is our XAML.

Code Snippet
<Window x:Class="MyConverter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        xmlns:local="clr-namespace:MyConverter"
        Title="And Or Converters" Height="300" Width="400">
    <Window.Resources>
        <local:AndConverter x:Key="AndConverter"/>
        <local:OrConverter x:Key="OrConverter"/>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <CheckBox Grid.Row="0" VerticalAlignment="Center"
                  Name="Condition1" Margin="5" IsChecked="{Binding Condition1}"
                  Content="Conditin 1"/>
        <CheckBox Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"
                  Name="Condition2" Margin="5" IsChecked="{Binding Condition2}"
                  Content="Conditin 2"/>
        <CheckBox Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"
                  Name="Condition3" Margin="5" IsChecked="{Binding Condition3}"
                  Content="Conditin 3"/>
        <CheckBox Grid.Row="3" Grid.Column="0" VerticalAlignment="Center"
                  Name="Condition4" Margin="5" IsChecked="{Binding Condition4}"
                  Content="Conditin 4"/>
        <TextBox Grid.Row="4" Grid.Column="0" VerticalAlignment="Center"
                   Margin="5" Text="And Value Converter">
            <TextBox.IsEnabled>
                <MultiBinding Converter="{StaticResource AndConverter}">
                    <Binding Path="Condition1"/>
                    <Binding Path="Condition2"/>
                    <Binding Path="Condition3"/>
                    <Binding Path="Condition4"/>
                </MultiBinding>
            </TextBox.IsEnabled>
        </TextBox>
        <TextBox Grid.Column="1" Grid.Row="4" VerticalAlignment="Center"
                   Margin="5" Text="Or Value Converter">
            <TextBox.IsEnabled>
                <MultiBinding Converter="{StaticResource OrConverter}">
                    <Binding Path="Condition1"/>
                    <Binding Path="Condition2"/>
                    <Binding Path="Condition3"/>
                    <Binding Path="Condition4"/>
                </MultiBinding>
            </TextBox.IsEnabled>
        </TextBox>
    </Grid>
</Window>

 

Here is an output of the program.

LogicalMultiValueConverter

Posted by: Zeeshan Amjad | November 15, 2013

Logical Multi value Converter


During one of my project, I came across a situation where I should enable or disable a control based on not one condition, but more than one conditions. For example, do not enable the submit button until user input all the required information. Or do not enable the button to move the next page of the wizard until you select all the required information from all the combo boxes and check boxes in the current screen.

As like other things, this can be done in different ways in WPF. I decided to use multi value converter for this purpose. The reason is because it is very lightweight and can be make generic enough to reuse and unlike markup extension can be applied at run time when the value of properties changes.

We already have an example of not converter here. There is only one operand to not operator, therefore we can implement it using IValueConverter interface. However, And, Or, operator needs at least two operators, therefore it has to be IMultiValueConverter interface.

Making “And” and “Or” logical operator are very straight forward. Here is a code for “And Converter”.

Code Snippet
namespace MyConverter
{
    using System.Windows.Data;

    [ValueConversion(typeof(bool), typeof(bool))]
    public class AndConverter : IMultiValueConverter
    {
        public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool result = true;

            foreach (var item in values)
            {
                bool value = (bool)item;

                if (!value)
                {
                    return false;
                }
            }

            return result;
        }

        public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
}

 

The “Or Converter” is also very similar. Here is a code for “Or Converter”.

 

Code Snippet
namespace MyConverter
{
    using System.Windows.Data;

    [ValueConversion(typeof(bool), typeof(bool))]
    public class OrConverter : IMultiValueConverter
    {
        public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool result = false;

            foreach (var item in values)
            {
                bool value = (bool)item;

                if (value)
                {
                    return true;
                }
            }

            return result;
        }

        public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
}

 

Now how we are going to use it. Its usage is very similar to any other converter. First creates and object of this class, usually in XAML in resource section then pass bind the conditions to it. Here is a usage of it.

Code Snippet
<TextBox Grid.Row="4" VerticalAlignment="Center"
           Margin="5" Text="And Value Converter">
    <TextBox.IsEnabled>
        <MultiBinding Converter="{StaticResource andConverter}">
            <Binding Path="Condition1"/>
            <Binding Path="Condition2"/>
            <Binding Path="Condition3"/>
            <Binding Path="Condition4"/>
        </MultiBinding>
    </TextBox.IsEnabled>
</TextBox>

 

Here we bind the enable property of TextBox to 4 conditions. Because we are using And converter, therefore the textbox will enable if all the condition will be true. These conditions can be set using any other UI element, some business logic or even based on other conditions. Usage of Or converter is also very similar.

Here is complete XAML of this simple program.

Code Snippet
<Window x:Class="MyConverter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
        xmlns:local="clr-namespace:MyConverter"
        Title="And Or Converters" Height="300" Width="400">
    <Window.Resources>
        <local:AndConverter x:Key="andConverter"/>
        <local:OrConverter x:Key="orConverter"/>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <CheckBox Grid.Row="0" VerticalAlignment="Center"
                  Name="condition1" Margin="5" IsChecked="{Binding Condition1}"
                  Content="Conditin 1"/>
        <CheckBox Grid.Row="1" VerticalAlignment="Center"
                  Name="condition2" Margin="5" IsChecked="{Binding Condition2}"
                  Content="Conditin 2"/>
        <CheckBox Grid.Row="2" VerticalAlignment="Center"
                  Name="condition3" Margin="5" IsChecked="{Binding Condition3}"
                  Content="Conditin 3"/>
        <CheckBox Grid.Row="3" VerticalAlignment="Center"
                  Name="condition4" Margin="5" IsChecked="{Binding Condition4}"
                  Content="Conditin 4"/>
        <TextBox Grid.Row="4" VerticalAlignment="Center"
                   Margin="5" Text="And Value Converter">
            <TextBox.IsEnabled>
                <MultiBinding Converter="{StaticResource andConverter}">
                    <Binding Path="Condition1"/>
                    <Binding Path="Condition2"/>
                    <Binding Path="Condition3"/>
                    <Binding Path="Condition4"/>
                </MultiBinding>
            </TextBox.IsEnabled>
        </TextBox>
        <TextBox Grid.Column="1" Grid.Row="4" VerticalAlignment="Center"
                   Margin="5" Text="Or Value Converter">
            <TextBox.IsEnabled>
                <MultiBinding Converter="{StaticResource orConverter}">
                    <Binding Path="Condition1"/>
                    <Binding Path="Condition2"/>
                    <Binding Path="Condition3"/>
                    <Binding Path="Condition4"/>
                </MultiBinding>
            </TextBox.IsEnabled>
        </TextBox>
    </Grid>
</Window>

 

And here is a C# code of the program.

Code Snippet
namespace MyConverter
{
    using System.ComponentModel;
    using System.Windows;

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

            DataContext = new MyConditions();
        }
    }

    public class MyConditions : INotifyPropertyChanged
    {
        private bool condition1;
        private bool condition2;
        private bool condition3;
        private bool condition4;

        #region NotifyPropertyChanged Methods

        public void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        public bool Condition1
        {
            get
            {
                return this.condition1;
            }

            set
            {
                this.condition1 = value;
                this.RaisePropertyChanged("Condition1");
            }
        }

        public bool Condition2
        {
            get
            {
                return this.condition1;
            }

            set
            {
                this.condition1 = value;
                this.RaisePropertyChanged("Condition2");
            }
        }

        public bool Condition3
        {
            get
            {
                return this.condition1;
            }

            set
            {
                this.condition1 = value;
                this.RaisePropertyChanged("Condition3");
            }
        }

        public bool Condition4
        {
            get
            {
                return this.condition1;
            }

            set
            {
                this.condition1 = value;
                this.RaisePropertyChanged("Condition4");
            }
        }
    }
}

 

Here is an output of the program.

LogicalMultiValueConverter

Older Posts »

Categories

Follow

Get every new post delivered to your Inbox.

Join 524 other followers