Reputation: 105
I am working in WPF and have a view model ModifiedReasonViewModel
that is my DataContext
for an XAML view. The ComboBox
doesn't display any of the 4 items that I can see in the data context when I'm debugging. I think it definitely has to do with the fact that I'm pulling the reason labels asynchronously. Any ideas on how to fix this?
When I test this code with just a list of test strings initialized in the constructor, it works as intended.
This is the RadComboBox
what I'm currently working with in the XAML:
d:DataContext="{d:DesignInstance Type=vm:ATMModifiedReasonViewModel, IsDesignTimeCreatable=True}">
<telerik:RadComboBox Name="ReasonCmbo"
ItemsSource="{Binding ReasonLabels}"
DisplayMemberPath="Name"
IsEditable="False"
Margin="2"
Grid.Column="1"
Grid.Row="1"
Grid.ColumnSpan="2">
</telerik:RadComboBox>
And this is the ViewModel code I'm working with:
public class ATMModifiedReasonViewModel : INotifyPropertyChanged
{
private List<LabelFileModel> _reasonLabels;
public List<LabelFileModel> ReasonLabels { get { return _reasonLabels; } set { _reasonLabels = value; } }
public ATMModifiedReasonViewModel(){
GetReasonLabels();
}
public void GetReasonLabels()
{
LabelFileProvider lfProvider = new LabelFileProvider();
LabelFileModelFilter filter = new LabelFileModelFilter() {LabelDefinition = "ModifiedReason"};
lfProvider.GetFiltered(filter,10, getResult => GetReasonLabelsCallback(getResult));
}
private void GetReasonLabelsCallback(Func<IEnumerable<LabelFileModel>> getResult)
{
try
{
_reasonLabels = (List<LabelFileModel>) getResult();
}
catch (Exception ex)
{
Messenger.Default.Send(new UnhandledExceptionMessage(this, ex));
}
}
}
Thank you so much in advance for the help!
Upvotes: 0
Views: 701
Reputation: 169320
Set the property in your callback and raise the PropertyChanged
event from the setter of it, or raise it the PropertyChanged
event in the callback after you have set the backing field:
private void GetReasonLabelsCallback(Func<IEnumerable<LabelFileModel>> getResult)
{
try
{
_reasonLabels = (List<LabelFileModel>)getResult();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ReasonLabels )));
}
catch (Exception ex)
{
Messenger.Default.Send(new UnhandledExceptionMessage(this, ex));
}
}
Raising the event is required for the framework to know when to refresh the UI.
Upvotes: 0
Reputation: 22099
If you reassign the ReasonLabels
collection at runtime, you have to implement INotifyPropertyChanged
and raise the PropertyChanged
event, otherwise the bindings will not notice the change.
Similarly, if you modify the collection itself, e.g. adding or removing items, the collection needs to implement INotifyCollectionChanged
, which provides events to trigger an update in the user interface. The List<T>
type does not implement this interface, use ObservableCollection<T>
instead. It automatically raises the CollectionChanged
event, if the collection is modified and therefore triggers an update of bindings.
public class ATMModifiedReasonViewModel : INotifyPropertyChanged
{
private ObservableCollection<LabelFileModel> _reasonLabels;
public ObservableCollection<LabelFileModel> ReasonLabels
{
get => _reasonLabels;
set
{
if (_reasonLabels = value)
return;
_reasonLabels = value;
OnPropertyChanged();
}
}
// ...your code here.
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
You also have to assign the ReasonLabels
property instead of the backing field _reasonLabels
, otherwise the property setter that triggers the PropertyChanged
event will not be executed.
private void GetReasonLabelsCallback(Func<IEnumerable<LabelFileModel>> getResult)
{
try
{
ReasonLabels = (List<LabelFileModel>) getResult();
}
catch (Exception ex)
{
Messenger.Default.Send(new UnhandledExceptionMessage(this, ex));
}
}
Upvotes: 2