-1

Update:

I successfully enable to update property by change value in the textbox. But for the combobox I am still confused. I update the code so that might help to illustrate my confusion.

    class viewModelObj:INotifyPropertyChanged
    {
        public string displayName { get; set; }
        public Dictionary<string,string> generalNote { get; set; }

        private int _weight;
        public int Weight
        {
            get { return _weight; }
            set
            {
                _weight = value;
                OnPropertyChanged("Weight");
                MessageBox.Show($"Weight changed from model.");
            }
        }

        private string _material;
        public string Material
        {
            get { return _material; }
            set
            {
                _material = value;
                OnPropertyChanged("Material");
                MessageBox.Show($"Material changed from model.");
            }
        }
        public viewModelObj(string name)
        {
            displayName = name;
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }

XAML:

    <ListBox x:Name="catDocListView" Grid.Column="0" Grid.RowSpan="2" Margin="16" ItemContainerStyle="{StaticResource ContainerStyle}" ItemsSource="{Binding viewModelSource}" DisplayMemberPath="displayName">
    </ListBox>
    <ComboBox x:Name="materialCombo" Grid.Column="1" HorizontalAlignment="Stretch" Margin="8" ItemsSource="{Binding viewModelSource}" SelectedItem="{Binding viewModelObj}">
         <ComboBoxItem>ABC</ComboBoxItem>
         <ComboBoxItem>DEF</ComboBoxItem>
         <ComboBoxItem>XYZ</ComboBoxItem>
    </ComboBox>
    <TextBox Grid.Row="1" Grid.Column="2" BorderBrush="Black" Text="{Binding ElementName=catDocListView, Path=SelectedItem.Weight, Mode=TwoWay}"/>
    <DataGrid x:Name="generalNoteDG" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding generalNoteSource}">
         <DataGrid.Columns>
                <DataGridCheckBoxColumn/>
                <DataGridTextColumn Header="Note" Binding="{Binding note}" Width="Auto"/>
                <DataGridTextColumn Header="No" Binding="{Binding no}" Width="Auto"/>
                <DataGridTextColumn Header="English Note" Binding="{Binding eng}" Width="Auto"/>
                <DataGridTextColumn Header="German Note" Binding="{Binding deu}" Width="Auto"/>
          </DataGrid.Columns>
    </DataGrid>

The viewModelSource is a ObservableCollection of viewModelObj class.

If you check the TextBox tag you will understand. Assuming I have now two items in the ListBox, I select the first one and the corresponding textbox shows the value of Weight property. I update the textbox then the value is also updated. After I select the second item and switch back to the first item, the value shown in the textbox should be the already updated one.

I want the same feature to the combobox.

Original Post

I try to explain the question more clearly because I think it is little tricky.

Let's say we have a Listbox that displays all possible items, a Combobox that displays available item which are independant to any other value, a Textbox and a Datagrid that shows preloaded values which are also independant to any other value, in a GUI page.

A class viewModelObj has some properties corresponding to the Combobox, Textbox and Datagrid. A ObservableCollection contains several such classes.

I now one-way bind the ObservableCollection to the Listbox. No matter which item I choose in the Listbox, the available items in the Combobox and values in the Datagrid should remain unchanged. But when I make the selection in Combobox and Datagrid (it has a checkbox column), the corresponding property of the viewModelObj class should be changed/added (at the beginning they are null).

