问题
Given a list of objects containing two properties (IdentityType and Name) in the format:
IdentityType | Name
A | One
A | Two
A | Three
B | Four
B | Five
C | Six
Is there a way to declaratively databind that so the accordion displays like this?
A
- One
- Two
- Three
B
- Four
- Five
C
- Six
So far the best I can get is a panel header for each item, like so:
<toolkit:Accordion ItemsSource="{Binding Path=Identities}" Grid.Row="2" SelectionMode="ZeroOrMore">
<toolkit:Accordion.ItemTemplate>
<DataTemplate >
<TextBlock Text="{Binding IdentityType, Converter={StaticResource EnumDescriptionConverter}}"/>
</DataTemplate>
</toolkit:Accordion.ItemTemplate>
<toolkit:Accordion.ContentTemplate>
<DataTemplate>
<StackPanel Margin="5" Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Foreground="White" />
</StackPanel>
</DataTemplate>
</toolkit:Accordion.ContentTemplate>
</toolkit:Accordion>
I'm new to Silverlight so I could be missing something blindingly obvious, but any help would be very much appreciated!
回答1:
You can do this with a view model inbetween your model (the initail list) and your view (the markup).
- Create a view model class with a Title and a NameCollection
- Use LINQ (or a simple foreach) to translate your existing list of 6 entities to a list of 3 entites with 3, 2 and 1 Names in their name collection respectively.
- Bind your Accordions ItemsSource to the collection of ViewModel objects.
- Bind the text block in the your accordion items header template to your Title property
- Add a repeating item control like ItemsControl to your content template of your accordion item
- Bind your repeating item to the NamesCollection
Assuming your model is as follows...
public class Model
{
public string Title { get; set; }
public string Name { get; set; }
}
Your View Model structure should be...
public class ViewModel
{
public string Title { get; set; }
public List<string> Names { get; set; }
}
public class DataContextClass
{
public DataContextClass()
{
var modelData = new ModelData();
var query = from m in modelData.ModelCollection
group m by m.Title
into vm select new ViewModel { Title = vm.Key, Names = vm.Select(x => x.Name).ToList() };
ViewModelCollection = query.ToList();
}
public List<ViewModel> ViewModelCollection { get; set; }
}
Then your view can create an instance of your DataContextClass, assign it to it's own DataContext property and then use this markup...
<layout:Accordion ItemsSource="{Binding Path=ViewModelDataInstance.ViewModelCollection}" >
<layout:Accordion.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</layout:Accordion.ItemTemplate>
<layout:Accordion.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Names}" />
</DataTemplate>
</layout:Accordion.ContentTemplate>
</layout:Accordion>
回答2:
You can also use Tuple instead. Code becomes :
public class DataContextClass{
public DataContextClass()
{
var modelData = new ModelData();
var query = from m in modelData.ModelCollection
group m by m.Title
into vm select Tuple.Create(vm.Key, vm.Select(x => x.Name).ToList() };
Collection = query.ToList();
}
public Tuple<string,List<string>> Collection { get; set; }
}
Xaml become :
<layout:Accordion ItemsSource="{Binding Path=ViewModelDataInstance.ViewModelCollection}" >
<layout:Accordion.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Item1}" />
</DataTemplate>
</layout:Accordion.ItemTemplate>
<layout:Accordion.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Path=Item2}" />
</DataTemplate>
</layout:Accordion.ContentTemplate>
I hope it helps
来源:https://stackoverflow.com/questions/5089275/databinding-accordion-to-generic-list-in-silverlight