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; }
    }
}
Eric R.
  • 1,105
  • 3
  • 21
  • 48

2 Answers2

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.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • 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? – Eric R. Jan 08 '12 at 19:10
  • @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`](http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.selector.selectedvalue.aspx) in combination with [`SelectedValuePath`](http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.selector.selectedvalue.aspx) if the value is a property on the selected item (and not the item itself). – H.B. Jan 08 '12 at 19:24
  • How would I do that? The new collection for Accounts that I am using is an ObservableCollection. 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! – Eric R. Jan 08 '12 at 20:20
  • @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... – H.B. Jan 08 '12 at 20:26
  • Yes, I have added this in. The value still isn't displayed in the TextBlock after choosing it. – Eric R. Jan 08 '12 at 20:37
  • @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. – H.B. Jan 08 '12 at 20:42
  • 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. – Eric R. Jan 08 '12 at 21:57
  • @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. – H.B. Jan 08 '12 at 22:50
  • 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'. – Eric R. Jan 08 '12 at 23:16
  • @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. – H.B. Jan 08 '12 at 23:18
  • 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. – Eric R. Jan 08 '12 at 23:48
  • @EricR.: The problem is the `Transaction.Account` property, all that other stuff seems fine. What does the transaction class look like? – H.B. Jan 09 '12 at 00:13
  • 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. Jan 09 '12 at 00:25
  • 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! – Eric R. Jan 09 '12 at 04:39
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.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Swapnil Tandel
  • 94
  • 1
  • 12