WinForms中AddGame窗体向MainWindow的ListView传值失败求助
WinForms跨窗体数据传递问题解决:无法访问listView1
问题根源
WinForms设计器默认将控件的访问修饰符设为private,这意味着外部窗体(比如你的AddGame)无法直接访问MainWindow里的listView1,这就是报错“因安全级别无法访问”的原因。另外你当前代码里还漏了传递MainWindow实例给AddGame,就算控件权限改了也会触发空引用异常。
下面给两种解决方案,以及关于SQL的疑问解答:
方案一:快速修正(修改控件权限+传递窗体实例)
修改listView1的访问权限
打开MainWindow的设计器,选中listView1,在右侧属性窗口找到Modifiers选项,将其改为public或internal。完善窗体实例传递
修改MainWindow中打开AddGame的代码,把当前窗体实例传递过去:private void AddGamesButton_Click(object sender, EventArgs e) { var addGames = new AddGame(); addGames.setForm1(this); // 新增此行,传递MainWindow实例 addGames.Show(); }
这样你的原有AddGame代码就能正常访问mainWindow.listView1了。
方案二:事件委托(更符合面向对象封装原则)
不直接暴露控件,通过事件传递数据,避免破坏窗体的封装性:
定义数据实体类
新建一个类用来封装游戏数据:public class GameInfo { public string Play0Name { get; set; } public string Players { get; set; } public string Sequence1 { get; set; } public string Sequence2 { get; set; } public string Comments { get; set; } public string Winner { get; set; } public string GameDate { get; set; } }修改AddGame窗体代码
删除public MainWindow mainWindow和setForm1方法,改为定义事件:public partial class AddGame : Form { // 定义游戏添加完成事件 public event EventHandler<GameInfo> GameAdded; public AddGame() { InitializeComponent(); } private void CloseAddFormButton_Click(object sender, EventArgs e) { Close(); } private void Add0Batchbutton_Click(object sender, EventArgs e) { try { // 空值检查,给异常添加明确提示 if (string.IsNullOrEmpty(Play0NametextBox.Text)) throw new ArgumentException("游戏名称不能为空"); if (string.IsNullOrEmpty(PlayersTextBox.Text)) throw new ArgumentException("玩家不能为空"); if (string.IsNullOrEmpty(Sequence1TextBox.Text)) throw new ArgumentException("序列1不能为空"); if (string.IsNullOrEmpty(Sequance2TextBox.Text)) throw new ArgumentException("序列2不能为空"); if (string.IsNullOrEmpty(CommentsTextBox.Text)) throw new ArgumentException("备注不能为空"); if (string.IsNullOrEmpty(WinnerTextBox.Text)) throw new ArgumentException("获胜者不能为空"); if (string.IsNullOrEmpty(GameDateTextBox.Text)) throw new ArgumentException("游戏日期不能为空"); // 封装数据 var gameInfo = new GameInfo { Play0Name = Play0NametextBox.Text, Players = PlayersTextBox.Text, Sequence1 = Sequence1TextBox.Text, Sequence2 = Sequance2TextBox.Text, Comments = CommentsTextBox.Text, Winner = WinnerTextBox.Text, GameDate = GameDateTextBox.Text }; // 触发事件通知MainWindow GameAdded?.Invoke(this, gameInfo); MessageBox.Show("数据添加成功"); Close(); } catch (Exception ex) { MessageBox.Show(ex.Message, "错误"); } } }修改MainWindow窗体代码
订阅AddGame的事件并处理数据添加:public partial class MainWindow : Form { public MainWindow() { InitializeComponent(); } private void AddGamesButton_Click(object sender, EventArgs e) { var addGames = new AddGame(); // 订阅事件 addGames.GameAdded += AddGames_GameAdded; addGames.Show(); } // 事件处理方法:将数据添加到listView1 private void AddGames_GameAdded(object sender, GameInfo e) { ListViewItem lvi = new ListViewItem(e.Play0Name); lvi.SubItems.Add(e.Players); lvi.SubItems.Add(e.Sequence1); lvi.SubItems.Add(e.Sequence2); lvi.SubItems.Add(e.Comments); lvi.SubItems.Add(e.Winner); lvi.SubItems.Add(e.GameDate); listView1.Items.Add(lvi); } // 其余原有方法不变 private void Closebutton_Click(object sender, EventArgs e) { Close(); } public void listView1_SelectedIndexChanged(object sender, EventArgs e) { foreach (ListViewItem item in listView1.Items) item.ForeColor = Color.Gray; } private void DeleteButton_Click(object sender, EventArgs e) { int selectNumber = -1; foreach (ListViewItem item in listView1.Items) if (item.Selected) { selectNumber = int.Parse(item.Text); } } }
关于SQL的疑问
用SQL存储数据是完全可行的,适合需要持久化数据的场景(比如关闭程序后数据不会丢失)。如果只是临时在内存中展示数据,上面的方案就足够;如果需要长期保存数据,可以把GameInfo的数据写入数据库,MainWindow启动时从数据库读取数据加载到listView1,添加新数据时同时写入数据库。
内容的提问来源于stack exchange,提问作者Mnur
相关产品推荐
相关产品推荐