XAML:

    <ListBox x:Name="catDocListView" Grid.Column="0" Grid.RowSpan="2" Margin="16" ItemContainerStyle="{StaticResource ContainerStyle}" ItemsSource="{Binding}" DisplayMemberPath="displayName">
    </ListBox>
    <ComboBox x:Name="materialCombo" Grid.Column="1" HorizontalAlignment="Stretch" Margin="8" ItemsSource="{Binding viewModelSource}" SelectedItem="{Binding viewModelObj}">
         <ComboBoxItem>ABC</ComboBoxItem>
         <ComboBoxItem>DEF</ComboBoxItem>
         <ComboBoxItem>XYZ</ComboBoxItem>
    </ComboBox>
    <TextBox Grid.Row="1" Grid.Column="2" BorderBrush="Black"></TextBox>
    <DataGrid x:Name="generalNoteDG" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding generalNoteSource}">
         <DataGrid.Columns>
                <DataGridCheckBoxColumn/>
                <DataGridTextColumn Header="Note" Binding="{Binding note}" Width="Auto"/>
                <DataGridTextColumn Header="No" Binding="{Binding no}" Width="Auto"/>
                <DataGridTextColumn Header="English Note" Binding="{Binding eng}" Width="Auto"/>
                <DataGridTextColumn Header="German Note" Binding="{Binding deu}" Width="Auto"/>
          </DataGrid.Columns>
    </DataGrid>

The viewModelSource and generalNoteSource are all in the viewModel.cs

As you can see, the Datagrid source binds to another List and the availble items in the Combobox are given manuelly. When I try to bind the itemsource of the Combobox to the ObservableCollection of the viewModelObj, an error pops up.

System.Windows.Markup.XamlParseException: ''Add value to collection of type 'System.Windows.Controls.ItemCollection' threw an exception.' 

The viewModelObj:

    class viewModelObj
    {
        public string displayName { get; set; }
        public string material { get; set; }
        public int weight { get; set; }
        public Dictionary<string,string> generalNote { get; set; }

        public viewModelObj(string name)
        {
            displayName = name;
        }
    }

The display property shows item in Listbox, material refers to the combobox and the generalNote corresponds to the value selected in the datagrid.

Now I'm confused how to use two-way binding to get selected values in the combobox, datagrid and textbox with predefined values.

Hope I explain the question clear.

Could someone give me a hint?

BabyHai
  • 89
  • 1
  • 9
  • you shouldn't add comboboxitems (`ABC`) since you use ItemsSource – ASh Sep 30 '22 at 10:21
  • @ASh If I don't add ComboBoxItem, should I add these predefined value in the viewModelObj class? But they are unchanged values, would that be redundant? – BabyHai Sep 30 '22 at 10:27

1 Answers1

1

You can't both bind the ItemsSource to a source collection and add items to the ComboBox in the XAML markup. It's one way or the other - not both.

You source collection should contain the values that you want to display in the ComboBox:

public IEnumerable<string> viewModelSource { get; } = new string[] { "ABC", "DEF", "XYZ" };

Then gid rid of the ComboBoxItem elements from the XAML markup:

<ComboBox x:Name="materialCombo" ... ItemsSource="{Binding viewModelSource}" 
      SelectedItem="{Binding viewModelObj}" />

The viewModelObj should store the currently selected (string) value in the ComboBox:

public string viewModelObj { get; set; }
mm8
  • 163,881
  • 10
  • 57
  • 88
  • I have tried that. It does not work. – BabyHai Sep 30 '22 at 13:58
  • 1
    What doesn't work? The binding? Then you haven't set or implemented your `DataContext`correctly. Of course this works otherwise. It's like the first thing you learn in MVVM... – mm8 Sep 30 '22 at 13:59
  • I have tried to bind the ItemsSource to the string list and bind SelectedItem to the property of the class. Then I test the GUI, the value is not updated. – BabyHai Sep 30 '22 at 14:03
  • You must implement `INotifyPropertyChanged` and raise the `PropertyChanged` event for the `viewModelObj` property if you want any UI element bound to the property to be updated. But that's another story. – mm8 Sep 30 '22 at 14:06
  • I implement that later this afternoon. Now I can update the textbox and its corresponding property. But the combox still confuses me. You can check my update. Hope that I did right. – BabyHai Sep 30 '22 at 14:19
  • The XAML is still invalid. Read my answer again... – mm8 Sep 30 '22 at 14:24
  • I set the DataContext later correctly, now it works. Thank you. – BabyHai Oct 04 '22 at 09:43