WPF如何在windows(MVVM)之间传输数据?
我知道有很多类似的问题,到目前为止,我花了两个小时试图实现它们,但无法继续。所以问题似乎很简单。当我没有viewmodel时,我可以将datacontext设置为一个类,使用该类传输数据非常容易。但是当存在viewmodel时,我必须将datacontext设置为该值,并且找不到在该值之后返回任何值的方法。我试图实施无数解决问题的方案,但它们似乎超出了我的技能水平。非常感谢你的帮助 我的代码的重要部分(这是一个简单的游戏,我想保存,其中保存由userinput命名)是第一个窗口,我想从第二个窗口获取数据WPF如何在windows(MVVM)之间传输数据?,wpf,mvvm,Wpf,Mvvm,我知道有很多类似的问题,到目前为止,我花了两个小时试图实现它们,但无法继续。所以问题似乎很简单。当我没有viewmodel时,我可以将datacontext设置为一个类,使用该类传输数据非常容易。但是当存在viewmodel时,我必须将datacontext设置为该值,并且找不到在该值之后返回任何值的方法。我试图实施无数解决问题的方案,但它们似乎超出了我的技能水平。非常感谢你的帮助 我的代码的重要部分(这是一个简单的游戏,我想保存,其中保存由userinput命名)是第一个窗口,我想从第二个窗口
case Key.Escape: {
Thread t = new Thread(() => {
SaveGameWindow pw = new SaveGameWindow(); //the second window
if ((pw.ShowDialog() == true) && (pw.Name != string.Empty)) //pw.Name always empty
{
ILogicSaveGame l = new LogicSaveGame();
l.Write(pw.Name, "saved_games.txt");
MessageBox.Show("game saved");
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
XAML(从现在起,一切都属于SaveGameWindow):
视图模型
public class SaveGameViewModel : ViewModelBase
{
public SaveGameViewModel()
{
this.CloseCommand = new RelayCommand(() => this.Close());
}
public string Name { get; set; }
public ICommand CloseCommand { get; private set; }
public Action CloseAction { get; set; }
private void Close()
{
this.CloseAction();
}
}
我使用galasoft mvvmlightlibs这个问题有很多解决方案。最简单的解决方案是对windows和数据绑定使用共享视图模型。由于两个窗口将共享相同的
DataContext
,因此两个窗口都可以通过引用其DataContext
属性来访问相同的数据或模型实例
但是,如果您更喜欢使用单独的视图模型,则可以选择不同的解决方案
解决方案1
如果要为每个窗口使用专用的视图模型,可以始终使用合成,并使实例SaveGameViewModel
成为MainWindowViewModel
的成员。任何可以访问MainWindowViewModel
的类也可以直接或通过委托属性访问SaveGameViewModel
及其API。此示例通过将
SaveGameViewModel
公开为MainWindowViewModel
的公共属性来使用直接访问:
SaveGameViewModel.cs
public class SaveGameViewModel : INotifyPropertyChanged
{
private string name;
public string Name
{
get => this.name;
set
{
this.name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainWindowViewModel : INotifyPropertyChanged
{
public SaveGameViewModel SaveGameViewModel { get; set; }
// Allow to create an instance using XAML
public MainWindowViewModel() {}
// Allow to create an instance using C#
public MainWindowViewModel(SaveGameViewModel saveGameViewModel)
=> this.SaveGameViewModel = saveGameViewModel;
}
partial class MainWindow : Window
{
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
var mainWindowViewModel = this.DataContext as MainWindowViewModel;
string saveGameName = mainWindowViewModel.SaveGameViewModel.Name;
}
}
}
partial class MainWindow : Window
{
private SaveGameViewModel CurrentSaveGameViewModel { get; set; }
private bool IsSaveGameValid { get; set; }
private void ShowDialog_OnSaveButtonClick(object sender, RoutedEventArgs e)
{
var saveGameDialog = new SaveGameWindow();
this.IsSaveGameValid = saveGameDialog.ShowDialog ?? false;
this.CurrentSaveGameViewModel = saveGameDialog.DataContext as SaveGameViewModel;
}
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape && this.IsSaveGameValid)
{
string saveGameName = this.CurrentSaveGameViewModel.Name;
}
}
}
MainWindowViewModel.cs
public class SaveGameViewModel : INotifyPropertyChanged
{
private string name;
public string Name
{
get => this.name;
set
{
this.name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainWindowViewModel : INotifyPropertyChanged
{
public SaveGameViewModel SaveGameViewModel { get; set; }
// Allow to create an instance using XAML
public MainWindowViewModel() {}
// Allow to create an instance using C#
public MainWindowViewModel(SaveGameViewModel saveGameViewModel)
=> this.SaveGameViewModel = saveGameViewModel;
}
partial class MainWindow : Window
{
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
var mainWindowViewModel = this.DataContext as MainWindowViewModel;
string saveGameName = mainWindowViewModel.SaveGameViewModel.Name;
}
}
}
partial class MainWindow : Window
{
private SaveGameViewModel CurrentSaveGameViewModel { get; set; }
private bool IsSaveGameValid { get; set; }
private void ShowDialog_OnSaveButtonClick(object sender, RoutedEventArgs e)
{
var saveGameDialog = new SaveGameWindow();
this.IsSaveGameValid = saveGameDialog.ShowDialog ?? false;
this.CurrentSaveGameViewModel = saveGameDialog.DataContext as SaveGameViewModel;
}
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape && this.IsSaveGameValid)
{
string saveGameName = this.CurrentSaveGameViewModel.Name;
}
}
}
App.xaml
<Application>
<Application.Resources>
<MainWindowViewModel x:Key="MainWindowViewModel">
<MainWindowViewModel.SaveGameViewModel>
<SaveGameViewModel />
</MainWindowViewModel.SaveGameViewModel>
</MainWindowViewModel>
</Application.Resources>
</Application>
<Window DataContext="{Binding Source={StaticResource MainWindowViewModel}, Path=SaveGameViewModel}">
<TextBox Text="{Binding Name}" />
<Window>
<Window DataContext="{StaticResource MainWindowViewModel}">
<Window>
<Window>
<Window.DataContext>
<MainWindowViewModel />
</Window.DataContext>
<Window>
<Window>
<Window.DataContext>
<SaveGameViewModel />
</Window.DataContext>
<TextBox Text="{Binding Name}" />
<Window>
解决方案2 由于您只是显示一个对话框,因此可以在对话框关闭后存储
SaveGameViewModel
的当前实例或其感兴趣的值:
MainWindow.xaml.cs
public class SaveGameViewModel : INotifyPropertyChanged
{
private string name;
public string Name
{
get => this.name;
set
{
this.name = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainWindowViewModel : INotifyPropertyChanged
{
public SaveGameViewModel SaveGameViewModel { get; set; }
// Allow to create an instance using XAML
public MainWindowViewModel() {}
// Allow to create an instance using C#
public MainWindowViewModel(SaveGameViewModel saveGameViewModel)
=> this.SaveGameViewModel = saveGameViewModel;
}
partial class MainWindow : Window
{
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
var mainWindowViewModel = this.DataContext as MainWindowViewModel;
string saveGameName = mainWindowViewModel.SaveGameViewModel.Name;
}
}
}
partial class MainWindow : Window
{
private SaveGameViewModel CurrentSaveGameViewModel { get; set; }
private bool IsSaveGameValid { get; set; }
private void ShowDialog_OnSaveButtonClick(object sender, RoutedEventArgs e)
{
var saveGameDialog = new SaveGameWindow();
this.IsSaveGameValid = saveGameDialog.ShowDialog ?? false;
this.CurrentSaveGameViewModel = saveGameDialog.DataContext as SaveGameViewModel;
}
private void OnKeyPressed(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape && this.IsSaveGameValid)
{
string saveGameName = this.CurrentSaveGameViewModel.Name;
}
}
}
main window.xaml
<Application>
<Application.Resources>
<MainWindowViewModel x:Key="MainWindowViewModel">
<MainWindowViewModel.SaveGameViewModel>
<SaveGameViewModel />
</MainWindowViewModel.SaveGameViewModel>
</MainWindowViewModel>
</Application.Resources>
</Application>
<Window DataContext="{Binding Source={StaticResource MainWindowViewModel}, Path=SaveGameViewModel}">
<TextBox Text="{Binding Name}" />
<Window>
<Window DataContext="{StaticResource MainWindowViewModel}">
<Window>
<Window>
<Window.DataContext>
<MainWindowViewModel />
</Window.DataContext>
<Window>
<Window>
<Window.DataContext>
<SaveGameViewModel />
</Window.DataContext>
<TextBox Text="{Binding Name}" />
<Window>
SaveGameWindow.xaml
<Application>
<Application.Resources>
<MainWindowViewModel x:Key="MainWindowViewModel">
<MainWindowViewModel.SaveGameViewModel>
<SaveGameViewModel />
</MainWindowViewModel.SaveGameViewModel>
</MainWindowViewModel>
</Application.Resources>
</Application>
<Window DataContext="{Binding Source={StaticResource MainWindowViewModel}, Path=SaveGameViewModel}">
<TextBox Text="{Binding Name}" />
<Window>
<Window DataContext="{StaticResource MainWindowViewModel}">
<Window>
<Window>
<Window.DataContext>
<MainWindowViewModel />
</Window.DataContext>
<Window>
<Window>
<Window.DataContext>
<SaveGameViewModel />
</Window.DataContext>
<TextBox Text="{Binding Name}" />
<Window>