Hi All,

I am working on a page that creates a dynamic MySql query with the selected fields at the run time and for this I want to take a combobox with few checkboxes so that based on their selection I can fetch the query result and populate them into the datagrid.
And also the most important thing I forgot to mention is that I want to achieve these functionalities in the ViewModel (VM) class only and if one could use templates for these comboboxes that would be an extra advantage.
Please see the screenshot below for the functionality module I want to achieve as of now. 94c5842ce31bfd8fb6f367bf0a6ba40d
Any help is highly appreciated.
Thanks :)

Recommended Answers

All 8 Replies

Personally speaking, a combobox is the wrong object for this job. It would be much better (and simpler) for the user, if you populated DataTables. Your functionality would still exist, only they UI would be better.

I would do this in a class structure that your ViewModel will utilise.

Create a Table and column class such as:

class TableViewModel : INotifyPropertyChanged
{
    string TableName;
    List<Column> Columns;
    bool IsSelected;

    /* Interface Implementation */
}

class ColumnViewModel : INotifyPropertyChanged
{
    TableViewModel ParentTable;
    String ColumnName;
    bool IsSelected;

    /* Interface Implementation */
}

Then in your Window ViewModel:

class CreateQueryViewModel
{
    List<TableViewModel> Tables;
}

Then you need to bind your first DataGridView (or even a TreeView) to the Tables object on your ViewModel.
Hook into the OnPropertyChanged event for each of your TableViewModel and everytime you detect that one has been selected, add a DataGridView for that Table and bind the column list to the Columns property.

Thanks a lot for your reply.
I have taken help from your code and added some new methods and class and its working fine now for me.

Hi,

Could you please see the following code :-

For xaml :-

<UserControl.Resources>
        <DataTemplate x:Key="chkBoxTemplate">
            <CheckBox Content="{Binding AllTablesCheckBoxContent, UpdateSourceTrigger=PropertyChanged}" IsChecked="{Binding IsTableChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        </DataTemplate>
    </UserControl.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <StackPanel>
                <TextBlock x:Name="txtAllTables" Text="Existing Tables" Height="25" Width="150" FontWeight="Bold" />
                <ComboBox x:Name="cmbAllTables" Height="25" Width="175" ItemTemplate="{StaticResource chkBoxTemplate}" ItemsSource="{Binding AllTables, UpdateSourceTrigger=PropertyChanged}" />
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>

For ViewModel :-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Windows.Data;
using Microsoft.Practices.Prism.Commands;
using MyProjectDemo.Classes;
using MySql.Data.MySqlClient;
using System.Data;

namespace MyProjectDemo.ViewModel
{
    public class MultipleDatumFilterVM : INotifyPropertyChanged
    {
        #region Fields

        private ObservableCollection<AllTablesCheckbox> _allTables;

        private bool _isTableChecked = false;

        #endregion

        #region Public Variables

        public MySqlConnection mySqlCon;

        #endregion

        #region Properties

        public ObservableCollection<AllTablesCheckbox> AllTables
        {
            get { return _allTables; }
            set
            {
                _allTables = value;
                OnPropertyChanged("AllTables");
            }
        }

        public bool IsTableChecked
        {
            get { return _isTableChecked; }
            set
            {
                _isTableChecked = value;
                OnPropertyChanged("IsTableChecked");
            }
        }

        #endregion

        #region Commands

        #endregion

        #region Constructors

        public MultipleDatumFilterVM()
        {
            mySqlCon = new MySqlConnection("Server=127.0.0.1; Database=test; Uid=root");
            ListTables();
        }

        #endregion

        #region Private Methods

