Мой проект WPF будет организован как это:
Screens
Group1
Screen1
View.xaml
ViewModel.cs
Group2
Screen2
View.xaml
ViewModel.cs
Показать Screen1
от Screen2
Я буду использовать что-то вроде этого: ScreenManager.Show("Group1.Screen1")
Это смотрит (использование отражения) в Screens.Group1.Screen1
пространство имен для Представления и ViewModel и инстанцирует их.
Как я могу устранить волшебную строку без связи Screen1
и Screen2
(Я не хочу классы в Screen2
использовать Screen1
пространство имен). Также я хотел бы некоторое экранное исследование (autocompletion/intellisense)
Или возможно некоторый путь (автоматизируют тест) проверить что все вызовы к ScreenManager.Show
допустимы.
Обновление: Я придумал это:
public class ScreenNames
{
public Group1Screens Group1;
public class Group1Screens
{
public ScreenName Screen1;
}
}
public sealed class ScreenName
{
private ScreenName() { }
}
public class ScreenManager : IScreenManager
{
public void Show(Expression<Func<ScreenNames, ScreenName>> x) {}
}
Использование:
screenManager.Show(x=>x.Group1.Screen1);
Не идеальный, но я предполагаю нарушение, DRY еще лучше, чем волшебные строки. И я могу автоматически протестировать (с отражением), что все вызовы допустимы.
Наконец, я использовал генерацию кода T4 для создания моего класса ScreenNames
. Я сделал это, адаптировав этот код: Автоматически создавать строго типизированный класс навигации для всех пользовательских элементов управления в веб-приложении ASP.NET
Вам не нужен весь этот ScreenManager в WPF, потому что механизм DataTemplate может позаботиться об этом за вас с помощью чистой разметки.
Вы можете просто привязать данные к определенной области вашего приложения с помощью ContentPresenter и набора DataTemplates. Свяжите область со свойством «корневой» ViewModel и позвольте «корневой» ViewModel реализовать INotifyPropertyChanged, чтобы WPF знал, измените ли вы ViewModel в этой области.
public class RootViewModel : INotifyPropertyChanged
{
public object Screen1ViewModel { get; }
public object Screen2ViewModel { get; }
}
Свяжите один элемент управления ContentPresenter со свойством Screen1ViewModel, используя
<ContentControl Content="{Binding Path=Screen1ViewModel}" />
и аналогично для следующего. Когда вам нужно изменить содержимое Screen1, вы просто повторно назначаете Screen1ViewModel из кода, и из-за возникшего события PropertyChanged WPF подберет его и привяжет новую ViewModel к новому View.
Шаблоны данных могут быть такими простыми:
<Window.Resources>
<DataTemplate DataType="{x:Type foo:MyViewModel}">
<self:MyControl />
</DataTemplate>
<DataTemplate DataType="{x:Type foo:MyOtherViewModel}">
<self:MyOtherControl />
</DataTemplate>
</Window.Resources>
Если вы не знакомы с ним, эта статья о MVVM в WPF является отличным введением.