Search code examples
c#wpfcomboboxitemsource

WPF Combobox - changed Datasource results in empty ItemsSource


I'm doing a simple binding of a Combobox in Page:

XAML:

 <ComboBox x:Name="Cmb_test"  Grid.Column="2" Grid.Row="2" HorizontalAlignment="Left"  ItemsSource="{Binding}" />

CODE behind:

private void Page_Loaded(object sender, RoutedEventArgs e)
{
     //Binding of label works fine everytime
     My_label.Content = dt.Rows[0]["Column1"];

     Cmb_test.DataContext = dt.DefaultView;
     Cmb_test.SelectedValuePath = dt.Columns[3].ToString();
     Cmb_test.DisplayMemberPath = dt.Columns[4].ToString();

     //Just a check to see whether DataTable really has changed
     Console.WriteLine(dt.Rows.Count.ToString());
 }

But whenever my DataTable "dt" get's changed, my Combobox doesn't display Items anymore. I know there were a lot of questions allready asked regarding this issue, but all I could found were problems associating with refreshing during run-time. In my case I close a Page and re-open It when DataTable is changed, but result is empty Combobox.

Code for closing my Page, for addition:

CODE in same Page as Combobox:

private void BtnClose_Click(object sender, RoutedEventArgs e)
{
      Cmb_test.ItemsSource = null;
      Cmb_test.DataContext = null;

      var main_window = Application.Current.MainWindow;
      var frame = (main_window as MainWindow).My_Frame;
      frame.Content = null;

}

Code in MainWindow:

private void My_Frame_Navigated(object sender, NavigationEventArgs e)
{
     if (My_Frame.Content == null)
     {
        My_Frame.RemoveBackEntry();
     }
}

EDIT - another attempt:

XAML:

  <Page.Resources>
        <CollectionViewSource x:Key="My_source"/>
    </Page.Resources>

  <ComboBox x:Name="Cmb_test" ItemsSource="{Binding Source={StaticResource My_source}}" DisplayMemberPath="Column1"/>

CODE behind:

 private void Page_Loaded(object sender, RoutedEventArgs e)
        {

            var combo_datasource = new CollectionViewSource();
            combo_datasource = (CollectionViewSource)this.FindResource("seznamVrstEvidenc");
            combo_datasource.Source = Tabele.dt_Sifrant.DefaultView;

        }

What is going on here, how can I fix combobox to show It's Items everytime ?


Solution

  • You're not binding your ComboBox to anything

    <ComboBox x:Name="Cmb_test" [...] ItemsSource="{Binding}" />
    

    You should have some sort of collection

    <ComboBox x:Name="Cmb_test" [...] ItemsSource="{Binding MyList}" />
    

    Looking at the rest of your code it seems like you're "manually binding" the ComboBox to a DataTable. You can then create a Binding programmatically that links the ComboBox ItemsSource to the DataTable DefaultView.

    There is a problem though, if what you mean with "DataTable is changed" is something like

    dt = new DataTable();
    

    or

    dt = Db.GetTable();
    

    you will likely fall in the same problem again because the binding is done between two instances, so when a new dt is created you have to rebind it to the ComboBox.

    Another way of solving the problem could be to set the ComboBox ItemsSource every time you have a new DataTable.

    I hope I was helpful.

    --------- UPDATE --------

    Following my comment I would go with implementing INotifyPropertyChanged on the class that stores the DataTable dt.

    public class ThatParticulareClass : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {  
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    
        // [...] all the other stuff
    
        public void MethodThatUpdateDataTable()
        {
            // Update DataTable
            NotifyPropertyChanged(nameof(dt));
        }
    }
    

    That should work. If your changes on the DataTable object came only from the user (from the view) than you should register at the control which expose the DataTable an the ending edit event (something like DataGrid.RowEditEnding). At that point you call NotifyPropertyChanged(nameof(dt)); (Be sure that this call is from the same class that contains the DataTable dt)

    Implementation