Я использую следующие статьи для начального кода:
Навигация между представлениями в WPF MVVM
Интеграция с простым инжектором WPF
Цель:
Попытка перейти от представления 1 к представлению 2 в форме WPF с помощью команды привязки кнопки и простого инжектора для внедрения зависимостей в представления. Примечание. Эти зависимости являются репозиториями, в которых хранятся данные из внешних источников.
Проблема:
После внедрения зависимостей в мои MainWindow и MainWindowViewModel с помощью Simple Injector мои кнопки больше не меняют мое текущее представление (на другое из моих представлений). При использовании Visual Studio и отладке с использованием точек останова код кажется застрявшим в цикле навсегда в функции CanExecute
файла RelayCommand.cs (см. Навигация между представлениями в WPF MVVM ), где что-то вызывает его снова и снова. Я не могу отладить больше в функции CanExecute
, потому что передается много кода (из DLL и тому подобного). Когда точки останова не используются, это выглядит так, как будто моя кнопка ничего не делает.
Я не получаю сообщения об ошибках в окне вывода, и никакие исключения не генерируются. Привязка команды работает, потому что я вижу функцию OnGo2Screen
, найденную в MainWindowViewModel.cs, вызываемую при отладке. После вызова OnGo2Screen
он перемещается по коду, как и ожидалось, пока не застрянет в CanExecute
.
Что я пробовал
Я проверил контекст данных моего MainWindow и вижу, что он имеет все правильные функции.
Я сделал отдельный проект для статьи Навигация между представлениями в WPF MVVM , и мне удалось добиться отличного изменения представлений. Но всякий раз, когда я пытаюсь использовать Simple Injector, мои кнопки ломаются.
Я заметил, что когда не используется Simple Injector, код перемещается из функции CanExecute
в CanExecuteChanged
EventHandler и выполняет удаление и добавление мутаторов, а затем изменяет представление должным образом. Однако при использовании простого инжектора это не выполняется.
Код
Я использую мой App.xaml.cs в качестве программы запуска, в которой мой App.xaml имеет действие «Страница».
SimulationCaseView - это вид 1 (начальный вид по умолчанию).
StreamsView - это представление 2 (просто другое представление).
UserControl3 - это представление 3 (просто другое представление).
Ниже мой код. Обратитесь к двум ссылкам, предоставленным для любого оставшегося кода, так как на этом я основал множество функций.
App.xaml
<Application x:Class="MyApp.Desktop.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:MyApp.Desktop.Views">
<Application.Resources>
<DataTemplate DataType="{x:Type views:SimulationCaseViewModel}">
<views:SimulationCaseView />
</DataTemplate>
<DataTemplate DataType="{x:Type views:StreamsViewModel}">
<views:StreamsView />
</DataTemplate>
<DataTemplate DataType="{x:Type views:UserControl3ViewModel}">
<views:UserControl3 />
</DataTemplate>
</Application.Resources>
</Application>
App.xaml.cs
namespace MyApp.Desktop
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
App()
{
InitializeComponent();
}
[STAThread]
static void Main()
{
var container = Bootstrap();
// Any additional other configuration, e.g. of your desired MVVM toolkit.
RunApplication(container);
}
private static Container Bootstrap()
{
// Create the container as usual.
var container = new Container();
// Register your types, for instance:
container.Register<IPreferencesRepository, PreferencesRepository>(Lifestyle.Singleton);
container.Register<IStreamRepository, StreamRepository>(Lifestyle.Singleton);
// Register your windows and view models:
container.Register<MainWindow>();
container.Register<MainWindowViewModel>();
container.Verify();
return container;
}
private static void RunApplication(Container container)
{
try
{
var app = new App();
var mainWindow = container.GetInstance<MainWindow>();
MainWindowViewModel viewModel = container.GetInstance<MainWindowViewModel>();
mainWindow.DataContext = viewModel;
app.Run(mainWindow);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
MainWindow.xaml
<Window x:Class="MyApp.Desktop.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyApp.Desktop"
mc:Ignorable="d"
Title="MainWindow"
Height="350" Width="525"
xmlns:views="clr-namespace:MyApp.Desktop.Views">
<Grid>
<ContentControl Content="{Binding CurrentPageViewModel}" />
</Grid>
</Window>
MainWindowViewModel.cs
namespace MyApp.Desktop.Views
{
public class MainWindowViewModel : BaseViewModel
{
private IPageViewModel _currentPageViewModel;
private List<IPageViewModel> _pageViewModels;
public List<IPageViewModel> PageViewModels
{
get
{
if (_pageViewModels == null)
_pageViewModels = new List<IPageViewModel>();
return _pageViewModels;
}
}
public IPageViewModel CurrentPageViewModel
{
get
{
return _currentPageViewModel;
}
set
{
_currentPageViewModel = value;
OnPropertyChanged("CurrentPageViewModel");
}
}
private void ChangeViewModel(IPageViewModel viewModel)
{
if (!PageViewModels.Contains(viewModel))
PageViewModels.Add(viewModel);
CurrentPageViewModel = PageViewModels
.FirstOrDefault(vm => vm == viewModel);
}
private void OnGo1Screen(object obj)
{
ChangeViewModel(PageViewModels[0]);
}
private void OnGo2Screen(object obj)
{
ChangeViewModel(PageViewModels[1]);
}
private void OnGo3Screen(object obj)
{
ChangeViewModel(PageViewModels[2]);
}
public MainWindowViewModel(IStreamRepository streamRepository)
{
// Add available pages and set page
PageViewModels.Add(new SimulationCaseViewModel(streamRepository));
PageViewModels.Add(new StreamsViewModel());
PageViewModels.Add(new UserControl3ViewModel());
CurrentPageViewModel = PageViewModels[0];
Mediator.Subscribe("GoTo1Screen", OnGo1Screen);
Mediator.Subscribe("GoTo2Screen", OnGo2Screen);
Mediator.Subscribe("GoTo3Screen", OnGo3Screen);
}
}
}
SimulationCaseView.xaml
<UserControl x:Class="MyApp.Desktop.Views.SimulationCaseView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyApp.Desktop"
mc:Ignorable="d"
d:DesignHeight="280" d:DesignWidth="280">
<Grid>
<Button
Content="Go to Streams"
Command="{Binding GoTo2}"
Width="90" Height="30" Margin="166,220,24,30">
</Button>
</Grid>
</UserControl>
SimulationCaseViewModel.cs
namespace MyApp.Desktop.Views
{
public class SimulationCaseViewModel : BaseViewModel, IPageViewModel
{
private ICommand _goTo2;
private readonly IStreamRepository _repo;
public SimulationCaseViewModel(IStreamRepository repo)
{
_repo = repo;
Application application = _repo.GetApplicationReference();
CurrentSimulationCases = new ObservableCollection<SimulationCase>();
Streams = new ObservableCollection<object>();
foreach (SimulationCase simulationCase in application.SimulationCases)
{
CurrentSimulationCases.Add(simulationCase);
}
//FetchStreams = new RelayCommand(OnFetch);
}
public ObservableCollection<SimulationCase> CurrentSimulationCases { get; set; }
public ObservableCollection<object> Streams { get; private set; }
public ICommand GoTo2
{
get
{
return _goTo2 ?? (_goTo2 = new RelayCommand(x =>
{
Mediator.Notify("GoTo2Screen", "");
}));
}
}
}
}
Любая помощь относительно того, почему кнопки не работают, приветствуется. Спасибо.