Create DataGridTemplateColumn Through C# Code
Asked Answered
F

2

17

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; }
    }
}
Flanigan answered 8/1, 2012 at 18:6 Comment(1)
You shouldn't be reusing the same binding instance for different bindings...Ripen
R
4

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.

Ripen answered 8/1, 2012 at 18:22 Comment(14)
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?Flanigan
@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).Ripen
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!Flanigan
@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...Ripen
Yes, I have added this in. The value still isn't displayed in the TextBlock after choosing it.Flanigan
@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.Ripen
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.Flanigan
@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.Ripen
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'.Flanigan
@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.Ripen
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.Flanigan
@EricR.: The problem is the Transaction.Account property, all that other stuff seems fine. What does the transaction class look like?Ripen
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.Flanigan
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!Flanigan
H
1
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.

Hemicycle answered 23/5, 2012 at 6:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.