Silverlight Simple Master Detail Binding - silverlight

I have what I think is a very simple problem, but for some reason the answer is escaping me. I am creating a simple Master/Detail DataGrid in Silverlight. Most of the samples on the web display this by creating an object with a Collection of some kind, and binding the Detail grid to the collection. In my case, I just want to bind the detail grid to the same object as the row acting as the master. I know my example code is simple, but I'm just trying to make the simplest possible demo to recreate it. That being said, let's say I have this data:
public class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public string FavoriteColor { get; set; }
}
public class CustomerCollection : ObservableCollection<Customer>
{
public CustomerCollection()
{
Add(new Customer() { CustomerId = 101, CustomerName = "Todd", FavoriteColor = "Red" });
Add(new Customer() { CustomerId = 102, CustomerName = "Melissa", FavoriteColor = "White" });
Add(new Customer() { CustomerId = 102, CustomerName = "Alicia", FavoriteColor = "Blue" });
Add(new Customer() { CustomerId = 104, CustomerName = "Matthew", FavoriteColor = "Yellow" });
}
}
OK. Pretty darn simple. Now, I'm going to bind this collection to a datagrid. Each row should show the CustomerId and CustomerName. And when you click the row, I want to display their favorite color in the details datagrid.
So the question is... How do I bind the details grid so that it shows the Favorite Color? Or in other words, how do bind to the parent row as my data source?
<UserControl x:Class="Sample.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="419" d:DesignWidth="742"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:src="clr-namespace:Sample">
<UserControl.Resources>
<src:CustomerCollection x:Key="CustDs"></src:CustomerCollection>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource CustDs}}">
<Grid.RowDefinitions>
<RowDefinition Height="56*" />
<RowDefinition Height="363*" />
</Grid.RowDefinitions>
<TextBlock Name="TextBlock1" Text="Customer Information" FontSize="28" TextAlignment="Center" />
<sdk:DataGrid AutoGenerateColumns="False" Grid.Row="1"
Height="301" HorizontalAlignment="Left" Margin="30,22,0,0"
Name="DgCust" VerticalAlignment="Top" Width="681" ItemsSource="{Binding}"
HeadersVisibility="All" ColumnWidth="*">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Customer Id" Binding="{Binding CustomerId}"></sdk:DataGridTextColumn>
<sdk:DataGridTextColumn Header="Customer Name" Binding="{Binding CustomerName}"></sdk:DataGridTextColumn>
</sdk:DataGrid.Columns>
<sdk:DataGrid.RowDetailsTemplate>
<DataTemplate>
<sdk:DataGrid Height="200" Width="600" AutoGenerateColumns="False" ColumnWidth="*"
ItemsSource="{Binding}">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Favorite Color" Binding="{Binding}"></sdk:DataGridTextColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</DataTemplate>
</sdk:DataGrid.RowDetailsTemplate>
</sdk:DataGrid>
</Grid>
</UserControl>

