Home > Back-end >  I cant add new data to DataGrid
I cant add new data to DataGrid

Time:12-31

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>
  • Related