I have been searching issues like this and making a lot of changes in my code but I can't solve it.
I have created a DataGrid:
<DataGrid Grid.Row="1" ItemsSource="{Binding VarDt}" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ID" Binding="{Binding Id}"/>
</DataGrid.Columns>
</DataGrid>
The list of the class that Im using is in the Main model.
private List<ObjectVariable> _varDt;
public List<ObjectVariable> VarDt
{
get { return _varDt; }
set
{
_varDt = value;
OnPropertyChanged("VarDt");
}
}
When I add the data for the first time it works and I can see the values in my DataGrid:
public MainViewModel()
{
VarDt = new List<ObjectVariable>()
{
new ObjectVariable { Id="9846849", Name="Val1" },
new ObjectVariable { Id="fregreg", Name="Val2" },
new ObjectVariable { Id="cd6s8s6", Name="Val3" }
}; [...]
But when I add new items when i execute a command (when i tree item is double clicked), the DataGrid doen's update. (code where I add the new item that it doens't work):
private ICommand _selectItemCommand;
public ICommand selectItemCommand
{
get
{
return _selectItemCommand ?? (_selectItemCommand = new RelayCommand(param => this.LoadContent(param)));
}
}
private void LoadContent(object selectedMenuItem)
{
// NEW ITEM THAT IS NOT ADDED WHY???
VarDt.Add(new ObjectVariable { Id = "cw61851cw", Name = "ValPost" });
}
I dont know if I am not raising the PropertyChanged event correctly and how I can do it.
Someone can tell me how can I add data correctly to my DataGrid.
Thanks!
Edit 1: Still not working with observable collection
Declaration:
private ObservableCollection<ObjectVariable> _varDt;
public ObservableCollection<ObjectVariable> VarDt
{
get { return _varDt; }
set
{
_varDt = value;
OnPropertyChanged("VarDt");
}
}
Public MainViewModel():
VarDt = new ObservableCollection<ObjectVariable>()
{
new ObjectVariable { Id="9846849", Name="ValuesAtStart1" },
new ObjectVariable { Id="fregreg", Name="ValuesAtStart2" },
new ObjectVariable { Id="cd6s8s6", Name="ValuesAtStart3" }
};
Command:
private void LoadContent(object selectedMenuItem)
{
// NEW ITEM THAT IS NOT ADDED WHY???
VarDt.Add(new ObjectVariable { Id = "cw61851cw", Name = "ValueInsideCommand" });
}
Result (data from command not added):
Value inside command not added
Edit 2: Problem found but I dont have the solution
The DataGrid where I have the problem is inside another View that I manage with another class and a ContentControl:
Actually I have:
- MainViewModel and the MainView.
- VariablesViewModel and VariablesView that i put inside the ContentControl. The VariablesViewModel is empty, I only use it to show the VariablesView.
When I execute a command, I show the VariablesView in the ContentControl:
private void LoadContent(object selectedMenuItem)
{
TreeItemModel ItemSelected = (TreeItemModel)selectedMenuItem;
if (ItemSelected.Name == "Object variables")
{
// Current view is VariablesView
CurrentView = VariableVM;
// NEW ITEM THAT IS NOT ADDED WHY???
VarDt.Add(new ObjectVariable { Id = "cw61851cw", Name = "ValueInsideCommand" });
}
else CurrentView = "";
}
I realized that the DataGrid inside the VariablesView that I show in the ContentControl doesn't update the values, but if I put the same DataGrid in the Main View, the values are updated.
Maybe the problem is that "VarDt" is in the MainViewModel, not in VariablesViewModel, but I can show some data, (only the new values are not showed)
Test code:
[...]
<ContentControl Grid.Column="1"
Margin="10"
Content="{Binding CurrentView}"/>
<DataGrid Grid.Row="3" Grid.Column="2" ItemsSource="{Binding VarDt}" AutoGenerateColumns="True" />
[...]
Result of test Code: DataBinding result using ContentControl os DataGrid in MainView
Edit 3: Full context
Variables view:
<UserControl x:Class="AOE.MVVM.View.VariablesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodel="clr-namespace:AOE.MVVM.ViewModel"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:AOE.MVVM.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<!--Asignación del archivo .cs a esta view-->
<UserControl.DataContext>
<viewmodel:MainViewModel/>
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions >
<RowDefinition Height="30*" MaxHeight="70"/>
<RowDefinition Height="100*"/>
<RowDefinition Height="10*" MaxHeight="30"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Image Source="/Media/Variables.png"
Height="50"
Width="50"
HorizontalAlignment="Left"/>
<TextBlock Text="Variables"
FontFamily="Verdana"
Foreground="#007BC0"/>
</StackPanel>
<DataGrid Grid.Row="1" ItemsSource="{Binding VarDt}" AutoGenerateColumns="True" >
</DataGrid>
</Grid>
VariablesViewModel: Empty class.
AppXaml:
<Application x:Class="AOE.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AOE"
xmlns:viewModel="clr-namespace:AOE.MVVM.ViewModel"
xmlns:view="clr-namespace:AOE.MVVM.View"
StartupUri="MainWindow.xaml">
<Application.Resources>
<DataTemplate DataType="{x:Type viewModel:VariablesViewModel}">
<view:VariablesView/>
</DataTemplate>
</Application.Resources>
MainViewModel:
namespace AOE.MVVM.ViewModel
{
class MainViewModel : ObservableObject
{
public ObservableCollection<ObjectVariable> VarDt { get; set; }
//public TreeItemModel ItemSelected { get; set; }
private ICommand _selectItemCommand;
public ICommand selectItemCommand
{
get
{
return _selectItemCommand ?? (_selectItemCommand = new RelayCommand(param => this.LoadContent(param)));
}
}
private void LoadContent(object selectedMenuItem)
{
// Current view is VariablesView
CurrentView = VariableVM;
// NEW ITEM THAT IS NOT ADDED WHY???
VarDt.Add(new ObjectVariable { Id = "cw61851cw", Name = "ValueInsideCommand" });
}
public VariablesViewModel VariableVM { get; set; }
private object _currentView;
public object CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
OnPropertyChanged("CurrentView");
}
}
public MainViewModel()
{
MainTree.Add(MainObject);
VarDt = new ObservableCollection<ObjectVariable>()
{
new ObjectVariable { Id="9846849", Name="ValuesAtStart1" },
new ObjectVariable { Id="fregreg", Name="ValuesAtStart2" },
new ObjectVariable { Id="cd6s8s6", Name="ValuesAtStart3" }
};
VariableVM = new VariablesViewModel();
}
}
}
CodePudding user response:
VariablesView
defines MainViewModel
as its DataContext
explicitly in XAML. That's why the DataGrid
shows initial values: the values from the MainViewModel
constructor. Since this is a new instance, changing the values of one instance does not change the values of the second instance.
Two simple solutions to fix this issue.
One solution can be to bind the DataContext
of the VariablesView
to the original MainViewModel
instance.
You can define a RelativeSource
to lookup the parent ContentControl
and uses its DataContext
as source for the DataContext
binding:
VariablesView.xaml
<UserControl DataContext="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=DataContext}">
...
</UserControl>
The second and recommended solution is to use the natural DataContext
, that is inherited from the DataTemplate
.
The consequence is that VariablesViewModel
can't be empty. If MainViewModel
and VariablesViewModel
share data like the VarDt
property, then don't duplicate those properties. Rather bind the controls that depend on this shared properties explicitly to the DataContext
of the ContentControl
(MainViewModel). Other non-shared data that relates to VariablesView
must be moved to the VariablesViewModel
.
The following example assumes that VariablesView
is not a reused control. Not, if reusability does matter, all internal bindings must reference the inherited DataContext
. This means Binding.RelativeSource
to lookup a source outside the UserControl must be avoided.
VariablesView.xaml
<!-- DataContext is inherited from the DataTemplate and is the VariablesViewModel -->
<UserControl>
<!-- Bind explicitly to the shared data located in MainViewModel -->
<DataGrid ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=DataContext}" />
</UserControl>