Silverlight - binding a listbox within a listbox template - silverlight

In silverlight, I'm trying to build a listbox of reports and I'm trying to show the parameters of the report in a listbox within the datatemplate of the outer reports listbox.
Here are the data classes:
public class Report
{
public string Title { get; set; }
public string Description { get; set; }
public List<ReportParameter> Parameters = new List<ReportParameter>();
}
public class ReportParameter
{
public string Name { get; set; }
public string ParameterType { get; set; }
public bool Required { get; set; }
}
Here's the XAML I'm trying to use to do it:
<ListBox x:Name="lstReports">
<ListBox.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel>
<TextBlock Text="{Binding Title}"/>
<ListBox ItemsSource="{Binding Parameters}" Height="60" Width="60">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The binding for the Title of the report works, but the inner listbox is empty for each of the reports.
The Parameters list is populated.
What am I doing wrong?
Thanks!

Your "Parameters" list is a public field not a property, silverlight can only bind to properties and not fields. Try changing your class to this:
public class Report
{
public Report()
{
Parameters = new List<ReportParameter>();
}
public string Title { get; set; }
public string Description { get; set; }
public List<ReportParameter> Parameters { get; set; }
}
This should work the way you want it.

Related

WPF DataGrid ContentControll bindng

I want to make DataGrid with a structure as in image below.
To have two TextBoxes in each cell.
Ive made Class
public class ComplexTable : ViewModelBase
{
public ComplexTable()
{
FirstProperty = new FirstClass();
SecondProperty = new Second();
}
public class FirstClass
{
public FirstClass()
{
First = "FirstString";
Second = "SecondString";
}
public string First { get; set; }
public string Second { get; set; }
}
public class Second
{
public Second()
{
Third = "ThirdString";
Fourth = "FourthString";
}
public string Third { get; set; }
public string Fourth { get; set; }
}
public FirstClass FirstProperty { get; set; }
public Second SecondProperty { get; set; }
}
public ObservableCollection<ComplexTable> _testCollection = new ObservableCollection<ComplexTable>();
private ObservableCollection<ComplexTable> TestCollection
{
get { return _testCollection; }
set
{
_testCollection = value;
RaisePropertyChanged("TestCollection");
}
}
And a TestCollection that should be a ItemsSource for DataGrid.
My DataGrid
<DataGrid CanUserAddRows="True"
ItemsSource="{Binding TestCollection}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="First Column">
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate >
<ContentControl>
<StackPanel>
<TextBox Text=" "/>
<TextBox Text=" "/>
</StackPanel>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Second Column">
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate >
<ContentControl>
<StackPanel>
<TextBox Text=" "/>
<TextBox Text=" "/>
</StackPanel>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I can't figure out how to bind those textboxes. Or i went in a wrong direction?
The datagrid sets the DataContext of the columns to the elements of the ItemSource. Every element in that ItemSource will be displayed as one Row. In your case the ItemSource is TestCollection. Therefore the DataContext inside your DataGridTemplateColumn is set to the elements of the TestCollection. If TestCollection contains ComplexTable elements. You can bind directly to the properties on ComplexTable.
var TestCollection = new ObservableCollection<DataForOneRow> {DataForFirstRow, DataForSecondRow, DataForThirdRow};
public class DataForOneRow {
public string DataForFirstColumnFirstTextBox {get; set;} //left out raise of PropertyChanged for brevity
public string DataForFirstColumnSecondTextBox {get; set;}
public string DataForSecondColumnFirstTextBox {get; set;}
public string DataForSecondColumnSecondTextBox {get; set;}
}
<DataGridTemplateColumn Header="First Column">
<DataGridTemplateColumn.CellEditingTemplate >
<DataTemplate >
<ContentControl>
<StackPanel>
<TextBox Text="{Bidning DataForFirstColumnFirstTextBox}"/>
<TextBox Text="{Bidning DataForFirstColumnSecondTextBox}"/>
</StackPanel>
</ContentControl>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
FYI: You have to raise a PropertyChanged event in all ViewModel properties.

WPF Expander Hierarchical data Template of 2 levels

I have a repeating data structure like this
public class Chapter
{
public string id { get; set; }
public string name { get; set; }
public List<BPage> pages { get; set; }
public List<SubChapter> chapters { get; set; }
}
public class SubChapter
{
public string name { get; set; }
public string id { get; set; }
public List<BPage> pages { get; set; }
public string ParentPageId { get; set; }
public List<SubChapter> chapters { get; set; }
}
public class BPage
{
public string name { get; set; }
public string label { get; set; }
}
Here is the xaml i am using , But this xaml is giving only one level of data back to me . Second level is missing completely
ie if Chapter 1 contains 2 subchapters and pages , then those info is missing
Chapter 1
page 1
page 2
Chapter 1.1
page 1a
page 1b
Chapter 1.2
page 2a
page 2b
And xaml is
<ListBox ItemsSource="{Binding}" Name="TOCView" ItemContainerStyle="{StaticResource ListBoxItemStyle}">
<ListBox.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding chapters}">
<Expander>
<Expander.Header>
<BulletDecorator>
<Label Style="{StaticResource ResourceKey=ChapterHeadStyle}" Content="{Binding name}"></Label>
</BulletDecorator>
</Expander.Header>
<ItemsControl Margin="25,0,0,0" ItemsSource="{Binding pages}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Tag="{Binding}" Click="btnNavigateToPage_Click" Style="{StaticResource ResourceKey=BookPageStyle}" Content="{Binding Path=label}" >
</Button>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Your problem is caused because you have only provided one HierarchicalDataTemplate, but you want to define two hierarchical levels. Therefore, you need to provide another HierarchicalDataTemplate for your second level. Please note that you do not have to define them in the ListBox.ItemTemplate property, instead defining them both in a Resources section:
<HierarchicalDataTemplate DataType="{x:Type YourPrefix:Chapter}"
ItemsSource="{Binding CollectionPropertyInSubChapterClass}">
...
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type YourPrefix:SubChapter}">
ItemsSource="{Binding CollectionPropertyInBPageClass}">
...
</HierarchicalDataTemplate>
As long as you don't specify the x:Key directive for either of them, they will be implicitly applied, so you won't have to provide any value for the ListBox.ItemTemplate property.

