Reputation: 693
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 ?
Upvotes: 0
Views: 1032
Reputation: 413
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)
Upvotes: 1
Reputation: 693
I found a solution. I must say a very frustrating thing to learn before you come fammiliar with WPF and binding controls...
I followed numerious amount of articles in order to understand that in WPF you should use MVVM pattern in order to correctly bind your controls. However, there are so many different approaches doing this, so I ended up in something that is at least little understandable to me at this point:
1.) Create Model class. Here you define your DataTable columns and expose them as properties. This class needs to be inherited from INotifyPropertyChanged:
class Test_Model : INotifyPropertyChanged
{
private string col1;
private string col2;
public string Col1
{
get
{
return col1;
}
set
{
col1 = value;
OnPropertyChanged("Col1");
}
}
public string Col2
{
get
{
return col2;
}
set
{
col2 = value;
OnPropertyChanged("Col2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
2.) Create Viev_Model class.Here you create an IList (of Test_Model type) and fill It with DataTable, I used LINQ for that - that was also a challenge. Next, you again expose a property of IList type, in order to use that as your Datasource:
class Test_ViewModel
{
private IList<Test_Model> _comboData;
public Test_ViewModel()
{
_comboData = dt.AsEnumerable().
Select(row => new Test_Model
{
Col1 = row.Field<string>(0),
Col2 = row.Field<string>(1)
}).ToList();
}
public IList<Test_Model> ComboData
{
get { return _comboData; }
set { _comboData = value; }
}
}
3.) In your Window or Page assign DataContext to View_Model class. That is done in constructor, like this:
public partial class My_Page: Page
{
public My_Page()
{
InitializeComponent();
this.DataContext = new Test_ViewModel(); //assign ViewModel class
}
//...
}
4.) Bind combobox to View_Model class:
<ComboBox x:Name="Cmb_Test" ItemsSource="{Binding Path= ComboData}"
DisplayMemberPath="Col1" SelectedValuePath="Col1" SelectedIndex="0"/>
And then It worked, finally. Although I'm not happy with solution, so I have to figure out more simple way of doing proper binding. I ussually have many controls to bind & If I would do this for every DataTable I need, I would end up with tons of code in classes.
Upvotes: 0