Your data doesn't represent a Master/Detail scenario. If you just want to display the favorite color in a details area, do this in the DataTemplate section:
<sdk:DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock Text="{Binding FavoriteColor}" />
</DataTemplate>
</sdk:DataGrid.RowDetailsTemplate>
If you actually want Master/Details, try this instead:
public class Customer
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public string FavoriteColor { get; set; }
public List<FavoriteShow> Shows { get; set; }
}
public class FavoriteShow
{
public string Name {get;set;}
public int Stars {get;set;}
}
public class CustomerCollection : ObservableCollection<Customer>
{
public CustomerCollection()
{
List<FavoriteShow> showList1 = new List<FavoriteShow>();
showList1.Add(new FavoriteShow { Name="Bugs Bunny", Stars = 4});
showList1.Add(new FavoriteShow { Name="Superman", Stars=2});
showList1.Add(new FavoriteShow { Name="A-Team", Stars=3});
List<FavoriteShow> showList2 = new List<FavoriteShow>();
showList2.Add(new FavoriteShow { Name = "Dallas", Stars = 1 });
showList2.Add(new FavoriteShow { Name = "Loony Tunes", Stars = 3 });
Add(new Customer() { CustomerId = 101, CustomerName = "Todd", FavoriteColor = "Red", Shows = showList1 });
Add(new Customer() { CustomerId = 102, CustomerName = "Melissa", FavoriteColor = "White" });
Add(new Customer() { CustomerId = 102, CustomerName = "Alicia", FavoriteColor = "Blue", Shows = showList2 });
Add(new Customer() { CustomerId = 104, CustomerName = "Matthew", FavoriteColor = "Yellow" });
}
}
And the XAML:
<UserControl x:Class="Sample.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="419"
d:DesignWidth="742"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:src="clr-namespace:Sample">
<UserControl.Resources>
<src:CustomerCollection x:Key="CustDs"></src:CustomerCollection>
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
Background="White"
DataContext="{Binding Source={StaticResource CustDs}}">
<Grid.RowDefinitions>
<RowDefinition Height="56*" />
<RowDefinition Height="363*" />
</Grid.RowDefinitions>
<TextBlock Name="TextBlock1"
Text="Customer Information"
FontSize="28"
TextAlignment="Center" />
<sdk:DataGrid AutoGenerateColumns="False"
Grid.Row="1"
Height="301"
HorizontalAlignment="Left"
Margin="30,22,0,0"
Name="DgCust"
VerticalAlignment="Top"
Width="681"
ItemsSource="{Binding}"
HeadersVisibility="All"
ColumnWidth="*">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Customer Id"
Binding="{Binding CustomerId}"></sdk:DataGridTextColumn>
<sdk:DataGridTextColumn Header="Customer Name"
Binding="{Binding CustomerName}"></sdk:DataGridTextColumn>
</sdk:DataGrid.Columns>
<sdk:DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding FavoriteColor}" />
<sdk:DataGrid ItemsSource="{Binding Shows}" />
</StackPanel>
</DataTemplate>
</sdk:DataGrid.RowDetailsTemplate>
</sdk:DataGrid>
</Grid>

Related

Bind nested object to WPF data grid

I have a DataGrid that has two columns (A and B). Each column cell contains a combo box control.
I have an object that contains two list items that I want to bind to the grid view, but the binding does not work.
Binding in both DataTemplates not working correctly. UI shows the namespace instead of value.
Sample Project:
https://1drv.ms/u/s!Ah27QQNpKj4jj2xsIsQamaOXOlin?e=jNAj2H
ViewModel
public class MainWindowViewModel {
public List < MainObject > MainObjects { get; set; }
public MainWindowViewModel() {
MainObjects = new List < MainObject > {
new MainObject {
AColumns = new List < ColumnA > {
new ColumnA { Name = "A1" },
new ColumnA { Name = "A1" }
},
BColumns = new List < ColumnB > {
new ColumnB { Name = "B1" },
new ColumnB { Name = "B1" }
},
}
};
}
}
public class MainObject {
public List < ColumnA > ?AColumns { get; set; }
public List < ColumnB > ?BColumns { get; set; }
}
public class ColumnA {
public string ? Name { get; set; }
}
View:
<Window x:Class="TestDataGrid.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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DataGrid ItemsSource="{Binding MainObjects}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Column A" Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center">
<TextBlock.Text>
<PriorityBinding>
<Binding Path="Name" Mode="TwoWay" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="True" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding AColumns}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
You have to use the "DisplayMemberPath" property instead of the "Text" property. like this
<ComboBox IsEditable="True" ItemsSource="{Binding AColumns}" SelectedValuePath="Name" DisplayMemberPath="Name"/>

WPF: MVVM: Bind selecteditem from inside an usercontrol to textbox

