FormattedCell как общедоступная переменная f1 имеет значение null, поскольку в конструкторе вы делаете это:
FormattedCell = new Dictionary<string, string[]>();
FormattedCell = formattedCell;
formattedCell (с нижним регистром f) не зависит от FormattedCell (с верхним регистром F).Вы начинаете FormattedCell с нового словаря, а затем сразу устанавливаете его равным formattedCell, который в данный момент равен нулю.Попытка использовать FormattedCell приведет к ошибке null ref.Позже вы устанавливаете для formattedCell (со строчной буквой f) что-то допустимое, но изменяя formattedCell, чтобы оно указывало на что-то действительное, не изменит то, на что указывает FormattedCell, и останется нулевым.
По существу, это работает так, когда конструктор выполняется:
formattedCell -> null //points to null because the member is not set
FormattedCell -> null //pound to null because the last line of the constructor "points it to whatever formattedCell points to"
Назначение c # не работает так:
FormattedCell -> formattedCell -> null
Что означает, что когда выпозже указав на что-либо formattedCell, FormattedCell все еще остается указателем на ноль:
formattedCell -> (a dictionary)
FormattedCell -> null
Я предполагаю, что вы предполагали, что FormattedCell будет публичным свойством, которое ссылается на закрытую переменную formattedCell:
public ... FormattedCell {
get { return formattedCell; }
set { formattedCell = value }
}
Делая что-то коротко, было бы легче.Я предлагаю вам что-то изменить в верхней части файла, полностью удалив приватную переменную formattedCell
(так как это вызовет еще одну похожую путаницу), и переведите FormattedCell в открытое свойство:
public partial class Form1: Form
{
Form2 f2;//you can remove this as a class wide variable and just instantiate it locally in the double click because you don't reuse it
public Dictionary<string, string[]> RecipeDict {get; set;} //make it a property by putting a get/set, capitalise the firt letter of public members
//remove formttedCell
public Dictionary<string, string[]> FormattedCell {get;set}
Измените кодссылки для поиска «formattedCell» заменить на «FormattedCell»
Также рассмотрите возможность сделать Form1 параметром для вашего конструктора Form2, чтобы вместо Form2 пришлось создавать собственный экземпляр Form1, он мог просто ссылаться на существующий экземплярбез необходимости перечитывать файлы заново:
public Form2(Form1 f) //form2's constructor
new Form2(this).ShowDialog(); //inside form1, open a new form2 but use the existing form1
Я рекомендую вам сделать это, потому что щелчок мыши читает и заполняет FormattedCell - если ваша form2 создает новую форму1, эта Form1 не будетВы испытали щелчок мышью, чтобы прочитать файл, поэтому FormattedCell в новой форме будет по-прежнему нулевым
Если в конечном итоге вам не понадобится form2, чтобы прочитать другие сведения о Form1 или настроить объекты в Form1, не давайте form2ссылка на Form1.Вместо этого предоставьте form2 сам словарь и избавьтесь от общеклассовой переменной FormattedCells из Form1:
private void DataGridView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
var fmt = File
.ReadAllLines(excelTemplatePath)
.Select(line => line.Split(','))
.GroupBy(arr => arr[0])
.ToDictionary(gr => gr.Key, gr => gr
.SelectMany(s => new string[] {s[1], s[2], s[3], s[4], s[5], s[6], s[7] }).ToArray());
new f2(fmt).Show(); //if you use Show instead of ShowDialog you can have 2 recipes open at the same time
}
//remember to make your form2 constructor take a Dictionary
public Form2(Dictionary<string, string[]> d)
В конечном счете, это отличное упражнение для обучения - не поддавайтесь искушению сделать все переменным в классе /свойство.Держите вещи так низко, как вы можете сойти с рук.Сделайте объект обще-классным только в том случае, если несколько вещей будут использовать его повторно, иначе вы попадете в ситуацию, когда пользователь или разработчик выполнил B раньше A, и все не настроено прямо в переменных класса