        private void ListTables()
        {
            try
            {
                mySqlCon.Open();
                List<string> tables = new List<string>();
                _allTables = new ObservableCollection<AllTablesCheckbox>();
                AllTablesCheckbox allTablesCheckbox = new AllTablesCheckbox();
                DataTable dt = mySqlCon.GetSchema("Tables");
                foreach (DataRow row in dt.Rows)
                {
                    string tablename = (string)row[2];
                    tables.Add(tablename);
                }
                foreach (var item in tables)
                {
                    _allTables.Add(new AllTablesCheckbox() { AllTablesCheckBoxContent = item, IsAllTablesCheckBoxChecked = IsTableChecked });
                }
                mySqlCon.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion

        #region OnPropertyChangedEvent

        public event PropertyChangedEventHandler PropertyChanged;

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

        #endregion
    }

    #region Classes

    public class AllTablesCheckbox
    {
        public string AllTablesCheckBoxContent { get; set; }
        public bool IsAllTablesCheckBoxChecked { get; set; }
    }

    #endregion
}

Here I am getting fields in the combobox with checkbox but not getting the IsChecked property fired. Actually I have the same scenario as discussed in the beginning of this article but I'm unfortunately stucked here at the first place only.
Could you please help me updating the code so that I can achieve the same functionality please ?

Did you add the viewmodel to the window datacontext?

<Window /* Add a namespace location for your viewmodel class eg. vm */>
    <Window.DataContext>
        <vm:MultipleDatumFilterVM />
    </Window.DataContext>
....
</Window>

Then in your code behind, in the constructor, point your Window DataContext to the ViewModel instantiation.

public partial class MyWindow : Window
{
    public MultipleDatumFilterVM ViewModel = new MultipleDatumFilterVM();

    public MyWindow()
    {
        IntialiseComponent();

        DataContext = ViewModel;
    }

