How do I bind the properties of a grid of child objects within a grid of parent objects? I wish to display the components of a product within a grid of products, but I get this error:
BindingExpression path error: 'Product' property not found on 'Orders.Product'. BindingExpression: Path='Product.ComponentDescription' DataItem='Orders.Product'; target element is 'Windows.UI.Xaml.Controls.TextBox' (Name='null'); target property is 'Text' (type 'String')How do I display a list of components for each product by nesting a Components grid within a Products grid?
The Models and ViewModel look like this
namespace Orders
{
public class Order
{
public List<Product> Products { get; set; }
}
public class Product
{
public string ProductCode { get; set; }
public string ProductDescription { get; set; }
public List<Component> Components { get; set; }
public override string ToString()
{
return this.ProductCode;
}
}
public class Component
{
public string ComponentCode { get; set; }
public string ComponentDescription { get; set; }
public override string ToString()
{
return this.ComponentCode;
}
}
public class OrderPageViewModel
{
public ObservableCollection<Product> Products { get; set; } = new ObservableCollection<Product>();
public OrderPageViewModel()
{
List<Component> componentList = new List<Component>()
{
new Component { ComponentCode="C1", ComponentDescription="Component One"},
new Component { ComponentCode="C2", ComponentDescription="Component Two"},
new Component { ComponentCode="C3", ComponentDescription="Component Three"}
};
Products = new ObservableCollection<Product>()
{
new Product {ProductCode="P1", ProductDescription="Product One", Components=componentList },
new Product {ProductCode="P2", ProductDescription="Product Two", Components=componentList },
new Product {ProductCode="P3", ProductDescription="Product Three", Components=componentList }
};
}
}
}
EDIT 1: The Xaml looks like this
<Page
x:Class="Orders.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Orders"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.DataContext>
<local:OrderPageViewModel x:Name="OrderPageViewModel" />
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListView
Name="ProductsList"
ItemsSource="{Binding Products}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Product">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding ProductCode}"></TextBox>
<TextBox Text="{Binding ProductDescription}"></TextBox>
</StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListView
Name="ComponentsList"
ItemsSource="{Binding Products.Components}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Component">
<StackPanel>
<TextBox Text="{Binding Product.ComponentCode}"></TextBox>
<TextBox Text="{Binding Product.ComponentDescription}"></TextBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
If I remove the grid of components, the products display correctly. How do I correctly bind the properties of components?
To display list you need to use ListView or any other ItemsControl. Here is the code snippet for the same
<ListView
Name="ComponentsList"
ItemsSource="{Binding Components}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Component">
<StackPanel>
<TextBox Text="{Binding ComponentCode}"></TextBox>
<TextBox Text="{Binding ComponentDescription}"></TextBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Related
I have had a lot of help so far with creating the correct formatting for an ItemsControl panel and appreciate this communities help so far with helping me troubleshoot coding issues.
Im currently at a rather small hurdle where im trying to figure out how to create multiple boxes within the same ItemsControl. Currently the overall view looks like this:
Im a little stumped and would just like a little guidance really as to where to put the other XAML lines.
I need it to look like this:
Here is my code currently (its all nested within a Frame):
<ItemsControl ItemsSource="{StaticResource userDataCollection}" Margin="40,40,40,725" Width="Auto" Height="310">
<!-- Changing Orientation of VirtualizingStackPanel -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Change header for ItemsControl -->
<ItemsControl.Template>
<ControlTemplate>
<Border Background="{StaticResource CustomAcrylicDarkBackground}">
<StackPanel>
<TextBlock Text="Accounts At A Glance" FontSize="28" Foreground="#b880fc" Padding="12"/>
<ItemsPresenter/>
</StackPanel>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<!-- Template for each card-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="240" Height="240" Background="Gray" Margin="30,0,0,0" VerticalAlignment="Center" Padding="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Name}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="24"/>
<TextBlock Grid.Row="1" Text="{Binding PayDate}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14" />
<TextBlock Grid.Row="2" Text="{Binding NumberOfItems}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I really apologise for this, im trying to learn as much as i can as i go. Im mainly stuggling with the XAML formatting and incorperating learning material into my project :/ Any help would be amazing
I have an alternative approach for your problem. This uses "semi" MVVM approach (browse through the net and study this pattern).
MainPageViewModel.cs
public class MainPageViewModel : INotifyPropertyChanged
{
private ObservableCollection<User> _userCollection;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<User> UserCollection
{
get => _userCollection;
set
{
_userCollection = value;
NotifyProperyChanged();
}
}
private void NotifyProperyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void LoadData()
{
UserCollection = new ObservableCollection<User>
{
new User
{
Name = "John Doe",
PayDate = DateTime.Now,
NumberOfItems = 1
},
new User
{
Name = "John Doe 2",
PayDate = DateTime.Now,
NumberOfItems = 1
},
new User
{
Name = "John Doe 3",
PayDate = DateTime.Now,
NumberOfItems = 1
},
};
}
}
The view (got rid of some styling temporarily):
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:App1.ViewModels"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
Loaded="MainPage_OnLoaded">
<Page.DataContext>
<vm:MainPageViewModel/>
</Page.DataContext>
<Grid>
<ScrollViewer>
<ItemsControl ItemsSource="{Binding UserCollection, Mode=TwoWay}" Margin="15" Width="Auto" Height="310">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- Template for each card-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Width="200" Height="100" Background="Gray" Margin="15,0,0,0" VerticalAlignment="Center" Padding="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Name}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="24"/>
<TextBlock Grid.Row="1" Text="{Binding PayDate}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14" />
<TextBlock Grid.Row="2" Text="{Binding NumberOfItems}" HorizontalAlignment="Center" TextAlignment="Center" Width="220" FontSize="14"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Page>
View's code-behind:
namespace App1
{
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
}
public MainPageViewModel VM => (MainPageViewModel) DataContext;
private void MainPage_OnLoaded(object sender, RoutedEventArgs e)
{
VM.LoadData();
}
}
}
Output:
Next steps:
Apply your styling. Study how to limit grid columns.
Improve the code
further, in MVVM you shouldn't really have implementations on the
code-behind, so study for ICommand, Microsoft.Xaml.Interactivity
Hope this helps.
It perfect now.
Im an idiot.
I essentially needed to seperate the information presented within the UserData.cs Class. I didnt understand how the information was being read but understand it now. The XAML has been left untouched as it works currently for what i need. It will be update to follow the MVVM format as mentioned by Mac. Here is the UserData.CS class located inside a data folder:
using System.Collections.ObjectModel;
namespace BudgetSheet.Data
{
public class UserData
{
public string Name { get; set; }
public string PayDate { get; set; }
public string NumberOfItems { get; set; }
}
class UserDataCollection : ObservableCollection<UserData>
{
public UserDataCollection()
{
// Placeholder, needs to be replaced with CSV or Database information
this.Add(new UserData()
{
Name = "Selected Username",
PayDate = "Friday",
NumberOfItems = "ItemAmount Placeholder"
});
// Placeholder for user 2
this.Add(new UserData()
{
Name = "Selected Username 2",
PayDate = "Friday 2",
NumberOfItems = "ItemAmount Placeholder 2"
});
// Placeholder for user 3
this.Add(new UserData()
{
Name = "Selected Username 3",
PayDate = "Friday 3",
NumberOfItems = "ItemAmount Placeholder 3"
});
}
}
}
Here is what it was before hand and why there were issues with information display:
using System.Collections.ObjectModel;
namespace BudgetSheet.Data
{
public class UserData
{
public string Name { get; set; }
public string PayDate { get; set; }
public string NumberOfItems { get; set; }
}
class UserDataCollection : ObservableCollection<UserData>
{
public UserDataCollection()
{
// Placeholder, needs to be replaced with CSV or Database information
this.Add(new UserData()
{
Name = "Selected Username",
});
// Placeholder for user selected PayDate
this.Add(new UserData()
{
PayDate = "Friday",
});
// Placeholder for user selected PayDate
this.Add(new UserData()
{
NumberOfItems = "ItemAmount Placeholder"
});
}
}
}
This solution does not provide much flexibility currently but it works for the formatting. Marking as resolved to close the ticket
In the ViewModel I have defined a bool ShouldExpand property, bound to it in from the TreeView's itemcontainerstyle - it does not work.
This answer (WinRT XAML Toolkit TreeView Save state) would've answered my question, but it does not work...
Is there a WORKING code snippet?
public class AgendaItemTreeView : ViewModelBase
{
private string _title;
private Visibility _documentGridVisibility = Visibility.Collapsed;
private bool _shouldExpand;
// Binding property - to display in a TreeView
public string Title
{
get { return _title; }
set { Set(ref _title, value); }
}
// To expand/collapse documents GridView
public Visibility DocumentGridVisibility
{
get { return _documentGridVisibility; }
set { Set(ref _documentGridVisibility, value); }
}
// Property to expand/collapse a node in a TreeView - does not work!
public bool ShouldExpand
{
get { return _shouldExpand; }
set { Set(ref _shouldExpand, value); }
}
// Nested agenda items
public ObservableCollection<AgendaItemTreeView> AgendaItems { get; set; } = new ObservableCollection<AgendaItemTreeView>();
// Documents of current agenda item
public ObservableCollection<DocumentViewModel> Documents { get; set; } = new ObservableCollection<DocumentViewModel>();
public DocumentViewModel SelectedItem { get; set; }
public AgendaItemTreeView(AgendaItem agendaItem, string selectedTitle = "")
{
// Constructor populating the nested AgendaItem & Documents
}
}
XAML:
<UserControl
<UserControl.Resources>
<!--<Style x:Key="TreeViewItemContainerStyle" TargetType="controls:TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding ShouldExpand, Mode=TwoWay}"/>
</Style>-->
<!-- Folder type Node, that can contain other 'folders' and 'files' -->
<DataTemplate x:Key="TreeViewItemTemplate" x:DataType="vm:AgendaItemTreeView">
<data:DataTemplateExtensions.Hierarchy>
<data:HierarchicalDataTemplate ItemsSource="{Binding AgendaItems}" />
<!-- When the next line used together with the Style TreeViewItemContainerStyle - the TreeView still does not expand the top level tree. The app C
<!--<data:HierarchicalDataTemplate ItemsSource="{Binding AgendaItems}" ItemContainerStyle="{StaticResource TreeViewItemContainerStyle}"/>-->
</data:DataTemplateExtensions.Hierarchy>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ToggleButton x:Name="titleToggleBtn" Tapped="{x:Bind ExpandDocumentsCommand}">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="{x:Bind DocumentsIcon}" Margin="5,0"/>
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</ToggleButton>
<GridView Grid.Row="1" x:Name="DocumentsGrid" ItemsSource="{Binding Documents}" ItemTemplate="{StaticResource ZoomedInTemplate}" Visibility="{Binding DocumentGridVisibility}" SelectedItem="{Binding SelectedItem}"/>
</Grid>
</DataTemplate>
<!-- Nested 'file' type Node data template -->
<DataTemplate x:Key="ZoomedInTemplate" x:DataType="vm:DocumentViewModel">
<Border BorderBrush="Black" Padding="5" BorderThickness="1" Width="100">
<Grid Tapped="{x:Bind TappedCommand}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Image Source="{Binding Thumbnail}" Width="60" Height="80" />
<TextBlock Grid.Row="1" Text="{x:Bind Title, Mode=OneWay}" VerticalAlignment="Center" Tapped="{x:Bind TappedCommand}"/>
</Grid>
</Border>
</DataTemplate>
</UserControl.Resources>
<Grid d:DataContext="{d:DesignData /SampleData/AgendaItemTreeViewSampleData.xaml}">
<controls:TreeView x:Name="myTreeView"
ItemsSource="{x:Bind TreeItems}"
ItemTemplate="{StaticResource TreeViewItemTemplate}" />
</Grid>
</UserControl>
Given I have a GridView and I want to navigate to a different page by clicking each item.
How can navigate to a view associated to the viewmodel?
In WPF there is a way to set multiple Datatemplates for the viewmodel.
<TabControl Grid.Row="1" Margin="0" ItemsSource="{Binding Tabs}" SelectedIndex="0" SelectedItem="{Binding SelectedTab}">
<TabControl.Resources>
<DataTemplate DataType="{x:Type dashboard:DashboardViewModel}">
<dashboard:DashboardView/>
</DataTemplate>
<DataTemplate DataType="{x:Type controls:ExchangeViewModel}">
<controls:ExchangeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type request:RequestViewModel}">
<request:RequestView/>
</DataTemplate>
<DataTemplate DataType="{x:Type addresses:AddressViewModel}">
<addresses:AddressView/>
</DataTemplate>
<DataTemplate DataType="{x:Type settings:ExchangeSettingsViewModel}">
<settings:ExchangeSettingsView/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate DataType="vm:ViewModelBase">
<TextBlock Text="{Binding Header}" FontSize="14"></TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
This is what I tried in UWP in my particular case:
<Frame Grid.Row="1" DataContext="{x:Bind ViewModel.Value}">
<Frame.Resources>
<DataTemplate x:DataType="viewModels:ExampleViewModel1">
<views:ExampleView1></views:ExampleView1>
</DataTemplate>
<DataTemplate x:DataType="viewModels:ExampleViewModel2">
<views:ExampleView2></views:ExampleView2>
</DataTemplate>
</Frame.Resources>
</Frame>
The Frame is part of a page and I want to show the corresponding view based on the Value of the ViewModel.
Visual Studio tells me DataTemplate has to have a key attribute, but even then it doesn't work as it would in WPF, since it's not creating the view.
I know DataType was replaced with x:DataType and x:Type seems to be gone. Is there a way to achieve similar results?
In WPF, the DataType is a dependency property which can be retrieved in runtime.
In UWP, the x:DataType is compile-time property, you cannot get the value in runtime.
I created a simple demo about how to map the datatype and data template in UWP through DataTemplateSelector.
DataTemplateSelector:
namespace UWPApp
{
public class Template
{
public string DataType { get; set; }
public DataTemplate DataTemplate { get; set; }
}
public class TemplateCollection2 : System.Collections.ObjectModel.Collection<Template>
{
}
public class MyDataTemplateSelector : DataTemplateSelector
{
public TemplateCollection2 Templates { get; set; }
private IList<Template> _templateCache { get; set; }
public MyDataTemplateSelector()
{
}
private void InitTemplateCollection()
{
_templateCache = Templates.ToList();
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (_templateCache == null)
{
InitTemplateCollection();
}
if(item != null)
{
var dataType = item.GetType().ToString();
var match = _templateCache.Where(m => m.DataType == dataType).FirstOrDefault();
if(match != null)
{
return match.DataTemplate;
}
}
return base.SelectTemplateCore(item, container);
}
}
}
ViewModel:
namespace UWPApp
{
public class ViewModel1
{
public string Text1 { get; set; }
}
public class ViewModel2
{
public string Text2 { get; set; }
}
}
XAML:
<Grid
x:Name="container"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<local:TemplateCollection2 x:Key="templates">
<local:Template DataType="UWPApp.ViewModel1">
<local:Template.DataTemplate>
<DataTemplate x:DataType="local:ViewModel1">
<StackPanel>
<TextBlock Text="{Binding Text1}"></TextBlock>
<TextBlock Text="From template1"></TextBlock>
</StackPanel>
</DataTemplate>
</local:Template.DataTemplate>
</local:Template>
<local:Template DataType="UWPApp.ViewModel2">
<local:Template.DataTemplate>
<DataTemplate x:DataType="local:ViewModel2">
<StackPanel>
<TextBlock Text="{Binding Text2}"></TextBlock>
<TextBlock Text="From template2"></TextBlock>
</StackPanel>
</DataTemplate>
</local:Template.DataTemplate>
</local:Template>
</local:TemplateCollection2>
<local:MyDataTemplateSelector
x:Key="myDataTemplateSelector" Templates="{StaticResource templates}">
</local:MyDataTemplateSelector>
</Grid.Resources>
<StackPanel>
<Button x:Name="button" Click="button_Click">Click Me</Button>
<ContentControl x:Name="stage" ContentTemplateSelector="{StaticResource myDataTemplateSelector}">
</ContentControl>
</StackPanel>
</Grid>
I am using MVVM light on a Windows 8.1 Store app. I have a view model that has several properties on it that have no setters (their value is derived from a different property). Here is part of my ViewModel:
public float TotalAmount
{
get
{
if (!LineItems.Any())
return 0.0f;
return SubTotal + TotalFees - TotalDiscounts;
}
}
public float SubTotal
{
get
{
return !LineItems.Any() ? 0.0f : LineItems.Select(i => i.Price.Amount).Sum();
}
}
public float TotalFees
{
get
{
return !Fees.Any() ? 0.0f : Fees.Select(f => f.Amount).Sum();
}
}
public float TotalDiscounts
{
get
{
return !Discounts.Any() ? 0.0f : Discounts.Select(d => d.Amount).Sum();
}
}
public ObservableCollection<Discount> Discounts { get; set; }
public ObservableCollection<Fee> Fees { get; set; }
public Customer Customer { get; set; }
public ObservableCollection<OrderLineItem> LineItems { get; set; }
In the XAML, I bind to each of these properties, and want to update them when an Item is added to LineItems.
Here is the relevant part of the XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="SubTotal:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Column="1" Style="{StaticResource OrderDetailsValue}"
Text="{Binding SubTotal, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
<TextBlock Grid.Row="1" Text="Fees:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Row="1" Style="{StaticResource OrderDetailsValue}" Grid.Column="1"
Text="{Binding TotalFees, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
<TextBlock Grid.Row="2" Text="Discounts:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Row="2" Style="{StaticResource OrderDetailsValue}" Grid.Column="1"
Text="{Binding TotalDiscounts, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
<TextBlock Grid.Row="3" Text="Order Total:" Style="{StaticResource OrderDetailsLabel}" />
<TextBlock Grid.Row="3" Style="{StaticResource OrderDetailsValue}" Grid.Column="1"
Text="{Binding TotalAmount, Converter={StaticResource MoneyConverter}, Mode=TwoWay}" />
</Grid>
My Binding to the LineItems is working as expected, but the fields that are populated by doing math on the line items are not.
Line Item Binding functioning as expected:
<ListView ItemsSource="{Binding LineItems, Mode=TwoWay}"
SelectionMode="Single"
HorizontalAlignment="Stretch">
<ListView.ItemContainerStyle>
....
How can I get SubTotal, Total, etc. to update when LineItems changes?
Pretty simple:
Register the ObservableCollection<T>.CollectionChanged event for each of those collection. Since your desired properties are based on some calculation of the collection.
On event fire Raise the OnPropertyChanged on those properties.
Example how to raise the OnPropertyChanged/inotifypropertychanged
MSDN: inotifypropertychanged Example
Something like this in your constructor:
LineItems.CollectionChanged += (s, e) =>
{
RaisePropertyChanged("SubTotal");
RaisePropertyChanged("TotalFees");
RaisePropertyChanged("TotalDiscounts");
}
assuming your ViewModel implements INotifyPropertyChanged, and has a 'RaisePropertyChanged' method that raises the PropertyChanged event (e.g. You're using MVVM-Light's ViewModelBase as your baseclass).
I ended up solving this by raising the OnPropertyChanged event on in the handler for my AddLineItems message:
public NewOrderViewModel()
{
//Subscribe to messages
MessengerInstance.Register<OrderItemAdded>(this, o => AddOrderItem(o.LineItem));
MessengerInstance.Register<SelectedCustomer>(this, c => Customer = c.Customer);
Discounts = new ObservableCollection<Discount>();
Fees = new ObservableCollection<Fee>();
LineItems = new ObservableCollection<OrderLineItem>();
}
private void AddOrderItem(OrderLineItem lineItem)
{
//add Line Item to collection
LineItems.Add(lineItem);
//Raise events for properties derived from collection
RaisePropertyChanged("TotalAmount");
RaisePropertyChanged("SubTotal");
}
I have a fairly simple Windows 8 XAML/C# UserControl:
<UserControl
x:Class="periodicTable.cell"
x:Name="periodicTableCell"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:periodicTable"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="100"
d:DesignWidth="65">
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="20"/>
<RowDefinition Height="50"/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="txtElementName"/>
<TextBlock Grid.Row="1" x:Name="txtAtomicNumber"/>
<TextBlock Grid.Row="2" x:Name="txtSymbol"/>
<TextBlock Grid.Row="3" x:Name="txtAtomicWeight"/>
</Grid>
My code behind is:
namespace periodicTable
{
public sealed partial class cell : UserControl
{
public string elementName { get; set; }
public string atomicNumber { get; set; }
public string symbol { get; set; }
public string atomicWeight { get; set; }
public cell()
{
this.InitializeComponent();
this.txtElementName.Text = elementName.ToString();
this.txtAtomicNumber.Text = atomicNumber.ToString();
this.txtAtomicWeight.Text = atomicWeight.ToString();
this.txtSymbol.Text = symbol.ToString();
}
}
}
When I add this control to my MainPage XAML:
xmlns:local="using:periodicTable"
Then when I try to add it to my grid:
<local:cell Grid.Row="0" Grid.Column="2"/>
I get an error stating: object reference not set to an instance of an object
I should note that I plan on reusing this user control in many rows and columns...
What am I doing wrong?
elementName, atomicNumber, symbol and atomicWeight appear not to be initialized. Their values will be null and the .ToString() methods will fail. Try initializing them to an empty string first.