2015-11-15 2 views
0

Попытка сделать мой первый MarkupExtension, как локатором и использовать его, чтобы получить DataContext в моем XAML:Как вернуть сильно типизированный объект из MarkupExtension?

ViewModel & Интерфейс

public interface IMainViewModel 
{ 
    ICommand OpenProjectCommand { get; } 
} 

public class MainViewModel : IMainViewModel 
{ 
    public ICommand OpenProjectCommand { get; private set; } 
    ... 
} 

Service Locator:

public static class ServiceLocator 
{ 
    public static void Map<T>(object concreteType) 
    { 
     // store type 
    } 

    public static T GetInstance<T>() where T : class 
    { 
     // get, instantiate and return 
    } 
} 

App .xaml

protected override void OnStartup(StartupEventArgs e) 
{ 
    ServiceLocator.Map<IMainViewModel>(typeof(MainViewModel)); 
    base.OnStartup(e); 
} 

MarkupExtension:

public class ServiceLocatorExtension : MarkupExtension 
{ 
    public Type ServiceType { get; set; } 

    public ServiceLocatorExtension(Type type) 
    { 
     ServiceType = type; 
    } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (ServiceType == null) 
      throw new ArgumentException("Type argument is not specified"); 

     var instance = ServiceLocator.GetInstance<IMainViewModel>(); // how to use this.ServiceType? 
     return instance; 
    } 
} 

XAML:

<Window ... DataContext="{loc:ServiceLocator {x:Type loc:IMainViewModel}}"> 
... 
<Button ... Command="{Binding OpenProjectCommand}"/> // problem complains cannot resolve in datacontext type of "object" 

Вопросы:

1) Как я могу использовать this.ServiceType недвижимость в MarkupExtension вместо явного интерфейса?

2) Привязка команды к кнопке в XAML жалуется, что она не может решить из datacontext объекта типа, поэтому я получаю предупреждение, которое я не хочу. Как я знаю, что это правильный тип?

+1

Выглядит как создание не-родовое Метод GetInstance (тип типа) упростит вашу жизнь, в зависимости от того, как именно реализуется «GetInstance». В этом случае вам не нужен общий вариант, так как «ProvideValue» все равно возвращает «объект». Что касается второй проблемы, если вы получите это предупреждение, тогда контекст данных не является «MainViewModel». Система привязки смотрит на фактический тип времени выполнения объекта. –

ответ

0

Не уверен, что это лучшее решение, ища альтернативы.

1:

С помощью отражения:

public override object ProvideValue(IServiceProvider serviceProvider) 
{ 
    if (ServiceType == null) 
     throw new ArgumentException("Type argument is not specified"); 

    var serviceLocatorMethod = typeof(ServiceLocator).GetMethod("GetInstance").MakeGenericMethod(ServiceType); 
    return serviceLocatorMethod.Invoke(null, null); 
} 

2:

Как сво дизайнер вопрос, это решает проблему:

d:DataContext="{d:DesignInstance loc:MainViewModel}" 
Смежные вопросы