    ...
}

Remember that when you fire the checkbox changed event, to fire OnPropertyChanged for the other items you're bound to, otherwise they won't pick up the changes (if you don't make manual adjustments).

eg

public class CheckBoxViewModel : INotifyPropertyChanged
{
    public CheckBoxViewModel()
    {
        IsChecked = false;
    }

    private bool _isChecked;

    public bool IsChecked
    {
        get { return _isChecked; }
        set { _isChecked = value; FireEvent("IsChecked"); FireEvent("Output"); }
    }

    public string Output
    {
        get { return IsChecked.ToString(); }
    }

    private void FireEvent(string paramName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(paramName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

If I didn't manually fire the event for "Output" then anything watching that property would never get updated.

I already tried these things out however I have done this by removing the class member "IsAllTablesCheckBoxChecked", taking data template of checkbox inside the comobobox and adding an Event Trigger by calling a dependency property that I discussed about in the previous article and my final code is up and running.
My code is as follows :-

xaml :-

<UserControl x:Class="MyProjectDemo.View.MultipleDatumFilter"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"   
             xmlns:interatComm="clr-namespace:InteractivityHelper"
             mc:Ignorable="d" 
             MinHeight="600" MinWidth="800">
    <Grid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <StackPanel>
                <TextBlock x:Name="txtAllTables" Text="Existing Tables" Height="25" Width="150" FontWeight="Bold" />
                <ComboBox x:Name="cmbAllTables" Height="25" Width="175" ItemsSource="{Binding AllTables, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedTableContents, UpdateSourceTrigger=PropertyChanged}">

                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="SelectionChanged">
                            <interatComm:InteractiveCommand Command="{Binding DelegateCmdCheckChange}" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>

                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <CheckBox Content="{Binding AllTablesCheckBoxContent, UpdateSourceTrigger=PropertyChanged}" IsChecked="{Binding IsAllTablesCheckBoxChecked, Mode=TwoWay}">
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="Click">
                                        <interatComm:InteractiveCommand Command="{Binding Path=DataContext.DelegateCmdCheckChange, 
                                    RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}" />
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </CheckBox>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>

View Model :-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Windows.Data;
using Microsoft.Practices.Prism.Commands;
using MyProjectDemo.Classes;
using MySql.Data.MySqlClient;
using System.Data;

namespace MyProjectDemo.ViewModel
{
    public class MultipleDatumFilterVM : INotifyPropertyChanged
    {
        #region Fields

        private ObservableCollection<AllTablesCheckbox> _allTables;

        private string _allTablesCheckBoxContent = string.Empty;

        private string _tableSelectedItem = string.Empty;

        private string _selectedTableContents = string.Empty;

        private DelegateCommand<RoutedEventArgs> _DelegateCmdCheckChange = null;

        #endregion

        #region Public Variables

        public MySqlConnection mySqlCon;

        public CheckBox selectedTableChecked;

        #endregion

        #region Properties

        public ObservableCollection<AllTablesCheckbox> AllTables
        {
            get { return _allTables; }
            set
            {
                _allTables = value;
                OnPropertyChanged("AllTables");
            }
        }

        public string AllTablesCheckBoxContent
        {
            get { return _allTablesCheckBoxContent; }
            set
            {
                _allTablesCheckBoxContent = value;
                OnPropertyChanged("AllTablesCheckBoxContent");
            }
        }

        public string TableSelectedItem
        {
            get { return _tableSelectedItem; }
            set
            {
                _tableSelectedItem = value;
                OnPropertyChanged("TableSelectedItem");
            }
        }

        public string SelectedTableContents
        {
            get { return _selectedTableContents; }
            set
            {
                _selectedTableContents = value;
                OnPropertyChanged("SelectedTableContents");
            }
        }

        #endregion

        #region Commands

        public DelegateCommand<RoutedEventArgs> DelegateCmdCheckChange
        {
            get
            {
                return this._DelegateCmdCheckChange ?? new DelegateCommand<RoutedEventArgs>(ExecuteCommandOnCheckChange);
            }
        }

        #endregion

        #region Constructors

        public MultipleDatumFilterVM()
        {
            mySqlCon = new MySqlConnection("Server=127.0.0.1; Database=test; Uid=root");
            selectedTableChecked = new CheckBox();
            ListTables();
        }

        #endregion

        #region Private Methods

        private void ExecuteCommandOnCheckChange(RoutedEventArgs sender)
        {
            try
            {
                _tableSelectedItem = ((System.Windows.Controls.ContentControl)(sender.OriginalSource)).Content.ToString();
                selectedTableChecked = ((System.Windows.Controls.Primitives.ToggleButton)(sender.OriginalSource)) as CheckBox;

                if (selectedTableChecked.IsChecked == true)
                {
                    if (string.IsNullOrEmpty(_selectedTableContents))
                    {
                        _selectedTableContents = _tableSelectedItem;
                    }
                    else
                    {
                        _selectedTableContents = _selectedTableContents + "," + _tableSelectedItem;
                    }
                }
                else
                {
                    _selectedTableContents = _selectedTableContents.Replace(_tableSelectedItem, string.Empty);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void ListTables()
        {
            try
            {
                mySqlCon.Open();
                List<string> tables = new List<string>();
                _allTables = new ObservableCollection<AllTablesCheckbox>();
                AllTablesCheckbox allTablesCheckbox = new AllTablesCheckbox();
                DataTable dt = mySqlCon.GetSchema("Tables");
                foreach (DataRow row in dt.Rows)
                {
                    string tablename = (string)row[2];
                    tables.Add(tablename);
                }
                foreach (var item in tables)
                {
                    _allTables.Add(new AllTablesCheckbox() { AllTablesCheckBoxContent = item });
                }
                mySqlCon.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion

        #region OnPropertyChangedEvent

        public event PropertyChangedEventHandler PropertyChanged;

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

        #endregion
    }

    #region Classes

    public class AllTablesCheckbox
    {
        public string AllTablesCheckBoxContent { get; set; }
        public bool IsAllTablesCheckBoxChecked { get; set; }
    }

    #endregion
}

Thanks for your reply too, I'll try that also :)

Hi,

I am again stuck at creating dynamic controls i.e., second step in the image at the beginning (upon clicking of the checkbox I need to generate a new combo box with again some check boxes displaying the fields of that selected table) but in ViewModel only.
Below is my current code :-

xaml :-

<UserControl x:Class="MyProjectDemo.View.MultipleDatumFilter"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"   
              xmlns:interatComm="clr-namespace:InteractivityHelper"
             mc:Ignorable="d" 
             MinHeight="600" MinWidth="800" x:Name="MultipleDatumUC">
    <UserControl.Resources>

    </UserControl.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <StackPanel>
                <TextBlock x:Name="txtAllTables" Text="Existing Tables" Height="25" Width="150" FontWeight="Bold" />
                <ComboBox x:Name="cmbAllTables" Height="25" Width="175" ItemsSource="{Binding AllTables, UpdateSourceTrigger=PropertyChanged}">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <CheckBox Content="{Binding AllTablesCheckBoxContent, UpdateSourceTrigger=PropertyChanged}" IsChecked="{Binding IsAllTablesCheckBoxChecked, Mode=TwoWay}">
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="Click">
                                        <interatComm:InteractiveCommand Command="{Binding Path=DataContext.DelegateCmdCheckChange, 
                                    RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}" />
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </CheckBox>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>

ViewModel :-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Input;
using System.Windows.Data;
using Microsoft.Practices.Prism.Commands;
using MyProjectDemo.Classes;
using MySql.Data.MySqlClient;
using System.Data;

namespace MyProjectDemo.ViewModel
{
    public class MultipleDatumFilterVM : INotifyPropertyChanged
    {
        #region Fields

        private ObservableCollection<AllTablesCheckbox> _allTables;

        private string _allTablesCheckBoxContent = string.Empty;

        private string _tableSelectedItem = string.Empty;

        private DelegateCommand<RoutedEventArgs> _delegateCmdCheckChange = null;

        #endregion

        #region Public Variables

        public MySqlConnection mySqlCon;

        public CheckBox selectedTableChecked;

        #endregion

        #region Properties

        public ObservableCollection<AllTablesCheckbox> AllTables
        {
            get { return _allTables; }
            set
            {
                _allTables = value;
                OnPropertyChanged("AllTables");
            }
        }

        public string AllTablesCheckBoxContent
        {
            get { return _allTablesCheckBoxContent; }
            set
            {
                _allTablesCheckBoxContent = value;
                OnPropertyChanged("AllTablesCheckBoxContent");
            }
        }

        public string TableSelectedItem
        {
            get { return _tableSelectedItem; }
            set
            {
                _tableSelectedItem = value;
                OnPropertyChanged("TableSelectedItem");
            }
        }

        #endregion

        #region Commands

        public DelegateCommand<RoutedEventArgs> DelegateCmdCheckChange
        {
            get
            {
                return this._delegateCmdCheckChange ?? new DelegateCommand<RoutedEventArgs>(ExecuteCommandOnCheckChange);
            }
        }

        #endregion

        #region Constructors

        public MultipleDatumFilterVM()
        {
            mySqlCon = new MySqlConnection("Server=127.0.0.1; Database=test; Uid=root");
            selectedTableChecked = new CheckBox();
            ListTables();
        }

        #endregion

        #region Private Methods

        private void ListTables()
        {
            try
            {
                mySqlCon.Open();
                List<string> tables = new List<string>();
                _allTables = new ObservableCollection<AllTablesCheckbox>();
                AllTablesCheckbox allTablesCheckbox = new AllTablesCheckbox();
                DataTable dt = mySqlCon.GetSchema("Tables");
                foreach (DataRow row in dt.Rows)
                {
                    string tablename = (string)row[2];
                    tables.Add(tablename);
                }
                foreach (var item in tables)
                {
                    _allTables.Add(new AllTablesCheckbox() { AllTablesCheckBoxContent = item });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                mySqlCon.Close();
            }
        }

        private void ExecuteCommandOnCheckChange(RoutedEventArgs sender)
        {
            try
            {
                _tableSelectedItem = ((System.Windows.Controls.ContentControl)(sender.OriginalSource)).Content.ToString();
                selectedTableChecked = ((System.Windows.Controls.Primitives.ToggleButton)(sender.OriginalSource)) as CheckBox;

                if (selectedTableChecked.IsChecked == true)
                {
                    mySqlCon.Open();
                    DataSet mySqlDataSet = new DataSet();
                    MySqlCommand mySqlCommand = mySqlCon.CreateCommand();
                    mySqlCommand.CommandText = "SELECT column_name FROM information_schema.columns WHERE table_name='" + _tableSelectedItem + "';";
                    MySqlDataAdapter mySqlDataAdapter = new MySqlDataAdapter(mySqlCommand);
                    mySqlDataAdapter.Fill(mySqlDataSet);
                    List<string> myList = new List<string>();
                    ComboBox myCmb = new ComboBox();
                    CheckBox chkOutputTableColumns = new CheckBox();
                    foreach (DataRow r in mySqlDataSet.Tables[0].Rows)
                    {
                        myList.Add(r.ItemArray[0].ToString());
                    }
                }
                else
                {

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                mySqlCon.Close();
            }
        }

        #endregion

        #region OnPropertyChangedEvent

        public event PropertyChangedEventHandler PropertyChanged;

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

        #endregion
    }

    #region Classes

    public class AllTablesCheckbox
    {
        public string AllTablesCheckBoxContent { get; set; }
        public bool IsAllTablesCheckBoxChecked { get; set; }
    }

    #endregion
}

Any help on this is highly appreciated.

This question is a bit too involved for me to answer quickly in the time I have available. However, there is a tutorial on dynamic control creation available at Tech Pro which should get you headed in the right direction.

Hey I did this one on my own...anyways thanks for your reply, much appreciate that :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.