Create DataGridTemplateColumn Through C# Code

16,142

Solution 1

You bind the ItemsSource to the selected value, a string, aka char array, so every character is used as an item, the ItemsSource binding presumably should target some other collection from which the value can be chosen.

Solution 2

Dim newBind As Binding = New Binding("LinktoCommonOutputBus")
newBind.Mode = BindingMode.OneWay

factory1.SetValue(ComboBox.ItemsSourceProperty, dictionary)
factory1.SetValue(ComboBox.NameProperty, name)
factory1.SetValue(ComboBox.SelectedValuePathProperty, "Key")
factory1.SetValue(ComboBox.DisplayMemberPathProperty, "Value")
factory1.SetBinding(ComboBox.SelectedValueProperty, newBind)

By creating Binding you can set SelectedValue in a datagrid for WPF.

Share:
16,142
Eric R.
Author by

Eric R.

Updated on June 05, 2022

Comments

  • Eric R.
    Eric R. almost 2 years

    I have a dynamic Datagrid that I have created. I am creating each column for it through code behind. I am having troubles on a column that I want to be displayed at a textblock when not editing, but as a combobox while editing. I have an ObservableCollection of Transactions. Each Transaction has a type called "Account". Here is what I have so far:

        private DataGridTemplateColumn GetAccountColumn()
        {
            // Create The Column
            DataGridTemplateColumn accountColumn = new DataGridTemplateColumn();
            accountColumn.Header = "Account";
    
            Binding bind = new Binding("Account");
            bind.Mode = BindingMode.TwoWay;
    
            // Create the TextBlock
            FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBlock));
            textFactory.SetBinding(TextBlock.TextProperty, bind);
            DataTemplate textTemplate = new DataTemplate();
            textTemplate.VisualTree = textFactory;
    
            // Create the ComboBox
            bind.Mode = BindingMode.OneWay;
            FrameworkElementFactory comboFactory = new FrameworkElementFactory(typeof(ComboBox));
            comboFactory.SetValue(ComboBox.DataContextProperty, this.Transactions);
            comboFactory.SetValue(ComboBox.IsTextSearchEnabledProperty, true);
            comboFactory.SetBinding(ComboBox.ItemsSourceProperty, bind);
    
            DataTemplate comboTemplate = new DataTemplate();
            comboTemplate.VisualTree = comboFactory;
    
            // Set the Templates to the Column
            accountColumn.CellTemplate = textTemplate;
            accountColumn.CellEditingTemplate = comboTemplate;
    
            return accountColumn;
        }
    

    The value displays in the TextBlock. However, in the combobox, I am only getting one character to display per item. For example, here is the textblock:

    enter image description here

    But when I click to edit and go into the combobox, here is what is shown:

    enter image description here

    Can someone help me out so that the items in the Combobox are displayed properly? Also, when I select something from the Combobox, the textblock isn't updated with the item I selected.

    UPDATED:

    Here is my column as of now. The items in the ComboBox are being displayed properly. The issue now is that when a new item is selected, the text in the TextBlock isn't updated with the new item.

        private DataGridTemplateColumn GetAccountColumn()
        {
            // Create The Column
            DataGridTemplateColumn accountColumn = new DataGridTemplateColumn();
            accountColumn.Header = "Account";
    
            Binding bind = new Binding("Account");
            bind.Mode = BindingMode.OneWay;
    
            // Create the TextBlock
            FrameworkElementFactory textFactory = new FrameworkElementFactory(typeof(TextBlock));
            textFactory.SetBinding(TextBlock.TextProperty, bind);
            DataTemplate textTemplate = new DataTemplate();
            textTemplate.VisualTree = textFactory;
    
            // Create the ComboBox
            Binding comboBind = new Binding("Account");
            comboBind.Mode = BindingMode.OneWay;
    
            FrameworkElementFactory comboFactory = new FrameworkElementFactory(typeof(ComboBox));
            comboFactory.SetValue(ComboBox.IsTextSearchEnabledProperty, true);
            comboFactory.SetValue(ComboBox.ItemsSourceProperty, this.Accounts);
            comboFactory.SetBinding(ComboBox.SelectedItemProperty, comboBind);
    
            DataTemplate comboTemplate = new DataTemplate();
            comboTemplate.VisualTree = comboFactory;
    
            // Set the Templates to the Column
            accountColumn.CellTemplate = textTemplate;
            accountColumn.CellEditingTemplate = comboTemplate;
    
            return accountColumn;
        }
    

    The "Accounts" property is declared like this in my MainWindow class:

    public ObservableCollection<string> Accounts { get; set; }
    
        public MainWindow()
        {
            this.Types = new ObservableCollection<string>();
            this.Parents = new ObservableCollection<string>();
            this.Transactions = new ObservableCollection<Transaction>();
            this.Accounts = new ObservableCollection<string>();
    
            OpenDatabase();
            InitializeComponent();
        }
    

    Here is my Transaction Class:

    public class Transaction
    {
        private string date;
        private string number;
        private string account;
    
        public string Date
        {
            get { return date; }
            set { date = value; }
        }
    
        public string Number
        {
            get { return number; }
            set { number = value; }
        }
    
        public string Account
        {
            get { return account; }
            set { account = value; }
        }
    }
    
  • Eric R.
    Eric R. over 12 years
    Ahhh yes that makes sense! Thanks for the info! I added code so that the itemssource comes from a different collection now. The items in the combobox appear as they should. One more thing though, when I select a different value from the combobox, the textblock isn't updated with the new item. How would I fix that?
  • H.B.
    H.B. over 12 years
    @EricR.: Bind the SelectedItem or SelectedValue to Account. Use SelectedItem if the items are already the strings that should be used as value for account, use SelectedValue in combination with SelectedValuePath if the value is a property on the selected item (and not the item itself).
  • Eric R.
    Eric R. over 12 years
    How would I do that? The new collection for Accounts that I am using is an ObservableCollection<string>. I am setting the ItemsSource now by this: comboFactory.SetValue(ComboBox.ItemsSourceProperty, this.Accounts);. this.Accounts is the ObservableCollection. So how would I set the SelectedItem for that? I really appreciate all the help you have given me so far!
  • H.B.
    H.B. over 12 years
    @EricR.: Create a new Binding with the path "Account" and use SetBinding to set it on the SelectedItemProperty, that should be all you need to do...
  • Eric R.
    Eric R. over 12 years
    Yes, I have added this in. The value still isn't displayed in the TextBlock after choosing it.
  • H.B.
    H.B. over 12 years
    @EricR.: Did you confirm the change using return? In a DataGrid edits normally need to be confirmed before they affect the item. Speaking of which, the DataGridComboBoxColumn should already do exactly what you appear to want: Display the value and show a combo-box when editing.
  • Eric R.
    Eric R. over 12 years
    I have edited my question to show what my current function looks like to create the column. Let me know your thoughts since the TextBlock still isn't updating when a new item is selected.
  • H.B.
    H.B. over 12 years
    @EricR.: Obviously the binding on the SelectedItem needs to be TwoWay, i never said you should change it to OneWay which makes it unable to change the Account property.
  • Eric R.
    Eric R. over 12 years
    I know you never said that. I added that in as part of my testing because when I have the mode set to TwoWay, I get the following error: A TwoWay or OneWayToSource binding cannot work on the read-only property 'Account' of type 'System.Data.DataRowView'.
  • H.B.
    H.B. over 12 years
    @EricR.: That means your data item which owns the account property does not allow you to change it in the first place, so the whole combobox is rather pointless.
  • Eric R.
    Eric R. over 12 years
    I am confused about what to do next. It is not my intention to have this as a readonly property. I edited my response again to show how I declare my property. All is done in my MainWindow class.
  • H.B.
    H.B. over 12 years
    @EricR.: The problem is the Transaction.Account property, all that other stuff seems fine. What does the transaction class look like?
  • Eric R.
    Eric R. over 12 years
    I updated above again to show my Transaction class. I am creating the Account Property the same way as my other properties. It is just a string basically.
  • Eric R.
    Eric R. over 12 years
    I figured it out. I was loading my datagrid initially from an SQL query on my Database. The query was performing an inner join to get the value for the Account Column. Apparently this set the column on my DataTable to readonly. Took me awhile to track that one down. So now I just set the readonly property to false and I can use my ComboBox to change it and the text displays in my TextBlock. Thanks so much for all your help!