Reputation: 33
As seen in the picture i have a ComboBox which is showing me all the Events that i have in my Database. This could be a birthday party for example. The Listview is showing me the participants. This is all working perfect. But, when i add a new Event in the running application, using the textboxes nd the button "Toevoegen" Which translates to "Add" My Combobox is not showing the new event. When i restart the program it does show it.
I figured out that it has something to do with the property changed. But how do i use this when i add my items to an instance of eventmanager.events.Add(item)?
Xaml
<Window x:Class="Databinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Databinding"
mc:Ignorable="d"
Title="Events" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ComboBox x:Name="cbEvents1" ItemsSource="{Binding events, Mode=TwoWay}" SelectedItem="{Binding currentEvent}" SelectedValuePath="Content" Margin="10,10,31.667,381.667">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ListView Grid.Column="1" ItemsSource="{Binding participants}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding firstName}"/>
<GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding lastName}"/>
</GridView>
</ListView.View>
</ListView>
<Label Content="Nieuw evenement " HorizontalAlignment="Left" Margin="10,53,0,0" VerticalAlignment="Top"/>
<Label Content="Naam:" HorizontalAlignment="Left" Margin="44,80,0,0" VerticalAlignment="Top" RenderTransformOrigin="1.083,0.564"/>
<TextBox x:Name="tbNaamEv" HorizontalAlignment="Left" Height="23" Margin="93,79,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="272"/>
<Label x:Name="lblOmschrijving1" Content="Omschrijving:" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="TbOmschrijvingEV" HorizontalAlignment="Left" Height="23" Margin="93,119,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="272"/>
<Label Content="Opmerking:" HorizontalAlignment="Left" Margin="21,151,0,0" VerticalAlignment="Top"/>
<Label Content="Datum:" HorizontalAlignment="Left" Margin="46,186,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="tbOpmerkingEv" HorizontalAlignment="Left" Height="23" Margin="93,154,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="205"/>
<Button x:Name="btnAdd1" Content="Toevoegen" HorizontalAlignment="Left" Margin="207,234,0,0" VerticalAlignment="Top" Width="158" Height="24" Click="btnAdd_Click"/>
<DatePicker x:Name="DPevenement" HorizontalAlignment="Left" Margin="93,189,0,0" VerticalAlignment="Top" Width="205" FirstDayOfWeek="Monday" IsDropDownOpen="True"/>
<Label Content="Evenement informatie" HorizontalAlignment="Left" Margin="6,270,0,0" VerticalAlignment="Top"/>
<Label Content="Omschrijving:" HorizontalAlignment="Left" Margin="6,301,0,0" VerticalAlignment="Top"/>
<Label x:Name="lblOmschrijvingEv" Content="{Binding omschrijving}" HorizontalAlignment="Left" Margin="93,301,0,0" VerticalAlignment="Top" Width="294" Height="26"/>
<Label Content="Opmerking:" HorizontalAlignment="Left" Margin="16,344,0,0" VerticalAlignment="Top"/>
<Label x:Name="lblOpmerkingEv" Content="{Binding opmerking}" HorizontalAlignment="Left" Margin="93,344,0,0" VerticalAlignment="Top" Width="294" Height="26"/>
<Label Content="Datum:" HorizontalAlignment="Left" Margin="40,385,0,0" VerticalAlignment="Top"/>
<Label x:Name="lblDatumEv" Content="{Binding Datum}" HorizontalAlignment="Left" Margin="93,385,0,0" VerticalAlignment="Top" Width="294" Height="26"/>
</Grid>
</Window>
Eventmanager Class
public class EventManager : INotifyPropertyChanged
{
public List<Event> events { get; set; }
public List<People> peoples { get; set; }
//this is the current event that correspond to the selected event in your combobox
private Event _currentEvent;
public Event currentEvent
{
get
{
return _currentEvent;
}
set
{
if (_currentEvent != value)
{
_currentEvent = value;
//when you change the selected event, you have to update the list of participants
OnPropertyChanged("participants");
}
}
}
public List<People> participants
{
get
{
//Here is the code to retrieve the people that registered to the selected event
return peoples.Where(p => p.registeredEvents.Contains(currentEvent)).ToList<People>();
}
}
public EventManager()
{
events = new List<Event>();
peoples = new List<People>();
}
//The following lines are specific to WPF and DataBinding
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
People Class
public class People : INotifyPropertyChanged
{
public string firstName { get; set; }
public string lastName { get; set; }
public List<Event> registeredEvents { get; set; }
public People()
{
registeredEvents = new List<Event>();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public class Event : INotifyPropertyChanged
{
public string name { get; set; }
public string omschrijving { get; set; }
public string opmerking { get; set; }
public DateTime Datum { get; set; }
//The following lines are specific to WPF and DataBinding
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
This is how i add my events and participants:
EventManager eventManager = new EventManager();
DBConnect connect = new DBConnect();
public Event Selected;
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
connect.EvToevoegen(tbNaamEv.Text, TbOmschrijvingEV.Text, tbOpmerkingEv.Text, Convert.ToDateTime(DPevenement.SelectedDate));
Selected = new Event()
{
name = tbNaamEv.Text
};
eventManager.events.Add(Selected);
}
}
The new Event won't show in my ComboBox?
Upvotes: 0
Views: 157
Reputation: 111
Lists don't respond to the PropertyChanged
events like you expect because the List itself likely never changed. Its contents did.
For ItemsSource
to respond to a collection changing, that collection must implement the INotifyCollectionChanged
interface. C# provides us with a collection that already implements that interface, thankfully.
If you use ObservableCollection<T>
you can get this functionality immediately.
Try replacing:
public List<Event> events { get; set; }
With:
public ObservableCollection<Event> events { get; set; }
If you are unable to change the type of this collection for whatever reason, you are going to need to wrap the list somehow.
The most simple way to do this is by using the copy constructor exposed by observable collection:
new ObservableCollection<T>(IEnumerable<T>)
Upvotes: 1
Reputation: 16148
Well first of all your People class is implementing INotifyPropertyChanged but none of the properties are actually raising OnPropertyChanged (unless you're using a framework like Caliburn or something to implement it automatically).
To answer your question though, your registeredEvents property needs to implement INotifyCollectionChanged
e.g. be of type ObservableCollection<Event>
. This creates a few potential problems though when you're serializing to and from a database, because if your database layer returns a List, and you convert it to an ObservableCollection, then when you go to save it again the database will think the entire list has changed and re-serialize the whole thing back out again irrespective of whether or not anything has actually changed. Obviously this will result in a serious performance hit.
How you best resolve this will depend on other parts of your application. You may choose to keep your ObservableCollection separate, then compare it to the original list when the user is finished and update the original list all in one go. Many ORMs allow you to control the types of data structures they create, in which case you can make them create ObservableCollections for all lists, and this problem doesn't exist in the first place. Your view model layer may choose to keep both lists in memory and add/remove elements from both of them at runtime, once for the benefit of the database and the other for the view. Alternatively, if your lists are small, you could simply continue to use a List<Element>
, raise OnPropertyChanged("registeredEvents")
whenever you make any changes to the list and cop the performance hit of having all the list GUI elements re-create themselves.
Upvotes: 0