Я сделал быстрый демонстрационный пример, чтобы показать один из способов сделать это. Я старался как можно проще дать общую идею. Существует много разных способов решения одной и той же задачи (например, вы можете сохранить ссылку на MainWindowViewModel
внутри LoginViewModel
, обрабатывать все там, затем вызвать метод на MainWindowViewModel
, чтобы вызвать изменение рабочей области или вы могли использовать события/сообщения и т. Д.).
Определенно читайте Navigation with MVVM. Это действительно хорошее введение, которое я нашел полезным, когда я начинал с него.
Ключевое значение, которое следует убрать, состоит в том, чтобы иметь внешний MainWindowViewModel
или ApplicationViewModel
, который обрабатывает навигацию, содержит ссылки на рабочие области и т. Д. Тогда выбор того, как вы взаимодействуете с этим, зависит от вас.
В нижеследующем коде я оставил беспорядок от определения Window
, UserControl
и т. Д., Чтобы сохранить его короче.
Окно:
<DockPanel>
<ContentControl Content="{Binding CurrentWorkspace}"/>
</DockPanel>
MainWindowViewModel (это должно быть установлено как DataContext
для Window
):
public class MainWindowViewModel : ObservableObject
{
LoginViewModel loginViewModel = new LoginViewModel();
LoggedInViewModel loggedInViewModel = new LoggedInViewModel();
public MainWindowViewModel()
{
CurrentWorkspace = loginViewModel;
LoginCommand = new RelayCommand((p) => DoLogin());
}
private WorkspaceViewModel currentWorkspace;
public WorkspaceViewModel CurrentWorkspace
{
get { return currentWorkspace; }
set
{
if (currentWorkspace != value)
{
currentWorkspace = value;
OnPropertyChanged();
}
}
}
public ICommand LoginCommand { get; set; }
public void DoLogin()
{
bool isValidated = loginViewModel.Validate();
if (isValidated)
{
CurrentWorkspace = loggedInViewModel;
}
}
}
LoginView:
В этом примере я связывании Button
на LoginView
- LoginCommand
на Window
DataContext
(т.е. MainWindowViewModel
).
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding UserName}"/>
<Button Content="Login" Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.LoginCommand}"/>
</StackPanel>
LoginViewModel:
public class LoginViewModel : WorkspaceViewModel
{
private string userName;
public string UserName
{
get { return userName; }
set
{
if (userName != value)
{
userName = value;
OnPropertyChanged();
}
}
}
public bool Validate()
{
if (UserName == "bob")
{
return true;
}
else
{
return false;
}
}
}
LoggedInView:
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding RestrictedData}"/>
</StackPanel>
LoggedInViewModel:
public class LoggedInViewModel : WorkspaceViewModel
{
private string restrictedData = "Some restricted data";
public string RestrictedData
{
get { return restrictedData; }
set
{
if (restrictedData != value)
{
restrictedData = value;
OnPropertyChanged();
}
}
}
}
WorkspaceViewModel:
public abstract class WorkspaceViewModel : ObservableObject
{
}
Тогда некоторые другие классы, которые вы, вероятно, уже реализованы (или альтернативы).
ObservableObject:
public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
}
RelayCommand:
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{ }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return canExecute == null ? true : canExecute(parameter);
}
public void Execute(object parameter)
{
execute(parameter);
}
}
app.xaml:
<DataTemplate DataType="{x:Type ViewModels:LoginViewModel}">
<Views:LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:LoggedInViewModel}">
<Views:LoggedInView />
</DataTemplate>
Я хотел бы предложить вы хотите '' MainWindowViewModel' или ApplicationViewModel', который обрабатывает навигацию и устанавливает текущую 'Workspace' (' LoginViewModel' или 'LoggedInViewModel'). В [Navigation with MVVM] есть хороший пример (https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/). При этом различные представления привязаны к кнопкам, но в вашем случае вы просто хотите, чтобы кнопка входа в систему запускала команду для проверки, а затем переключилась по мере необходимости. (пример кода также имеется там) – Tone
Хорошо, но как бы LoginCommand получить экземпляр ApplicationViewModel для выполнения команды ChangeViewModel? @Tone – Tdorno
'LoginCommand' будет определен в' ApplicationViewModel', а не в 'LoginViewModel' (этот' ApplicationViewModel' будет 'DataContext' для' Window'). – Tone