【问题标题】:C# Two Forms accessing the same class dataC# 两个表单访问相同的类数据
【发布时间】:2011-02-06 01:23:34
【问题描述】:

我正在使用 MS Visual C# 2010。

我创建了 2 个 WPF 表单,MainWindow.xaml 和 CreateCharacter.xaml。我做了 Project->Add Class... 添加一个名为 Hero.cs 的空类。 Hero 类将保存玩家姓名和其他重要数据。

在 MainWindow.xaml.cs 中,我创建了 Hero 类的实例:Hero player = new Hero();。我单击 MainWindow 上的一个按钮,它会打开 CreateCharacter 表单。在 CreateCharacter 表单上,我想输入玩家姓名并将此数据存储在 player.name 中,该名称已在 MainWindow 中实例化。

如何使我在 MainWindow 类中创建的 Hero 对象可用于 CreateCharacter 类?

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    如果 CreateCharacter 表单正在创建一个角色,那么它也许应该创建 Hero 实例。它可以在 CreateCharacter 表单成功返回后,在主表单可以读取的公共属性中返回它。

    【讨论】:

      【解决方案2】:

      这可能是互联网论坛上最常见的问题之一。
      我建议您在深入研究 GUI 编程之前先熟悉面向对象编程,以便了解基本概念。

      要将对象传递给另一个窗口,您可以添加一个特殊的构造函数,将其作为参数接受,并添加一个属性或字段来保存它(取决于您是否要使其可访问):

      partial class CreateCharacterWindow : Window {
          private Character character;
      
          public CreateCharacterWindow ()
              : this (null) { } // designer requires parameterless constructor
      
          public CreateCharacterWindow (Character character)
          {
              this.character = character;
              InitializeComponent ();
          }
      }
      
      var spiderman = new Character ();
      var charWindow = new CreateCharacterWindow (spiderman);
      

      我碰巧不喜欢这种方法。

      您打算在即将显示的窗口中创建角色似乎是合乎逻辑的。在显示窗口之前创建对象有什么意义? 我认为实际实例化CharacterCreateCharacterWindow 的责任,因为它最了解它的属性,而且无论如何在用户按下创建 之前使用虚拟字符是没有意义的> 按钮或类似的东西,如果你不打算使用数据绑定。

      如果您确实打算使用数据绑定,请在 CreateCharacterWindow 中创建一个公共只读 Character 属性,以便 MainWindow 可以访问它,在构造函数中实例化它,将实例分配给 DataContext 对象并连接 UI 控件和 XAML 标记中的对象属性。

      但在这种情况下我也不会使用数据绑定。

      我要做的是使用ShowModal 方法以模态方式显示CreateCharacterWindow。在此类中,如果用户选择实际创建角色(例如,与按取消按钮相反),我会将 this.DialogResult 设置为 true

      ShowModal 将返回我们分配给DialogResult 的值,因此MainWindow 知道用户是否真的想要创建角色。如果是这样,我们最后要求CreateCharacterWindow创建Character实例:

      partial class CreateCharacterWindow : Window {
      
          public CreateCharacterWindow ()
          {
              InitializeComponent ();
              createButton.Click += (sender, e) => {
                  this.DialogResult = true;
                  this.Close ();
              };
          }
      
          public Character CreateCharacter ()
          {
              return new Character {
                  Name = nameBox.Text
              };
          }
      }
      
      var createWindow = new CreateCharacterWindow ();
      var doCreate = createWindow.ShowDialog ();
      
      if (doCreate ?? false) { // if DialogResult was not specified, assume it's false 
          var character = createWindow.CreateCharacter ();
          // do whatever you like with it
      }
      

      这种方法缺乏一些 WPF 数据绑定的花哨,但我喜欢 Character 只有在确实存在 从业务逻辑角度来看的字符时创建,并且该对象不像某个占位符可以用也可以不用。

      【讨论】:

        【解决方案3】:

        添加到 Hero 类的 CreateCharacter 参数或属性,并将其传递给它的构造函数或任何其他方法。

        【讨论】:

        • @Kirk,我们是在谈论创建多个构造函数吗?
        • @Snowbear - 我不知道,这将取决于这两个类的耦合程度/应该如何。我只是不明白为什么将引用传递给构造函数是“错误的”。
        • @Kirk,我认为为 Controls 创建非默认 ctor 是错误的
        【解决方案4】:

        这是一种很常见的模式。以下是我在 WPF 中的做法。

        在主窗口的视图模型中,应该有一个名为Characters 的属性,即ObservableCollection<CharacterViewModel>。在视图中,这与某种项目控件绑定,例如ListBoxCharacterViewModel 有一个DataTemplate,或者类实现了ToString(),以便有用地呈现字符。 ListBoxSelectedItem 属性绑定到视图模型中的 SelectedCharacter 属性,因此每当用户单击列表框中的项目时,视图模型都知道当前选择的字符是什么。

        主窗口视图模型还实现了一个EditingCharacter事件(它只是一个普通的事件处理程序)和一个EditCharacterCommand(使用Josh Smith's RelayCommand pattern),及其附带的属性和方法,例如:

        public bool CanEditCharacter { get { return SelectedCharacter != null; } }
        
        public void EditCharacter()
        {
           EventHandler h = EditingCharacter;
           if (EditingCharacter != null)
           {
              EditingCharacter(this, EventArgs.Empty);
           }
        }
        

        EditCharacterCommand 绑定到视图中的可点击控件(例如按钮或超链接)。

        主窗口view实例化主窗口视图模型并为EditingCharacter事件注册一个处理程序:

        private void ViewModel_EditingCharacter(object sender, EventArgs e)
        {
           CharacterViewModel cvm = ((MainWindowViewModel)sender).SelectedCharacter;
           CharacterWindow cw = new CharacterWindow();
           cw.ShowDialog(cvm);
        }
        

        (为什么使用事件?因为使用事件将创建和显示窗口的实现细节保留在视图模型对象之外。CharacterViewModel 不需要知道有关如何编辑字符的任何细节。它只是引发了一个事件说“嘿,是时候编辑当前选定的角色了。”由主窗口决定在引发事件时它将做什么。)

        CharacterWindow 实际上让用户可以编辑一个字符。它的控件绑定到CharacterViewModel 的属性。它实现了ShowDialog的重载:

        public bool? ShowDialog(CharacterViewModel cvm)
        {
           DataContext = cvm;
           return ShowDialog();
        }
        

        (让读者可以在不保存更改的情况下取消此对话框。)

        最后,您在窗口视图模型中实现AddCharacterCommand - 它创建一个新的CharacterViewModel,将其添加到Characters 集合中,设置SelectedCharacter,并引发@ 987654347@。将此绑定到主窗口中的按钮、超链接或菜单项,就完成了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-23
          • 1970-01-01
          • 1970-01-01
          • 2021-11-23
          • 2013-11-11
          • 1970-01-01
          相关资源
          最近更新 更多