Binding list property to TextBlock

I have a class named MyClass which looks like this:
public class MyClass : BaseObject, IDisposable
{
public int MyClassId { get; set; }
public IList<MyClassTranslation> MyTranslations { get; set; }
}
And MyClassTranslation looks like this:
public class MyClassTranslation
{
public string MyClassName { get; set; }
}
I have a view and a view model. The View model looks like this:
class MyClassViewModel : ViewModelBase, IMyClassViewModel
{
public MyClassViewModel()
{
myObjects = GetMyObjects();
}
public IList<MyClass> myObjects { get; set; }
}
And here's the view:
<ItemsControl ItemsSource="{Binding myObjects}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Center">
<TextBlock FontSize="24pt" FontWeight="Bold" TextAlignment="Center" Text="{Binding MyClassTranslation.MyClassName[0]}"></TextBlock>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The problem is that the myClassName property isn't shown. How do I bind it?
assuming that the data context is set properly, so the proper binding would be
<StackPanel HorizontalAlignment="Center">
<TextBlock FontSize="24pt"
FontWeight="Bold"
TextAlignment="Center"
Text="{Binding MyTranslations[0].MyClassName}">
</TextBlock>
</StackPanel>
you can use indexer to bind such values

WPF TabControl ContentTemplate List

Inexperienced with WPF, so I need a little help. Appreciate the help in advance.
I have the following class:
public class TabDefn
{
public TabDefn() { }
public TabDefn(string inFolderName, List<FilesFolder> inFilesFolders)
{
folderName = inFolderName;
FFs = inFilesFolders;
}
public string folderName { get; set; }
public List<FilesFolder> FFs {get; set;}
}
public class FilesFolder
{
public FilesFolder() {}
//public Image image { get; set; }
public string ffName { get; set; }
//public Image arrow { get; set; }
}
The TabControl.ItemContent is working fine. I can't get anything to show up for the TabControl.ContentTemplate. I've tried many things, but this is where the WPF is right now:
<TabControl Grid.Column="1" Grid.Row="1" Visibility="Hidden" Name="Actions">
<!-- This displays the tab heading perfectly.-->
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding folderName}" />
</DataTemplate>
</TabControl.ItemTemplate>
<!-- This is the content of the tab that I can't get anything to show up in.-->
<TabControl.ContentTemplate>
<DataTemplate>
<ListBox ItemsSource="{Binding FF}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding ffName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
I don't care if the content changes, so I don't need the INotifyPropertyChanged or ObservableCollection. However, if I have to put all that code in, so be it.
You declare FF as field which is invalid binding source. You need to convert it into property
public List<FilesFolders> FF { get; set; }
and initialize it for example in TabDefn constructor. You can find more as to what is a valid binding source on MSDN

WPF datagrid dropdown two-way binding

I'm trying to get a dropdown column in a WPF datagrid (hosted in a user control derived from a base class called ControlBase) to bind properly. It initially populates fine from the object, and a populated dropdown appears when I edit the cell, but a selected value does not get back into the cell when I leave focus.
Here's my model and domain objects:
public class ModelBase : INotifyPropertyChanged
{
public IList<Person> Persons { get; set; }
}
public class UserControlModel : ModelBase
{
public ObservableCollection<DatagridRecord> SourceData { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
public class DatagridRecord
{
public string Name { get; set; }
public Person ContactPerson { get; set; }
}
And in my xaml.cs, I set the DataContext via a Model property:
public UserControlModel _model;
public UserControlModel Model
{
set
{
_model = value;
DataContext = null;
DataContext = _model;
}
}
Here's my DataGrid column definition in xaml:
<DataGridTemplateColumn Header="Person" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ContactPerson.Name}"/></DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Persons,
RelativeSource={RelativeSource AncestorType={x:Type uch:ControlBase}}}"
DisplayMemberPath="Name"
SelectedValuePath="Id" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
I figure there is something wrong with tying the combobox selected value to the grid row, but I've gone around in circles trying to hook it up. Any advice would be appreciated.
Corey.
You're Missing a SelectedItem or SelectedValue binding:
<ComboBox ItemsSource="{Binding Path=DataContext.Persons,
RelativeSource={RelativeSource AncestorType={x:Type uch:ControlBase}}}"
DisplayMemberPath="Name"
--> SelectedItem="{Binding ContactPerson}" <--
SelectedValuePath="Id" />

Resources