i am new to mvvm and hope, someone could help me to understand the following:
I have a Model, ViewModel and a View (UserControl), in the MainWindow there are 3 textboxes and the PersonView, which show several persons. This work. Now i want to select one of the persons (binded to SelectedPerson) and show the information in the 3 textboxes.
But i don't know, how to bind the SelectedPerson from PersonViewModel to the textboxes.
I tried to set the datacontext for the textboxes and the usercontrol to the same, and bind the boxes like Text="{Binding SelectedPerson.ID}", but that doesn't work.
Is there a way, to get the selected person from within the UserControl and display the information, or do i need to put the textboxes also in the usercontrol?
Thanks in advance,
Flo
PersonModel.cs:
namespace MVVMExample.Model
{
public class PersonModel: INotifyPropertyChanged
{
public int ID { get; set; }
private string forname;
public string Forname
{
get { return forname; }
set {
forname = value;
RaisePropertyChanged("Forname");
}
}
private string surname;
public string Surname
{
get { return surname; }
set {
surname = value;
RaisePropertyChanged("Surname");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
PersonViewModel.cs:
public class PersonViewModel
{
public PersonViewModel()
{
Persons = new ObservableCollection<PersonModel>();
LoadPersons();
}
public ObservableCollection<PersonModel> Persons
{
get;
set;
}
public PersonModel SelectedPerson { get; set; }
public void LoadPersons()
{
ObservableCollection<PersonModel> persons = new ObservableCollection<PersonModel>();
persons.Add(new PersonModel { ID = 1, Forname = "Thomas", Surname = "Sogen" });
persons.Add(new PersonModel { ID = 2, Forname = "Seth", Surname = "Xu" });
persons.Add(new PersonModel { ID = 3, Forname = "Derik", Surname = "Mayers" });
persons.Add(new PersonModel { ID = 4, Forname = "Daisy", Surname = "Doros" });
Persons = persons;
}
}
PersonView.xaml (UserControl):
<UserControl x:Class="MVVMExample.Views.PersonView"
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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MVVMExample.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="400">
<Grid>
<DataGrid Name="PersonDataGrid" Grid.Row="4" AutoGenerateColumns="False" ItemsSource="{Binding Persons, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" CanUserAddRows="False" IsReadOnly="True" HeadersVisibility="Column" FontSize="14" SelectionMode="Single" SelectedItem="{Binding SelectedPerson}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ID}" Width="*"/>
<DataGridTextColumn Header="Forname" Binding="{Binding Forname}" Width="*"/>
<DataGridTextColumn Header="Surname" Binding="{Binding Surname}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
PersonView.xaml.cs:
public partial class PersonView : UserControl
{
public PersonView()
{
InitializeComponent();
this.DataContext = new MVVMExample.ViewModel.PersonViewModel();
}
}
MainWindow.xaml
<Window x:Class="MVVMExample.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:MVVMExample"
xmlns:views="clr-namespace:MVVMExample.Views"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0"/>
<TextBox Grid.Row="1"/>
<TextBox Grid.Row="2"/>
<views:PersonView x:Name="PersonViewControl" Loaded="PersonViewControl_Loaded" Grid.Row="3"/>
</Grid>
</Window>

add dynamic Tab Item having data grid control

I have tab control In wpf Application. I want to add dynamic Tab Item having data grid control ? Any Solutions. Thanks In Advance.
please try the next solution:
Xaml Code (just uncomment gridview code if needed):
<Window x:Class="TabControlSOHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tabControlSoHelpAttempt="clr-namespace:TabControlSOHelpAttempt"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<tabControlSoHelpAttempt:TabControlViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TabControl Grid.Row="0" ItemsSource="{Binding Customers}" SelectedItem="{Binding SelectedCustomer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type tabControlSoHelpAttempt:Customer}">
<TextBlock>
<Run Text="Customer:"></Run>
<Run Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"></Run>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type tabControlSoHelpAttempt:Customer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
<!--<ListView Grid.Row="1" ItemsSource="{Binding CustomerDataCollection}">
<ListView.View>
<GridView>
<GridViewColumn Header="Book Name" DisplayMemberBinding="{Binding BookName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
<GridViewColumn Header="Keeping From" DisplayMemberBinding="{Binding KeepingFrom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
</GridView>
</ListView.View>
</ListView>-->
<DataGrid Grid.Row="1" ItemsSource="{Binding CustomerDataCollection}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Book Name" Binding="{Binding BookName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></DataGridTextColumn>
<DataGridTextColumn Header="Keeping From" Binding="{Binding KeepingFrom, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" VerticalAlignment="Bottom" Command="{Binding RemoveCustomer}">Remove Customer</Button>
<Button Grid.Column="1" VerticalAlignment="Bottom" Command="{Binding AddCustomer}">Add Customer</Button></Grid>
</Grid></Window>
View Models and models:
public class TabControlViewModel:BaseObservableObject
{
private ICommand _addCommand;
private Customer _selectedCustomer;
private ICommand _removeCommand;
public TabControlViewModel()
{
//here you can inject a model which will be able
//to support the initial data for the Customers colection,
//and will inform user if a customer was added or removed.
//On each model changes you can add a new custome object into Customers collection,
//since this collection is ObservableCollection, UI will be updated imidiatelly
Customers = new ObservableCollection<Customer>
{
new Customer
{
Name = "John",
CustomerDataCollection = new ObservableCollection<CustomerData>
{
new CustomerData
{
BookName = "Uncle Vania",
KeepingFrom = DateTime.Today,
},
new CustomerData
{
BookName = "Anna Karenine",
KeepingFrom = DateTime.Today,
}
}
},
new Customer
{
Name = "Tom",
CustomerDataCollection = new ObservableCollection<CustomerData>
{
new CustomerData
{
BookName = "War and Peace",
KeepingFrom = DateTime.Today,
},
new CustomerData
{
BookName = "Alice's Adventures in Wonderland",
KeepingFrom = DateTime.Today,
}
}
},
};
}
public ObservableCollection<Customer> Customers { get; set; }
public ICommand AddCustomer
{
get { return _addCommand ?? (_addCommand = new RelayCommand(AddCommandMethod)); }
}
private void AddCommandMethod()
{
Customers.Add(new Customer());
SelectedCustomer = Customers.LastOrDefault();
}
public ICommand RemoveCustomer
{
get { return _removeCommand ?? (_removeCommand = new RelayCommand(RemoveCommandMethod)); }
}
private void RemoveCommandMethod()
{
if(SelectedCustomer == null) return;
Customers.Remove(SelectedCustomer);
SelectedCustomer = Customers.LastOrDefault();
}
public Customer SelectedCustomer
{
get { return _selectedCustomer; }
set
{
_selectedCustomer = value;
OnPropertyChanged();
}
}
}
public class Customer:BaseObservableObject
{
public Customer()
{
Name = "Enter Customer Name";
CustomerDataCollection = new ObservableCollection<CustomerData>();
}
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public ObservableCollection<CustomerData> CustomerDataCollection { get; set; }
}
public class CustomerData:BaseObservableObject
{
private string _bookName;
private DateTime _qty;
public string BookName
{
get { return _bookName; }
set
{
_bookName = value;
OnPropertyChanged();
}
}
public DateTime KeepingFrom
{
get { return _qty; }
set
{
_qty = value;
OnPropertyChanged();
}
}
}
I'll be glad to help if there will be problems with the code, just let me know about this.
Regards.

Silverlight MVVM: Changing cell border color in DataGrid based on bound value in Silverlight

I am very new to Silverlight and am working on a project that is using the MVVM pattern. What that means is that I do not want to write code-behind to accomplish this task (the solution architect is very clear on this requirement), but rather I am looking for a way to do it entirely in XAML.
I have two classes that look like this:
using System.Collections.ObjectModel;
namespace SilverlightApplication2.ViewModels
{
public class ClassA
{
public long ClassAValueOne { get; set; }
public ObservableCollection<ClassB> ClassBs { get; set; }
}
}
namespace SilverlightApplication2.ViewModels
{
public class ClassB
{
public long? ClassBValueOne { get; set; }
public long? ClassBValueTwo { get; set; }
public long? ClassBValueThree { get; set; }
public long? ClassBValueFour { get; set; }
}
}
A view model class that looks like this:
using System.Collections.ObjectModel;
namespace SilverlightApplication2.ViewModels
{
public class EditorViewModel
{
public EditorViewModel()
{
this.ClassAs = new ObservableCollection<ClassA>
{
new ClassA
{
ClassAValueOne = 1,
ClassBs = new ObservableCollection<ClassB>
{
new ClassB { ClassBValueOne = 1, ClassBValueTwo = 2, ClassBValueThree = 3, ClassBValueFour = 4 },
new ClassB { ClassBValueOne = 5, ClassBValueTwo = 6, ClassBValueThree = 7, ClassBValueFour = 8 },
new ClassB { ClassBValueOne = 9, ClassBValueTwo = 10, ClassBValueThree = 11, ClassBValueFour = 12 }
}
},
new ClassA
{
ClassAValueOne = 3,
ClassBs = new ObservableCollection<ClassB>
{
new ClassB (),
new ClassB (),
new ClassB ()
}
}
};
}
public ObservableCollection<ClassA> ClassAs { get; set; }
}
}
And a view that looks like this:
<controls:ChildWindow x:Class="SilverlightApplication2.Views.ExemptionEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:viewmodels="clr-namespace:SilverlightApplication2.ViewModels"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
Width="470" Height="700"
Title="Exemption Editor">
<controls:ChildWindow.DataContext>
<viewmodels:EditorViewModel/>
</controls:ChildWindow.DataContext>
<i:Interaction.Triggers>
<ei:PropertyChangedTrigger Binding="{Binding DialogResult}">
<ei:ChangePropertyAction TargetObject="{Binding ElementName=ExemptionEditorChildWindow}" PropertyName="DialogResult" Value="{Binding DialogResult}"/>
</ei:PropertyChangedTrigger>
</i:Interaction.Triggers>
<controls:ChildWindow.Resources>
</controls:ChildWindow.Resources>
<Grid x:Name="LayoutRoot" Margin="2">
<Grid.Resources>
<Style x:Key="DataGridTextColumnReadOnlyBackgroundColor" TargetType="sdk:DataGridCell">
<Setter Property="Background" Value="#C6DEFE" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding ClassAs}">
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:Expander IsExpanded="True">
<toolkit:Expander.Header>
<Border Background="#FF99CC00">
<TextBlock Text="{Binding Path=ClassAValueOne}" FontWeight="Bold" Foreground="Black"></TextBlock>
</Border>
</toolkit:Expander.Header>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=ClassAValueOne, StringFormat='Enter data for item {0}'}" Margin="5,10,0,10" Foreground="Black" FontWeight="Bold"/>
<sdk:DataGrid ItemsSource="{Binding ClassBs}" AutoGenerateColumns="False" HorizontalAlignment="Center" VerticalAlignment="Center" RowHeight="20" Margin="0, 0, 0, 10">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding ClassBValueOne}" Header="ValueOne" FontWeight="Bold" Width="100" IsReadOnly="True" CellStyle="{StaticResource DataGridTextColumnReadOnlyBackgroundColor}"/>
<sdk:DataGridTextColumn Binding="{Binding ClassBValueTwo, Mode=TwoWay}" Header="ValueTwo" FontWeight="Bold" Width="100"/>
<sdk:DataGridTextColumn Binding="{Binding ClassBValueThree, Mode=TwoWay}" Header="ValueThree" FontWeight="Bold" Width="100"/>
<sdk:DataGridTextColumn Binding="{Binding ClassBValueFour, Mode=TwoWay}" Header="ValueFour" FontWeight="Bold" Width="100"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
</toolkit:Expander>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</controls:ChildWindow>
I have two UI requirements:
If any of the value properties in ClassB are null, the data grid cell representing that null value should have a red border around it to bring to the user's attention that they need to enter a value into that cell.
If a user tries to type a string into the cell for a value property of ClassB (which is typed as a nullable long), the cell background should turn red to bring to the user's attention that they can't enter a string value into the cell.
I've searched for possible ways to accomplish this, but everything I am finding is for WPF and refers to using a DataTemplateSelector, which doesn't exist in Silverlight.
Any help?
That is easier than you think!
You just need to use some validation attributes.
Check out these links:
http://msdn.microsoft.com/en-us/library/dd901590%28v=vs.95%29.aspx
http://www.asp.net/mvc/tutorials/older-versions/models-%28data%29/validation-with-the-data-annotation-validators-cs
ps: there are some examples in aspx , but you can apply then to silverlight as well.
Good luck!

WPF ListView within a ListView

I am sure I am missing something simple/obvious, but I cannot seem to bind the data of a ListView within a ListView
<Window x:Class="TestList.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="InsideListTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="test" Width="50"></TextBlock>
<TextBlock Text="{Binding OrderId}" Width="50"></TextBlock>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="OrdersTemplate">
<ListView HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
MinWidth="100"
MinHeight="25"
ItemsSource="{Binding Orders}"
ItemTemplate="{StaticResource InsideListTemplate}"
>
</ListView>
</DataTemplate>
<DataTemplate x:Key="CustomersTemplate">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding CustomerId}" Width="50" Foreground="Navy" VerticalAlignment="Center" />
<ListBox ItemsSource="{Binding Orders}" ItemTemplate="{StaticResource OrdersTemplate}" HorizontalContentAlignment="Stretch"></ListBox>
</StackPanel>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<ListView Name="listView" ItemTemplate="{StaticResource CustomersTemplate}" >
</ListView>
</DockPanel>
using System.Collections.Generic;
namespace TestList
{
public partial class MainWindow
{
public class Customer
{
public int CustomerId { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int OrderId { get; set; }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
var customers = new List<Customer>
{
new Customer
{
CustomerId = 1,
Orders = new List<Order>
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
},
new Customer
{
CustomerId = 2,
Orders = new List<Order>
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
}
};
listView.ItemsSource = customers;
}
}
}
This is an explanation of Hadis answer:
You are binding a ListBox to the Orders collection within the customer template. And then in the orders template you define a ListView binding again to the orders. This means that the binding path at that point is customer.orders.orders which does not exists.
If you just remove the OrdersTemplate and place the ListView where the ListBox is in the customer template then it works.
How about changing it list this:
public partial class MainWindow : Window
{
public class Customer
{
public int CustomerId { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public List<OrderItem> Items { get; set; }
}
public class OrderItem
{
public int No { get; set; }
public string Name { get; set; }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
var customers = new List<Customer>
{
new Customer
{
CustomerId = 1,
Orders = new List<Order>
{
new Order {OrderId = 1, Items = new List<OrderItem>(new[] { new OrderItem { Name = "CD Player", No = 1}, new OrderItem { Name = "VCR Player", No = 2} })},
new Order {OrderId = 2, Items = new List<OrderItem>(new[] { new OrderItem { Name = "DVD Player", No = 1} })}
}
},
new Customer
{
CustomerId = 2,
Orders = new List<Order>
{
new Order {OrderId = 1},
new Order {OrderId = 2}
}
}
};
listView.ItemsSource = customers;
}
}
and on your Xaml modify it like this:
<DataTemplate x:Key="InsideListTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding No}" Width="50"></TextBlock>
<TextBlock Text="{Binding Name}" Width="50"></TextBlock>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="OrdersTemplate">
<StackPanel>
<TextBlock Text="{Binding OrderId}" />
<ListView HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
MinWidth="100"
MinHeight="25"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource InsideListTemplate}" />
</StackPanel>
</DataTemplate>
And your output will display the details

Resources