I'm currently facing an issue in my C# WPF application, that is seemingly simple to solve. But even after reading several Stackoverflow posts, tutorials on the web i still cannot solve the problem.
I have a DataGrid, that i'm trying to bind to a ObservableCollection. Furthermore, i am using the MVVM pattern (at least i'm trying) together with PRISM.
My Problem is, that the DataGrid does not get populated after i add a new Rule to the ObservableCollection. When i'm debugging the application i can see, that the collection has items contained. As you can see from the code i am using RaisePropertyChanged from the Bindablebase to fire the PropertyChangedEvent. I have also bound the DataGrid's ItemSource to RuleList.
Can anybody see what i'm doing wrong?
Thanks in Advance,
Michael
Here is my RuleModel.cs:
namespace MyApp.GenericViews.Model
{
public class RuleModel
{
public bool IsEnabled { get; set; }
public string RuleName { get; set; }
public string Source { get; set; }
public string Target { get; set; }
public string ModuleName { get; set; }
public string ElementName { get; set; }
public RuleModel()
{
}
}
}
Here is my View.xaml:
<UserControl
x:Class="MyApp.GenericViews.View.RulesView"
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:local="clr-namespace:MyApp.GenericViews.View"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:MyApp.GenericViews.ViewModel"
d:DataContext="{d:DesignInstance d:Type=vm:RulesViewModel}"
d:DesignHeight="600"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Content="{Binding Title}" />
<!--<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button Content="Add" Style="{StaticResource DefaultDialogButton}" />
<Button Content="Remove" Style="{StaticResource DefaultDialogButton}" />
</StackPanel>-->
<DataGrid
Name="RulesDataGrid"
Grid.Row="1"
Margin="5"
AutoGenerateColumns="False"
ItemsSource="{Binding Path=RuleList, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<DataGrid.Columns>
<!--<DataGridCheckBoxColumn Width="40" Binding="{Binding Path=IsEnabled}" />-->
<DataGridTextColumn
Width="100"
Binding="{Binding Path=RuleName, UpdateSourceTrigger=PropertyChanged}"
Header="Name" />
<DataGridTextColumn
Width="100"
Binding="{Binding ModuleName}"
Header="Module" />
<!--<DataGridComboBoxColumn
Width="100"
Header="Element"
ItemsSource="{Binding ModuleList}"
SelectedItemBinding="{Binding Path=ElementName}" />-->
<DataGridTextColumn
Width="50*"
Binding="{Binding Source}"
Header="Source" />
<DataGridTextColumn
Width="50*"
Binding="{Binding Target}"
Header="Target" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
Here is my ViewModel.cs.
namespace MyApp.GenericViews.ViewModel
{
public class RulesViewModel : BindableBase, INavigationAware, IViewModel
{
private XmlDatabase _xmlDatabase;
private readonly IUnityContainer _container;
private readonly IEventAggregator _eventAggregator;
public IMyAppView View { get; set; }
public List<string> ModuleList { get; set; }
private string _title;
public string Title
{
get { return _title; }
set
{
if (_title != value)
{
_title = value;
SetProperty(ref _title, value);
RaisePropertyChanged(nameof(Title));
}
}
}
private Rule _selectedRule;
public Rule SelectedRule
{
get { return _selectedRule; }
set
{
if (_selectedRule != value)
{
SetProperty(ref _selectedRule, value);
RaisePropertyChanged(nameof(SelectedRule));
}
}
}
private ObservableCollection<RuleModel> _RuleList;
public ObservableCollection<RuleModel> RuleList
{
get { return _RuleList; }
set
{
if (_RuleList != value)
{
SetProperty(ref _RuleList, value, nameof(RuleList));
//RaisePropertyChanged(nameof(RuleList));
//OnPropertyChanged(nameof(RuleList));
}
}
}
public RulesViewModel(IRuleView view, IUnityContainer c, IEventAggregator evt)
{
View = view;
View.ViewModel = this;
_container = c;
_eventAggregator = evt;
_eventAggregator.GetEvent<RuleCommand>().Subscribe(DoProcessRuleCommand);
}
private void DoProcessRuleCommand(RuleCommandType commandType)
{
switch (commandType)
{
case RuleCommandType.AddRule:
if (RuleList.IsNullOrEmpty())
{
RuleList = new ObservableCollection<RuleModel>();
}
var newRule = new RuleModel()
{
RuleName = "new rule",
};
RuleList.Add(newRule);
RaisePropertyChanged(nameof(RuleList));
//OnPropertyChanged(nameof(RuleList));
break;
case RuleCommandType.DeleteRule:
if (RuleList.IsNeitherNullNorEmpty())
{
//RuleList.Remove(Selected)
}
break;
default:
break;
}
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
_xmlDatabase = _container?.Resolve<XmlDatabase>();
if (_xmlDatabase != null)
{
RuleList = new ObservableCollection<RuleModel>(_xmlDatabase.Rules.Select(r => RuleModel.FromSerializable(r)));
}
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
}
}
Ok, after Ivoros gave me the hint in the comments to review the UserControl's DataContext i looked into the code behind of my View.xaml.cs.
It turnes out that i forgot to return the DataContext on the public View property
before:
public IMiCasaViewModel ViewModel { get; set; }
after:
public IMiCasaViewModel ViewModel
{
get
{
return (INormalizationViewModel)DataContext;
}
set
{
DataContext = value;
}
}
Thank You!!