Этот вопрос является логическим продолжеием этого вопроса.
Я попытался реализовать схему, изложенную здесь , но программа не работает.
Я опишу свои шаги по реализации схемы по второй ссылке, и буду цитировать шаги оттуда со своим кодом. Цитаты выделены курсивом.
Положите в App.xaml
шаблоны, привязывающие VM к UserControl
'ам:
<Application x:Class="PresentationLayer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PresentationLayer"
xmlns:vm="clr-namespace:PresentationLayer.WPFViewModels"
xmlns:view="clr-namespace:PresentationLayer.Views"
StartupUri="StartWindow.xaml">
<Application.Resources>
<DataTemplate DataType="{x:Type vm:StartPageVM}">
<view:StartPage/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:FLPPage1VM}">
<view:FLPPage1></view:FLPPage1>
</DataTemplate>
</Application.Resources>
Заведите в главной VM свойство `ActivePage`, в начале присвойте ему экземпляр `StartPageVM`...
public class MainVM : BaseVM
{
public static BaseVM ActivePage { get; set; }
public MainVM()
{
ActivePage = new StartPageVM();
}
}
Здесь все работает. При запуске программы меня автоматически перебрасывает на StartPage
с таким кодом:
<UserControl x:Class="PresentationLayer.Views.StartPage"
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:PresentationLayer.Views"
xmlns:vm="clr-namespace:PresentationLayer.WPFViewModels"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="500">
<UserControl.DataContext>
<vm:StartPageVM></vm:StartPageVM>
</UserControl.DataContext>
<Grid Background="LightGray">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" FontSize="16" Foreground="DarkGreen" FontWeight="Bold" Command="{Binding FLPStartCommand}">
<TextBlock HorizontalAlignment="Center" TextWrapping="Wrap">Регистрационные действия ФЛП</TextBlock>
</Button>
<Button Grid.Column="1" FontSize="16" Foreground="DarkGreen" FontWeight="Bold" IsEnabled="False" Command="{Binding SettingsCommand}">
<TextBlock HorizontalAlignment="Center" TextWrapping="Wrap">Настройки </TextBlock>
</Button>
</Grid>
Соответствующая VM
public class StartPageVM : BaseVM
{
public BaseVM ActivePage { get; set; }
public ICommand FLPStartCommand { get; set; }
public ICommand SettingsCommand { get; set; }
public StartPageVM()
{
FLPStartCommand = new RelayCommand(x => FLPStartMethod());
SettingsCommand = new RelayCommand(x => SettingsMethod());
}
private void FLPStartMethod()
{
MainVM.ActivePage = new FLPPage1VM();
//OnPropertyChanged("PresentationLayer.WPFViewModels.MainVM.ActivePage");
}
private void SettingsMethod()
{
}
}
для переключения на первую страницу присвойте экземпляр FLPPage1VM
и т. д
Я ожидаю, что при нажатии на кнопку меня перебросит на страницу FLPPage1
. Однако, программа на нажатbе кнопки не реагирует. Что я сделал не так? Если раскомментировать вызов OnPropertyChanged
ничего не меняется.
Код FLPPage1
и FLPPage1VM
:
<UserControl x:Class="PresentationLayer.Views.FLPPage1"
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:PresentationLayer.Views"
xmlns:vm ="clr-namespace:PresentationLayer.WPFViewModels"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<vm:FLPPage1VM></vm:FLPPage1VM>
</UserControl.DataContext>
<Grid Background="Aquamarine">
<TextBlock>PAGE FLP1</TextBlock>
</Grid>
VM пустая пока, но приведу для полноты картины:
public class FLPPage1VM: BaseVM
{
FLPCompleteEntity FLP { get; set; }
}
Для справки:
Класс VMBase
Брал с предыдущего проекта, должен быть рабочий:
public class BaseVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Класс RelayCommand
(тоже с предыдущего проекта)
public class RelayCommand:ICommand
{
public Predicate<object> CanExecuteDelegate { get; set; }
public Action<object> ExecuteDelegate { get; set; }
public RelayCommand(Action<object> action)
{
ExecuteDelegate = action;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
if (CanExecuteDelegate != null)
{
return CanExecuteDelegate(parameter);
}
return true;
}
public void Execute(object parameter)
{
if (ExecuteDelegate != null)
{
ExecuteDelegate(parameter);
}
}
}
У вас неверно реализован интерфейс INotifyPropertyChanged
. Вы должны отправлять NotifyPropertyChanged
, а имя свойства не должно содержать «пути» к свойству. Причём отправлять NotifyPropertyChanged
должен именно тот объект, в котором меняется свойство. А также, это самое свойство не должно быть статическим.
Я бы посоветовал реализовать это так:
// https://ru.stackoverflow.com/a/632894/10105
class BaseVM : INotifyPropertyChanged
{
protected bool Set<T>(ref T field, T value,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
NotifyPropertyChanged(propertyName);
return true;
}
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler PropertyChanged;
}
public class MainVM : BaseVM
{
BaseVM activePage;
public BaseVM ActivePage
{
get => activePage;
set => Set(ref activePage, value);
}
public MainVM()
{
ActivePage = new StartPageVM();
}
}
При этом нужное имя отправляется в событие PropertyChanged
автоматически (посредством «волшебного» атрибута CallerMemberName
).
Следующая ошибка — задание DataContext
внутри контрола. Это неправильно. Во-первых, вы уже и так задаёте DataContext
снаружи, а значит, внешний DataContext
будет проигнорирован, хотя как раз он у вас правильно связан с другими VM. А во-вторых, с точки зрения MVVM у View нет прав определять свой DataContext
.
Просто уберите
<UserControl.DataContext>
...
</UserControl.DataContext>
из кода.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Обьясните, пожалуйста, максимально простыми словами, в чем же разница между [InverseProperty] и [ForeignKey], ведь оба атрибута устанавливают однозначную...
Всем приветСтоит задача получить название вводимого адреса сайта в адресную строку браузера