Create a Collection with different Data Types and Bind to a List
I am trying to create a collection with different data types to bind to a listbox control in Silverlight and C#.
Is this possible if each of the data types implements an interface?
For example, I have separate objects "Violin", "Guitar", an开发者_JAVA百科d "Drums", each of which implement the "IMusicalInstrument" interface. Can I then create a List, bind that to a listbox, and alternatively add "Violin", "Guitar", and "Drums" objects to that list?
Yes you can, by using a list that is Generic, have a look at List<T>
. You can create a list with some instruments like this:
var instruments = new List<IMusicalInstrument> {
new Drum(),
new Guitar(),
new Violin()
}
and then use instrumentsListBox.DataSource = instruments;
However if you want to make it easy for yourself, tell them to implement the properties for DisplayMember
and ValueMember
, this is what the ListBox
uses to determen what to show and use as value when you select something.
To clarify one thing, because Silverlight data-binding isn't strongly typed, the various items in the list don't need to all support a common interface. It's likely a better design if they do, but all they actually need to do is support the properties to which you'll be binding. And if you want to get fancy, you could divide up your datatemplate into different parts, each of which is designed for a different class, and then hide the parts that aren't applicable to the particular item being displayed. So you could have a completely different interface for a drum, guitar, violin, etc. For instance, let's say your instruments were defined like this:
public class Drum
{
public int DrummerCount { get; set; }
}
public class Violin
{
public int ViolinistCount { get; set; }
}
public class Guitar
{
public int GuitaristCount { get; set; }
}
You could then create a ListBox that looked like this:
<ListBox x:Name="instrumentsListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock
Visibility="{Binding Converter={StaticResource instrumentVisibilityConverter}, ConverterParameter=Drum}"
Text="{Binding DrummerCount, StringFormat=Drummers:\{0\}, Converter={StaticResource debugConverter}}"/>
<TextBlock
Visibility="{Binding Converter={StaticResource instrumentVisibilityConverter}, ConverterParameter=Violin}"
Text="{Binding ViolinistCount, StringFormat=Violinists:\{0\}, Converter={StaticResource debugConverter}}"/>
<TextBlock
Visibility="{Binding Converter={StaticResource instrumentVisibilityConverter}, ConverterParameter=Guitar}"
Text="{Binding GuitaristCount, StringFormat=Guitarists:\{0\}, Converter={StaticResource debugConverter}}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note how each class has a separate TextBlock that's used to display it. The visibility of each TextBlock is controlled via an InstrumentVisibilityConverter that looks like this:
public class InstrumentVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string expectedType = parameter as string;
if (value.GetType().Name == expectedType)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then instantiate it in code like this (or however you want):
List<object> instruments = new List<object>
{
new Guitar(),
new Guitar(),
new Violin(),
new Violin(),
new Drum()
};
instrumentsListBox.ItemsSource = instruments;
Now, I personally think (see here) that Silverlight data-binding should be strongly typed. But I seem to be in the minority there. And as long as it's not, there's no problem with taking advantage of it like this.
精彩评论