C# 将自定义用户控件中的类实例添加到主窗口中的列表时出现空引用异常
我正在Visual Studio中进行一个C#WPF项目,在该项目中,我允许用户添加一个用户控件(下面的代码中有两个文本框),该控件创建一个类(将数据存储在用户控件中,以便使用单个按钮创建多个用户控件)并将其添加到存储在主窗口文件中的列表中,以便稍后写入csv文件。当我点击按钮创建新用户控件时,出现以下错误: MasterListErrorTest.exe中发生类型为“System.NullReferenceException”的未处理异常 其他信息:对象引用未设置为对象的实例 我创建了一个简化版本的项目,其中只包含重现错误所需的元素。这是我所有的代码,所以你可以直接插入并自己得到错误。我做错了什么 MainWindow.xaml:C# 将自定义用户控件中的类实例添加到主窗口中的列表时出现空引用异常,c#,.net,wpf,xaml,C#,.net,Wpf,Xaml,我正在Visual Studio中进行一个C#WPF项目,在该项目中,我允许用户添加一个用户控件(下面的代码中有两个文本框),该控件创建一个类(将数据存储在用户控件中,以便使用单个按钮创建多个用户控件)并将其添加到存储在主窗口文件中的列表中,以便稍后写入csv文件。当我点击按钮创建新用户控件时,出现以下错误: MasterListErrorTest.exe中发生类型为“System.NullReferenceException”的未处理异常 其他信息:对象引用未设置为对象的实例 我创建了一个简化
<Window x:Class="MasterListErrorTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MasterListErrorTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel x:Name="UserControlContainer" HorizontalAlignment="Left" Height="216" Margin="24,83,0,0" VerticalAlignment="Top" Width="471" Orientation="Horizontal"/>
<Button x:Name="CreateNewControl" Content="Create New" HorizontalAlignment="Left" Margin="76,37,0,0" VerticalAlignment="Top" Width="75" Click="CreateNewControl_Click"/>
<Button x:Name="GiveStringFromList" Content="Give String" HorizontalAlignment="Left" Margin="360,37,0,0" VerticalAlignment="Top" Width="75" Click="GiveStringFromList_Click"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MasterListErrorTest
{
public partial class MainWindow : Window
{
int MultipleTextBoxControlID = 1;
public MainWindow()
{
InitializeComponent();
}
public static class TextBoxControlList
{
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList;
}
private void CreateNewControl_Click(object sender, RoutedEventArgs e)
{
MultipleTextBoxControl newUserControl = new MultipleTextBoxControl(MultipleTextBoxControlID);
UserControlContainer.Children.Add(newUserControl);
}
private void GiveStringFromList_Click(object sender, RoutedEventArgs e)
{
foreach (MultipleTextBoxControl.TextBoxData textBoxPanel in TextBoxControlList.MasterDataList)
{
List<string> userControlLine = new List<string>();
userControlLine.Add(textBoxPanel.Identifier.ToString());
userControlLine.Add(textBoxPanel.TextBox1Data);
userControlLine.Add(textBoxPanel.TextBox2Data);
MessageBox.Show(string.Join(",", userControlLine));
}
}
}
}
<UserControl x:Class="MasterListErrorTest.MultipleTextBoxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MasterListErrorTest"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="300">
<Grid>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="0,10,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" TextChanged="textBox1_TextChanged"/>
<TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="153,10,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" TextChanged="textBox2_TextChanged"/>
</Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MasterListErrorTest
{
public partial class MultipleTextBoxControl : UserControl
{
TextBoxData newTextBoxGroup = new TextBoxData();
public MultipleTextBoxControl(int identifier)
{
InitializeComponent();
newTextBoxGroup.Identifier = identifier;
MainWindow.TextBoxControlList.MasterDataList.Add(newTextBoxGroup);
}
public class TextBoxData
{
public int Identifier { get; set; }
public string TextBox1Data { get; set; }
public string TextBox2Data { get; set; }
public TextBoxData()
{
TextBox1Data = "Unchanged Textbox 1";
TextBox2Data = "Unchanged Textbox 2";
}
}
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
newTextBoxGroup.TextBox1Data = textBox1.Text;
}
private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
{
newTextBoxGroup.TextBox2Data = textBox2.Text;
}
}
}
如果在CreateNewControl\u单击中的代码周围放置一个try/catch异常块,则捕获的异常将为您提供有关发生情况的更多信息。StackTrace说:
at GuiTest.MultipleTextBoxControl..ctor(Int32 identifier) in c:\Dev\GuiTest\MultipleTextBoxControl.xaml.cs:line 31
at GuiTest.MainWindow25.CreateNewControl_Click(Object sender, RoutedEventArgs e) in c:\Dev\GuiTest\MainWindow25.xaml.cs:line 43
因此,列表中最近的一项是MultipleTextBoxControl.xaml.cs第31行:
MainWindow25.TextBoxControlList.MasterDataList.Add(newTextBoxGroup);
在此处放置断点并检查内容会发现MasterDataList为空,因为您没有在TextBoxControlList
中初始化它:
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList;
您的子窗口可以在其构造函数中接受对此类服务的引用,并像以前一样进行注册,但改用此服务:
public MultipleTextBoxControl(int identifier, IDataRegistrationService service)
{
InitializeComponent();
newTextBoxGroup.Identifier = identifier;
service.Register(newTextBoxGroup); // <---------
}
将TextBoxControlList类更改为:
public static class TextBoxControlList
{
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList;
static TextBoxControlList() {
MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
}
}
MainWindow.cs
public partial class MainWindow : Window
{
int MultipleTextBoxControlID = 1;
public static List<MultipleTextBoxControl.TextBoxData> MasterDataList;
static MainWindow() {
MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
}
public MainWindow()
{
InitializeComponent();
}
private void CreateNewControl_Click(object sender, RoutedEventArgs e)
{
MultipleTextBoxControl newUserControl = new MultipleTextBoxControl(MultipleTextBoxControlID);
UserControlContainer.Children.Add(newUserControl);
MasterDataList.Add(newUserControl.TextBoxGroup);
}
private void GiveStringFromList_Click(object sender, RoutedEventArgs e)
{
foreach (MultipleTextBoxControl.TextBoxData textBoxPanel in MasterDataList)
{
List<string> userControlLine = new List<string>();
userControlLine.Add(textBoxPanel.Identifier.ToString());
userControlLine.Add(textBoxPanel.TextBox1Data);
userControlLine.Add(textBoxPanel.TextBox2Data);
MessageBox.Show(string.Join(",", userControlLine));
}
}
}
公共部分类主窗口:窗口
{
int MultipleTextBoxControlID=1;
公共静态列表主数据列表;
静态主窗口(){
MasterDataList=新列表();
}
公共主窗口()
{
初始化组件();
}
私有void CreateNewControl_单击(对象发送方,路由目标)
{
MultipleTextBoxControl newUserControl=新的MultipleTextBoxControl(MultipleTextBoxControlID);
UserControlContainer.Children.Add(newUserControl);
添加(newUserControl.TextBoxGroup);
}
私有void GiveStringFromList_单击(对象发送方,路由目标)
{
foreach(主数据列表中的MultipleTextBoxControl.TextBoxData textBoxPanel)
{
List userControlLine=new List();
添加(textBoxPanel.Identifier.ToString());
添加(textBoxPanel.TextBox1Data);
添加(textBoxPanel.TextBox2Data);
Show(string.Join(“,”,userControlLine));
}
}
}
非常感谢,可能会重复!您是否介意扩展第二个版本的优点?对于UserControl依赖于父控件不是一个好主意,因为它会减少可重用性。要将信息从子级传递到父级,反之亦然,请公开属性或使用事件。这就是事件的意义所在。现在,我们的用户控件不以任何方式依赖于父窗口。我们已经暴露了一处将一直居住的房产。所有静态字段都应该在类的静态构造函数中初始化。这是一个非常好的观点。我在这里没有考虑可重用性。这也很好地工作了。我也很欣赏调试中的经验教训。将来遇到这些情况时,我将使用try/catch异常块。另外,您是否有可能给我一个提示,告诉我您对这种情况的建议?哪怕只是一个宽泛的陈述——我正在尽可能多地收集。答案更新。顺便说一句,当你遇到异常时,你也可以将“$exception”添加到监视窗口中,以立即查看详细信息,而无需修改和重新运行代码。这是一个很棒的东西。我将对此进行研究并重新编写代码。谢谢你的解释!
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
public void Register(MultipleTextBoxControl.TextBoxData data)
{
MasterDataList.Add(data);
}
private void CreateNewControl_Click(object sender, RoutedEventArgs e)
{
MultipleTextBoxControl newUserControl = new MultipleTextBoxControl(MultipleTextBoxControlID, this);
UserControlContainer.Children.Add(newUserControl);
}
public partial class MultipleTextBoxControl : UserControl
{
// this gets created by the DI framework, with identifier set automatically
[Inject] private TextBoxData newTextBoxGroup { get; set; }
// this get injected automatically when the class is create
[Inject] private IDataRegistrationService DataService {get; set;}
public MultipleTextBoxControl()
{
InitializeComponent();
}
// this gets called immediately after the constructor
public void Initialize()
{
// and you do any custom initialization here, using injected components
this.DataService.Register(newTextBoxGroup);
}
public static class TextBoxControlList
{
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList;
static TextBoxControlList() {
MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
}
}
public partial class MultipleTextBoxControl : UserControl
{
TextBoxData _newTextBoxGroup;
public TextBoxData TextBoxGroup { get { return _newTextBoxGroup; } }
public MultipleTextBoxControl(int identifier)
{
InitializeComponent();
_newTextBoxGroup = new TextBoxData(identifier);
}
public class TextBoxData
{
public int Identifier { get; set; }
public string TextBox1Data { get; set; }
public string TextBox2Data { get; set; }
public TextBoxData(int identifier)
{
Identifier = identifier;
TextBox1Data = "Unchanged Textbox 1";
TextBox2Data = "Unchanged Textbox 2";
}
}
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
_newTextBoxGroup.TextBox1Data = textBox1.Text;
}
private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
{
_newTextBoxGroup.TextBox2Data = textBox2.Text;
}
}
public partial class MainWindow : Window
{
int MultipleTextBoxControlID = 1;
public static List<MultipleTextBoxControl.TextBoxData> MasterDataList;
static MainWindow() {
MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
}
public MainWindow()
{
InitializeComponent();
}
private void CreateNewControl_Click(object sender, RoutedEventArgs e)
{
MultipleTextBoxControl newUserControl = new MultipleTextBoxControl(MultipleTextBoxControlID);
UserControlContainer.Children.Add(newUserControl);
MasterDataList.Add(newUserControl.TextBoxGroup);
}
private void GiveStringFromList_Click(object sender, RoutedEventArgs e)
{
foreach (MultipleTextBoxControl.TextBoxData textBoxPanel in MasterDataList)
{
List<string> userControlLine = new List<string>();
userControlLine.Add(textBoxPanel.Identifier.ToString());
userControlLine.Add(textBoxPanel.TextBox1Data);
userControlLine.Add(textBoxPanel.TextBox2Data);
MessageBox.Show(string.Join(",", userControlLine));
}
}
}