【问题标题】:WPF how to transfer data between windows (MVVM)?WPF如何在windows(MVVM)之间传输数据?
【发布时间】:2020-07-30 20:10:47
【问题描述】:

我知道有很多类似的问题,我花了两个小时尝试实施它们,但无法继续。所以问题看起来很简单。当我没有视图模型时,我可以将数据上下文设置为一个类,并且使用该类传输数据非常容易。但是当有 viewmodel 时,我必须将 datacontext 设置为那个,然后找不到返回任何值的方法。我试图为这个问题实施无数的解决方案,但似乎它们超出了我的技能水平。非常感谢您的帮助!

我的代码的重要部分(它是一个我要保存的简单游戏,其中保存由用户输入命名)第一个窗口,我想从第二个窗口获取数据

             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):

 <Window.Resources>
    <local:SaveGameViewModel x:Key="my_viewmodel"/>
</Window.Resources>
<Grid DataContext="{StaticResource my_viewmodel}">
 <TextBox Text="{Binding Name}"/> //i want to acces this in the first window
  <Button Command="{Binding CloseCommand}"
                Content="Save"/>

后面的代码:

    private readonly SaveGameViewModel vm;
    public SaveGameWindow()
    {
        this.InitializeComponent();
        this.vm = this.FindResource("my_viewmodel") as SaveGameViewModel;
        if (this.vm.CloseAction == null)
        {
            this.vm.CloseAction = new Action(() => this.Close());
        }
    }

视图模型

 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

【问题讨论】:

    标签: wpf mvvm


    【解决方案1】:

    这个问题有很多解决方案。最简单的解决方案是对窗口和数据绑定使用共享视图模型。由于两个窗口将共享相同的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));
      }
    }
    

    MainWindowViewModel.cs

    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; 
    }
    

    App.xaml

    <Application>
      <Application.Resources>
        <MainWindowViewModel x:Key="MainWindowViewModel">
          <MainWindowViewModel.SaveGameViewModel>
            <SaveGameViewModel />
          </MainWindowViewModel.SaveGameViewModel>
        </MainWindowViewModel>
      </Application.Resources>
    </Application>
    

    SaveGameWindow.xaml

    <Window DataContext="{Binding Source={StaticResource MainWindowViewModel}, Path=SaveGameViewModel}">
      <TextBox Text="{Binding Name}" />
    <Window>
    

    MainWindow.xaml

    <Window DataContext="{StaticResource MainWindowViewModel}">
    
    <Window>
    

    MainWindow.xaml.cs

    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;
        }
      }
    }
    

    解决方案 2

    由于您只是显示一个对话框,因此您可以在对话框关闭后存储SaveGameViewModel 的当前实例或其感兴趣的值:

    MainWindow.xaml.cs

    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;
        }
      }
    }
    

    MainWindow.xaml

    <Window>
      <Window.DataContext>
        <MainWindowViewModel />
      </Window.DataContext>
    <Window>
    

    SaveGameWindow.xaml

    <Window>
      <Window.DataContext>
        <SaveGameViewModel />
      </Window.DataContext>
    
      <TextBox Text="{Binding Name}" />
    <Window>
    

    【讨论】:

      猜你喜欢
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-15
      • 2015-09-23
      • 1970-01-01
      相关资源
      最近更新 更多