Reputation: 69
I'm building a basic WPF application using MVVM. I'm trying to get data about different power plants to display on a Datagrid. The program builds fine and displays the grid lines, but no data. I've seen lots of of similar questions and tried several things, but nothing seems to work. I'm wondering if the problem is just an easy thing I don't know to look for.
View:
public class Plant : INotifyPropertyChanged
{
#region Properties
private int plantID;
public int PlantID
{
get { return plantID; }
set
{
plantID = value;
RaisePropertyChanged("PlantID");
}
}
//...etc for all properties//
#endregion
void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
ViewModel:
public class MainViewModel : ViewModelBase, IPlantViewModel
{
private ObservableCollection<Plant> _plants = new ObservableCollection<Plant>();
private ICommand _loadCommand;
public MainViewModel()
{
_plants = GetPlants();
_plants.Add(new Plant (){PlantID=1, Name="Orange Plant", Address="1111 Orange Road", PlantPhone="(314)456 7489",PlantFax="(593)202 6948", Contact="John Smith"});
_plants.Add(new Plant() { PlantID = 2, Name = "Blue Plant", Address = "2222 Blue Lane", PlantPhone = "6368967483", PlantFax = "783279948", Contact = "Jane Doe" });
}
public ObservableCollection<Plant> Plants
{
get { return _plants; }
}
public ObservableCollection<Plant> GetPlants()
{
if (_plants == null || _plants.Count == 0)
_loadCommand.Execute(_plants);
return _plants;
}
}
View:
<UserControl
x:Class="Directory.MVVM.View.DirectoryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
xmlns:local="clr-namespace:Directory.ViewModel"
Height="481" Width="708">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="21*"/>
<ColumnDefinition Width="79*"/>
</Grid.ColumnDefinitions>
<DataGrid
ItemsSource="{Binding Source=Plants}"
Name="PlantGrid"
HorizontalAlignment="Left"
Margin="82,54,0,0"
VerticalAlignment="Top"
Height="147" Width="515"
AutoGenerateColumns="False" Grid.ColumnSpan="2">
<DataGrid.DataContext>
<local:MainViewModel />
</DataGrid.DataContext>
<DataGrid.Columns>
<DataGridTextColumn Header="Plant ID" Width="89" Binding="{Binding Path=PlantID,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<DataGridTextColumn Header="Name" Width="140" Binding="{Binding Path=Name,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay }" />
<DataGridTextColumn Header="Address" Width="90" Binding="{Binding Path=Address, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
<DataGridTextColumn Header="Phone" Width="90" Binding="{Binding Path=PlantPhone, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<DataGridTextColumn Header="Fax" Width="60" Binding="{Binding Path=PlantFax,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
<DataGridCheckBoxColumn Header="Contact" Width="58" Binding="{Binding Path=Contact, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</DataGrid.Columns>
</DataGrid>
Code Behind for the view(Not sure if I should have more in here):
public partial class DirectoryView : UserControl
public DirectoryView()
{
InitializeComponent();
}
Also, I'm using this as a reference:
http://wpfgrid.blogspot.com/2014/02/simple-observablecollection-wpf-mvvm.html
Upvotes: 4
Views: 3540
Reputation: 22435
if you set the DataContext like you did, your datagrid gets a new instance of your MainViewmodel every time the UserControl is loaded new.
<DataGrid.DataContext>
<local:MainViewModel />
</DataGrid.DataContext>
so you have to change your itemssource first to
ItemsSource="{Binding Path=Plants}"
now all you have to check is how you "fill" your collection. if you do NOT use Add, Clear and Remove for alter your collection then you have to raise OnPropertyChanged() so WPF notice that there are changes.
public ObservableCollection<Plant> Plants
{
get
{
return _plants;
}
set
{
_plants = value;
OnPropertyChanged();
}
}
Upvotes: 1
Reputation: 634
Here's how I do it:
Window Constructor instantiates the view model (here I have it as a property but the instantiation can also be inside the constructor) and sets the DataContext to the ViewModel:
public partial class WinFilesTransmitted : Window
{
static FTViewModel w = new FTViewModel();
public WinFilesTransmitted()
{
InitializeComponent();
DataContext = w;
}
}
The DataGrid xaml then does this:
<DataGrid AutoGenerateColumns="False" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch"
ItemsSource="{Binding DataContext.oFTrn, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding UID}" Header="xID" Width="40"/>
<DataGridTextColumn Binding="{Binding TransID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="TransID" Width="40"/>
<DataGridTextColumn Binding="{Binding DocID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="DocID" Width="40"/>
<DataGridTextColumn Binding="{Binding TransmittalName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="325">
So the ItemsSource of the datagrid is set to my observablecollection, and the columns are bound to the properties directly.
Upvotes: 0
Reputation: 5255
Try changing your itemsource binding in your datagrid you have source not path. From
ItemsSource="{Binding Source=Plants}"
To
ItemsSource="{Binding Path=Plants}"
or
ItemsSource="{Binding Plants}"
Changing your binding will fix the issue where your data is not showing in the grid at least for the two plants with id's 1 and 2 which you are adding in your constructor of you mainviewmodel. You also have a call to GetPlants in your constructor which loads additional plants by calling execute on a command. We cannot see how you are adding the plants to the observablecollection. You may want to take a look at how you are adding these plants to the observablecollection in getplants. If commenting out
_plants = GetPlants();
in
MainViewModel
Causes you to see two plants you also have an issue in how you are adding items in the command execute method.
Upvotes: 2