Всем доброго времени суток. Моя проблема заключается в следующем, как реализовать в WPF переключение между страницами используя MVVM. Переключение должно осуществлять по нажатию кнопки, расположенных слева на изображении.Страниц будет всего лишь шесть, как и кнопок.
Я уже указывал в комментариях на пример своего ответа здесь. Может такой вариант и представляется кому-то рабоче-крестьянским способом, в особенности для любителей девственно чистого кодбихайнд, но я считаю его вполне годным и, самое главное, простым и быстрым в реализации. Ладно, это лирика.
Вот вам другой вариант,
с рефлексией, все дела, как у четких пацанов...:) Это не мой мопед, я чисто его сп... подсмотрел в проекте NAudio. Подход довольно интересный, кстати.
Создаем вот такой интерфейс
public interface IModule
{
/// <summary>
/// Название выводимое в меню
/// </summary>
string Name { get; }
/// <summary>
/// Ссылка на вьюшку
/// </summary>
UserControl UserInterface { get; }
/// <summary>
/// Отключение текущей вьюшки, для вьюмоделей с реализацией IDisposable
/// </summary>
void Deactivate();
}
Далее для каждой пары View & ViewModel создается еще один класс, который реализует этот интерфейс таким образом:
class SeparateDemo : IModule
{
//наша неразлучная парочка
private SeparateDemoView view;
private SeparateDemoViewModel viewModel;
public string Name => "Вьюшка SeparateDemo";
public UserControl UserInterface
{
get { if (view == null) CreateView(); return view; }
}
private void CreateView()
{
//загружаем вьюшку
view = new SeparateDemoView();
//её вьюмодель
viewModel = new SeparateDemoViewModel();
//связываем их между собой
view.DataContext = viewModel;
}
public void Deactivate()
{
viewModel.Dispose();
view = null;
}
}
т.е. это такой загрузчик для пары View & ViewModel. Далее это у нас MainWindow.xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0"
ItemsSource="{Binding Modules}"
SelectedItem="{Binding SelectedModule, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1"
Content="{Binding UserInterface}" />
</Grid>
Это её вьюмодель, которая подгружает и отображает нужную вьюшку
class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
//ctor
public MainWindowViewModel(IEnumerable<IModule> modules)
{
Modules = modules.OrderBy(m => m.Name).ToList();
if (this.Modules.Count > 0)
{
SelectedModule = this.Modules[0];
}
}
//Properties
/// <summary>
/// Список всех возможных загрузчиков пар View и ViewModel
/// </summary>
public List<IModule> Modules { get; private set; }
/// <summary>
/// Выбранная и загруженная парочка View и ViewModel
/// </summary>
private IModule _SelectedModule;
public IModule SelectedModule
{
get { return _SelectedModule; }
set
{
if (value == _SelectedModule) return;
if (_SelectedModule != null) _SelectedModule.Deactivate();
_SelectedModule = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(SelectedModule)));
PropertyChanged(this, new PropertyChangedEventArgs("UserInterface"));
}
}
/// <summary>
/// То, что отображает View через ContentPresenter
/// </summary>
public UserControl UserInterface
{
get
{
if (SelectedModule == null) return null;
return SelectedModule.UserInterface;
}
}
}
А вот теперь самая мякотка - тут без рефлексии не обойтись
static class ReflectionHelper
{
public static IEnumerable<T> CreateAllInstancesOf<T>()
{
return typeof(ReflectionHelper).Assembly.GetTypes()
.Where(t => typeof(T).IsAssignableFrom(t))
.Where(t => !t.IsAbstract && t.IsClass)
.Select(t => (T)Activator.CreateInstance(t));
}
}
Подправляем App.xaml такой строчкой - Startup="Application_Startup">
И тогда App.xaml.cs такой
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
var mainWindow = new MainWindow();
var modules = ReflectionHelper.CreateAllInstancesOf<IModule>();
var vm = new MainWindowViewModel(modules);
mainWindow.DataContext = vm;
mainWindow.Closing += (s, args) => vm.SelectedModule.Deactivate();
mainWindow.Show();
}
}
Вот и все. Как вариант можно сделать промежуточный класс abstract class ModuleBase : IModule и тогда загрузчик пары можно сделать таким
class FirstDemo : ModuleBase
{
public override string Name
{
get { return "Вьюшка FirstDemo"; }
}
protected override UserControl CreateViewAndViewModel()
{
return new FirstDemoView() { DataContext = new FirstDemoViewModel() };
}
}
Весь проект целиком можно скачать здесь.
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости