Reputation: 12833
I have a view model that currently looks like below. The TCm type is a domain model type, ie TelephoneNumber. And there are subclassed PcmDetailVms (ie, TelephoneNumberPcmDetailVm). I want to use these properties for a DataGrid that deals the specific TCm (ie, TelephoneNumber).
While it isn't horrible at all to subclass it and do the casting I am wondering if there is any built-in xaml features that would do the casting. Or if it would be more idiomatic to use a converter?
Cheers,
Berryl
public class PcmShellVm<TCm> : ... where TCm : ContactMechanism
{
public ObservableCollection<PcmDetailVm> DetailVms { get; protected set; }
public PcmDetailVm SelectedVm {
get { return _collectionView.CurrentItem as PcmDetailVm; }
set { _collectionView.MoveCurrentTo(value); }
}
}
public class TelecomNumberPcmShellVm : PcmShellVm<TelecomNumber>
{
...
public IEnumerable<TelecomPcmDetailVm> CastedDetailVms { get { return DetailVms.Cast<TelecomPcmDetailVm>(); } }
public TelecomPcmDetailVm CastedSelectedVm
{
get { return (TelecomPcmDetailVm) SelectedVm; }
set { SelectedVm = value; }
}
}
So Andrei had the right answer to the question I did not ask very clearly above. I had incorrectly assumed I needed to cast my items somewhere in xaml, as I would need to do in code.
The binding engine must be using reflection to discover properties by name however, making the cast unnecessary.
Upvotes: 2
Views: 1327
Reputation: 20780
I am not sure I understood the question correctly but I think specific DataTemplates for each type would be an idea.
View :
<Window x:Class="WpfApplication18.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication18="clr-namespace:WpfApplication18"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type WpfApplication18:PersonsVM}">
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding FirstName}" Header="First name"/>
<DataGridTextColumn Binding="{Binding LastName}" Header="Last name"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
<DataTemplate DataType="{x:Type WpfApplication18:SpecificPersonsVM}">
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding LastName}" Header="Last name"/>
<DataGridTextColumn Binding="{Binding FirstName}" Header="First name"/>
<DataGridTextColumn Binding="{Binding Age}" Header="Age"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</Grid.Resources>
<ContentControl Content="{Binding}"/>
</Grid>
</Window>
ViewModels :
using System.Collections.ObjectModel;
namespace WpfApplication18
{
public class PersonVM
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class SpecificPersonVM : PersonVM
{
public byte Age { get; set; }
}
public class PersonsVM
{
public ObservableCollection<PersonVM> Items { get; private set; }
public PersonsVM()
{
Items = new ObservableCollection<PersonVM>();
}
}
public class SpecificPersonsVM
{
public ObservableCollection<SpecificPersonVM> Items { get; private set; }
public SpecificPersonsVM()
{
Items = new ObservableCollection<SpecificPersonVM>();
}
}
}
Setupcode (code behind, yeah...)
namespace WpfApplication18
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
//SetupPersonsVM();
SetupSpecificPersonsVM();
}
private void SetupSpecificPersonsVM()
{
var vm = new SpecificPersonsVM();
vm.Items.Add(new SpecificPersonVM { FirstName = "Johny", LastName = "Bravo", Age = 17 });
vm.Items.Add(new SpecificPersonVM { FirstName = "Dude", LastName = "Gray", Age = 22 });
vm.Items.Add(new SpecificPersonVM { FirstName = "Scott", LastName = "Thomas", Age = 34 });
DataContext = vm;
}
private void SetupPersonsVM()
{
var vm = new PersonsVM();
vm.Items.Add(new PersonVM { FirstName = "John", LastName = "Scott" });
vm.Items.Add(new PersonVM { FirstName = "Matthew", LastName = "Johnson" });
DataContext = vm;
}
}
}
You can serve the view different VMs and it will render different things based on this. In my example there is a DataGrid for both VM types but it could have been more different.
Upvotes: 3