Вы не можете сделать это без отражения. Однако вы можете делать это с отражением. Вот полный пример:
using System;
using System.Reflection;
public class Generic<T>
{
public Generic()
{
Console.WriteLine("T={0}", typeof(T));
}
}
class Test
{
static void Main()
{
string typeName = "System.String";
Type typeArgument = Type.GetType(typeName);
Type genericClass = typeof(Generic<>);
// MakeGenericType is badly named
Type constructedClass = genericClass.MakeGenericType(typeArgument);
object created = Activator.CreateInstance(constructedClass);
}
}
Примечание: если ваш универсальный класс принимает несколько типов, вы должны включать запятые, когда вы опускаете имена типов, например:
Type genericClass = typeof(IReadOnlyDictionary<,>);
Type constructedClass = genericClass.MakeGenericType(typeArgument1, typeArgument2);
Вы бы сделали это в родительской ViewModel.
Например, если ваша страница (назовите ее PageViewModel
) имела два вида (ViewModelA
и ViewModelB
), у вас будет свойство на PageViewModel
с именем CurrentView
, и это будет определять, какой вид является видимый. Когда PageViewModel.CurrentView
установлен на экземпляр ViewModelA
, тогда DataTemplate ViewA используется для рисования контента. Когда он установлен на экземпляр ViewModelB
, отображается DataTemplate ViewB.
<DataTemplate DataType="{x:Type local:PageViewModel}">
<ContentControl Content="{Binding CurrentView}" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelA}">
<TextBlock Text="I'm ViewModelA" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelB}">
<TextBlock Text="I'm ViewModelB" />
</DataTemplate>
Было бы идеально вызывать команду переключения представлений из родительского представления (в данном случае DataTemplate для PageViewModel
), однако, если вы хотите переключить представления из ViewModelA / B, вы можете либо подключить поднимите событие вручную, когда объекты будут созданы (CurrentView.ChangeViewCommand = this.ChangeViewCommand
), или загляните в систему обмена сообщениями. MVVM Light имеет простой Messenger
класс, который, как я обнаружил, довольно прост в использовании, или Prism имеет более продвинутый EventAggregator
. Если вы хотите переключить виды для одной и той же ViewModel, я бы порекомендовал свойство Mode. который используется, чтобы определить, какой вид использовать. Например:
<DataTemplate x:Key="ViewA" DataType="{x:Type local:MyViewModel}">
<TextBlock Text="I'm ViewModelA" />
</DataTemplate>
<DataTemplate x:Key="ViewB" DataType="{x:Type local:MyViewModel}">
<TextBlock Text="I'm ViewModelB" />
</DataTemplate>
<DataTemplate DataType="{x:Type local:MyViewModel}">
<ContentControl Content="{Binding }">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource ViewA}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Mode}" Value="2">
<Setter Property="ContentTemplate" Value="{StaticResource ViewB}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
РЕДАКТИРОВАТЬ
Я на самом деле вижу, что такого рода вопросы часто возникают, поэтому разместил что-то об этом здесь , если всем интересно