Похоже, вы создаете несколько экземпляров AppVm
.
Кнопка в View1
и кнопки панели навигации, очевидно, не привязываются к одному и тому же экземпляру AppVm
.
То же применяется к свойству CurrentView
: ваш хост контента связывается с другим экземпляром, т. е. ссылками на значения свойства, отличными от CurrentView
, который вы изменяете в View1
. Поэтому изменение CurrentView
изнутри View1
не влияет на хост содержимого -> представление никогда не меняется.
Убедитесь, что вы всегда ссылаетесь на один и тот же (общий) экземпляр в одном и том же контексте.
Существует несколько способов достижения этого в зависимости от структуры вашего пользовательского интерфейса. Создание Singleton класса модели представления - безусловно, худший выбор. Синглетонов следует и всегда можно избежать.
Самое простое решение - объявить модель представления в качестве ресурса в приложении, xaml ResourceDictionary
:
App.xaml
Ресурсы, определенные в этом файле, доступны глобально в любом контексте XAML с помощью поиска по словарю расширения разметки StaticResource
.
<Application>
<Application.Resources>
<AppVM x:Key="AppVMinView1" />
</Application.Resources>
</Application>
Внутри любого файла XAML (область приложения):
<UserControl>
<UserControl.DataContext>
<View1VM />
</UserControl.DataContext>
<!-- Reference resources defined in App.xaml, using the StaticResource markup extension -->
<Button Command="{Binding Source={StaticResource AppVMinView1}, Path=View2ButtonCommand}" />
</UserControl>
Рекомендованное решение
Также похоже, что вы создаете экземпляры ваших представлений или страниц внутри вашей модели представления (я предполагаю, что new View1(dummy as string)
создает элемент управления, поскольку модель представления называется View1VM
). Работа только с моделями представлений вместо этого также решает вашу проблему более элегантным способом.
Очень важно использовать один экземпляр моделей просмотра страниц, если вы не хотите терять состояние (и данные) при переключении представлений. (Не путайте это с Singleton, который является шаблоном проектирования, который гарантирует, что один экземпляр используется глобально , назначая его свойству static
. Singleton Pattern обычно считается анти-шаблоном .)
Это короткий, но полный пример того, как показывать страницы и перемещаться по ним:
AppVM.cs
// Main view model
class AppVM : ObservableObject
{
// Create a property that controls current view
private ObservableObject _currentView;
public ObservableObject CurrentView
{
get => _currentView;
private set => OnPropertyChanged(ref _currentView, value);
}
private Dictionary<string, ObservableObject> Pages { get; set; }
public AppVM()
{
// Create and store the pages,
// so that the same instances can be reused.
// All pages must extend ObservableObject (or any other common base type).
this.Pages = new Dictionary<string, ObservableObject>()
{
{ nameof(DefaultVM), new DefaultVM() },
{ nameof(View1VM), new View1VM() },
{ nameof(View2VM), new View2VM() },
};
// Initialize first page
this.CurrentView = this.Pages[nameof(DefaultVM)];
this.DefaultCommand = new RelayCommand(param => this.CurrentView = this.Pages[nameof(DefaultVM)], param => true);
this.View1ButtonCommand = new RelayCommand(param => this.CurrentView = this.Pages[nameof(View1VM)], param => true);
this.View2ButtonCommand = new RelayCommand(param => this.CurrentView = this.Pages[nameof(View2VM)], param => true);
}
}
View1.xaml
<!-- DataContext is inherited from the surrounding DataTemplate and is the corresponding page view model -->
<UserControl>
<StackPanel>
<TextBox Text="{Binding View1InfoClass.FirstName}" />
<!--
Bind to the command of the same view model instance,
which is the DataContext of the content host
-->
<Button Content="Show View2"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=MainWindow}, Path=DataContext.View2ButtonCommand}" />
</StackPanel>
</UserControl>
MainWindow.xaml
<Window>
<Window.DataContext>
<AppVM />
</Window.DataContext>
<Window.Resources>
<!-- Define the views as implicit (keyless) DataTemplate -->
<DataTemplate DataType="{x:Type DefaultVM}">
<DefaultView />
</DataTemplate>
<DataTemplate DataType="{x:Type View1VM}">
<View1 />
</DataTemplate>
<DataTemplate DataType="{x:Type View2VM}">
<View2 />
</DataTemplate>
</Window.Resources>
<!--
Host of the pages.
The implicit DataTemplates will apply automatically
and show the control that maps to the current CurrentView view model
-->
<ContentPresenter Content="{Binding CurrentView}" />
</Window>