Reputation: 99
I have a really simple class which I am populating with a LINQ query - all works well;
public class CatSummary : INotifyPropertyChanged
{
private string _catName;
public string CatName
{
get { return _catName; }
set { if (_catName != value) { _catName = value; NotifyPropertyChanged("CatName"); } }
}
private decimal _catAmount;
public decimal CatAmount
{
get { return _catAmount; }
set { if (_catAmount != value) { _catAmount = value; NotifyPropertyChanged("CatAmount"); } }
}
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify Silverlight that a property has changed.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
//MessageBox.Show("NotifyPropertyChanged: " + propertyName);
}
}
}
LINQ bit;
var myOC = new ObservableCollection<CatSummary>();
var initialQuery = BoughtItemDB.BoughtItems
.GroupBy(item => item.ItemCategory)
.Select(x => new CatSummary
{
CatName = x.Key,
CatAmount = x.Sum(amt => amt.ItemAmount)
});
foreach (var item in initialQuery) myOC.Add(item);
I am trying to bind my WPF control to my custom class in the XAML below;
<ListBox x:Name="boughtItemsListBox" ItemsSource="{Binding CatSummary}" Margin="5,27,-35,100" Width="450" Height="371" Grid.ColumnSpan="2" Grid.RowSpan="2">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Width="440">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding CatName, StringFormat=g}" TextWrapping="Wrap" FontSize="{StaticResource PhoneFontSizeSmall}" VerticalAlignment="Top"/>
<TextBlock Grid.Column="1" Text="{Binding CatAmount, StringFormat=\{0:C\}}" Margin="1" FontSize="{StaticResource PhoneFontSizeSmall}" VerticalAlignment="Top"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This give me the following error; BindingExpression path error: 'CatSummary' property not found on 'MyApp.SpendAnalysis+CatSummary'
According to what I have read I think I need to make the properties of my class into ObservableCollection properties but this seems to break my LINQ query. I've tried all sorts for this, nor can I find any tutorials to help me understand how this should work. Any advice or pointers gladly received.
Upvotes: 0
Views: 1325
Reputation: 17083
Assuming you have a MyOC property
private ObservableCollection<CatSummary> _myOC = new ObservableCollection<CatSummary>();
public ObservableCollection<CatSummary> MyOC
{
get { return _myOC ; }
set { if (_myOC != value) { _myOC = value; NotifyPropertyChanged("MyOC"); } }
}
bind your ListBox
to the ObservableCollection
, then each ListBoxItem
will have a DataContext
of type CatSummary
.
<ListBox x:Name="boughtItemsListBox" ItemsSource="{Binding MyOc}" ...
In your LINQ query code
var initialQuery = BoughtItemDB.BoughtItems
.GroupBy(item => item.ItemCategory)
.Select(x => new CatSummary
{
CatName = x.Key,
CatAmount = x.Sum(amt => amt.ItemAmount)
});
reassign MyOC
MyOC = new ObservableCollection<CatSummary>(initialQuery.ToList());
or use the existing MyOC collection.
MyOC.Clear();
foreach (var item in initialQuery) MyOC.Add(item);
Upvotes: 1
Reputation: 56556
With your XAML bindings, the DataContext
of boughtItemsListBox
should be an item with a property named CatSummary
of type IEnumerable<CatSummary>
(or ObservableCollection<CatSummary>
, or other implementer of INotifyCollectionChanged
, if you want to be able to change the items that make up the list in real time). I'm guessing this is where you're going wrong.
E.g. if you actually have something more like boughtItemsListBox.DataContext = myOC;
, then it's looking for myOC.CatSummary
and not finding anything; what you need to do is either change the XAML to ItemsSource="{Binding}"
or change your code to boughtItemsListBox.ItemsSource = myOC;
(and remove the now-useless ItemsSource
setting in the XAML).
Upvotes: 2