I'm working on a WPF MVVM application and running into an issue. I'm familiar with WPF itself, however I've rarely used MVVM and I suspect I am doing something that MVVM doesn't support, however I don't know how else to accomplish what I am trying to do.
In the application, I have a user control called Agenda. It consist several controls including a text box, a button to add a new agenda item, and a list box with a custom template. The template includes an expander where the header is the agenda item title, up/down arrows to reorder items, and a button to delete the item. The expander content contains a toolbar and a rich text box. In the agenda UC I have a dependency property called ItemsSource
which is an IEnumerable<AgendaItem>
.
Now, I have a view called Appointment, its associated VM (AppointmentViewModel), and its model (AppointmentModel). In the model, there is a field called AgendaItems which is an ObservableCollection<AgendaItem>
. The agenda UC is used within the appointment view and the UC's ItemsSource
is bound to the Model.AgendaItems
(the observable collection).
The problem I'm having is when I try to handle the buttons to reorder the agenda items in the UC. As an example, for the button to move an agenda item up the list, this is the code in the UC:
var tb = sender as Button;
var tag = tb.Tag as AgendaItem;
var lst = ItemsSource.ToList();
var index = lst.IndexOf(tag);
if(index > 0)
{
lst.RemoveAt(index);
lst.Insert(index - 1, tag);
ItemsSource = lst;
}
The tag of the up arrow is bound to the specific agenda item in the list so I know which item is being moved. The problem comes after I update the ItemsSource
property doing ItemsSource = lst
. After that line executes, the AgendaItems
ObservableCollection in the VM is null. The binding mode is set to TwoWay
.
Since the the appointment UC is used in various windows in the application, it made sense to me that the reordering of agenda items should be taken care of my the UC instead of duplicating code in every window which makes use of the UC. But updating the ItemsSource
property in the UC results in the collection in the VM being null.
For reference, the ItemsSource
property in the UC is defined as:
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable<AgendaItem>), typeof(Agenda), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));
There is the regular .NET property:
public IEnumerable<AgendaItem> ItemsSource
{
get => (IEnumerable<AgendaItem>)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
And the OnItemsSourceChanged
method is:
private static void OnItemsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (obj is Agenda control)
{
if (e.OldValue is INotifyCollectionChanged oldValueINotifyCollectionChanged)
{
oldValueINotifyCollectionChanged.CollectionChanged -= control.ItemsSource_CollectionChanged;
}
if (e.NewValue is INotifyCollectionChanged newValueINotifyCollectionChanged)
{
newValueINotifyCollectionChanged.CollectionChanged += control.ItemsSource_CollectionChanged;
}
}
}
Any help/guidance on how I can reorder the ItemsSource
collection in the UC without breaking the VM would be greatly appreciated. Thank you in advance.
By changing the data type of ItemsSource
from IEnumerable<AgendaItem>
to ObservableCollection<AgendaItem>
resolved the issue. Thank you to everyone who responded. It is much appreciated.