简体   繁体   中英

DataGrid display is empty MVVM Wpf

The problem: the DataGrid display is empty, however I have infos, and my DataGrid received the information but still empty!

My XAML:

<DataGrid x:Name="dataGrid" Grid.Row="1" ItemsSource="{Binding ViewList}" 
          CanUserAddRows="False" AlternationCount="2"
          AlternatingRowBackground="Blue">
  <DataGrid.Columns>
    <DataGridTextColumn Header="View" Binding="{Binding id}"
                        Width="2*" IsReadOnly="True" />
    <DataGridTemplateColumn Header="Is Enabled" Width="Auto">
      <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <CheckBox IsChecked="{Binding isEnabled, Mode=TwoWay,
                        UpdateSourceTrigger=PropertyChanged}"/>
        </DataTemplate>
      </DataGridTemplateColumn.CellTemplate>
    </DataGridTemplateColumn>                
  </DataGrid.Columns>
</DataGrid>

My ViewModel:

public ConfigRoleModel()
{
    _viewList = new ObservableCollection<ViewList>(WCFclient.getListOfViews(1));
}

private ObservableCollection<ViewList> _viewList;
public ObservableCollection<ViewList> ViewList
{
    get { return _viewList; }
    set
    {
        _viewList = value;
        OnPropertyChanged("ViewList");
    }
}  

ViewList class:

public class ViewList
{
    public int id;    
    public string description;
    public string code;
}

This is the result: 在此输入图像描述

How can I fix it ?

By looking at your code:

  1. You should define public property in your ViewList class for binding to work.

  2. set Datacontext to your viewModel.

  3. No isEnabled property in your DataContext

Your ViewList Class should look like this:

public class ViewList 
{
    public int Id { get; set; }
    public bool IsEnabled { get; set; }
    ...
}

and your Xaml:

<DataGrid x:Name="dataGrid" Grid.Row="1"  ItemsSource="{Binding ViewList}" 
           CanUserAddRows="False" AlternationCount="2" AlternatingRowBackground="Blue" >
    <DataGrid.Columns>
        <DataGridTextColumn Header="View" Binding="{Binding Id}" Width="2*" IsReadOnly="True" />

        <DataGridTemplateColumn Header="Is Enabled" Width="Auto">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsEnabled , Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>                
    </DataGrid.Columns>
</DataGrid>

And in your view code behind or in your xaml itself:

  • Set your DataContext to your ViewModel

Fields are not valid targets for WPF bindings. You should use a property instead.

public class ViewList {
    public int Id { get; set; }
    public string Description { get; set; }
    public string Code { get; set; }
    public bool IsEnabled { get; set; }
}

Make sure that your View List class implements INotifyPropertyChanged

public class ViewList : INotifyPropertyChanged
{
    private int _id;
    public int id
    {
        get { return _id; }
        set
        {
            _id = value;
            OnPropertyChanged(new PropertyChangedEventArgs("id"));
        }
    }

    private string _description;
    public string description
    {
        get { return _description; }
        set
        {
            if((value as string) != null)
            {
                _description = value;
                OnPropertyChanged(new PropertyChangedEventArgs("description"));
            }
        }
    }

    private string _code;
    public string code
    {
        get { return _code; }
        set
        {
            _code = value;
            OnPropertyChanged(new PropertyChangedEventArgs("code"));
        }
    }

    private bool _isEnabled;
    public bool isEnabled
    {
        get { return _isEnabled; }
        set
        {
            _isEnabled = value;
            OnPropertyChanged(new PropertyChangedEventArgs("isEnabled"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }
}

Your ViewModel does not need to implement INotifyPropertyChanged if you are just wanting to display data from the ObservableCollection. Here is my ViewModel:

public class MainWindowVM
{
    private ObservableCollection<ViewList> _MyList;
    public ObservableCollection<ViewList> MyList
    {
        get { return _MyList; }
        set
        {
            if(value != null)
            {
                _MyList = value;
            }
        }
    }

    public MainWindowVM()
    {
        _MyList = new ObservableCollection<WpfDataGridTest.ViewList>();

        _MyList.Add(new WpfDataGridTest.ViewList() { id = 1, code = "C101", description = "test1", isEnabled = true });
        _MyList.Add(new WpfDataGridTest.ViewList() { id = 2, code = "C102", description = "test2", isEnabled = false });
        _MyList.Add(new WpfDataGridTest.ViewList() { id = 3, code = "C103", description = "test3", isEnabled = true });
    }
}

Here is my Window's XAML

<Window x:Class="WpfDataGridTest.MainWindow"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfDataGridTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{StaticResource MainWindowVM}">
    <Grid>
        <DataGrid x:Name="dataGrid" HorizontalAlignment="Left" Margin="33,34,0,0" VerticalAlignment="Top" Height="236" Width="444" 
                  CanUserAddRows="False" AlternationCount="2" AlternatingRowBackground="Blue"  AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True"
                  ItemsSource="{Binding MyList}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="View" Binding="{Binding id}" Width="2*" IsReadOnly="True" />

                <DataGridTemplateColumn Header="Is Enabled" Width="Auto">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding isEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>

    <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="44,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"
             Text="{Binding Path=CurrentItem.description, ElementName=dataGrid}"/>
</Window>

This example shows the 3 rows as expected for me using VS 2015. as you can see here:

WPFDataGridTest应用程序捕获 Note: I renamed your ViewList member of the ViewModel to MyList because I don't like having a member be the same name of a class as it can make things confusing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM