Проходной словарьот 1 формы до другой формы, если соблюдены определенные критерии - PullRequest
0 голосов
/ 21 сентября 2019

Я довольно новичок в c #, поэтому, пожалуйста, будьте терпеливы.Это, скорее всего, проблема дизайна.Я хочу передать значение словаря из одной формы в другую при выполнении определенных критериев, поскольку я загружаю все в свою первую форму.

Мое приложение в основном загружает CSV-файлы, содержащие рецепты, и распечатывает их в шаблоне Excel, который позжебудет распечатан на бумаге.У меня есть 2 формы в wpf.Где 1-я форма читает файлы CSV, отображает данные в методе gridview и сохраняет данные в словаре для дальнейшего использования.2-я форма вызывается, когда я дважды щелкаю ячейку gridview.

2-ая форма будет динамически создавать метки, текстовые поля и загружать CSV-файл, содержащий места размещения в ячейке Excel, в зависимости от идентификатора выбранного продукта.Немного не в тему, он затем распечатает Excel, используя справочную библиотеку EPPLUS.

Вот пример моего CSV-файла данных:

ID,Product's Type, Product's Name, Ingredient01, Ingredient01 Qty
A0101,SoftCake,Cheese Cake, Flour, 100g
A0201,CupCake,Blueberry Cupcake, Blueberries, 50g
A0202,CupCake,Chocolate Cupcake, Chocolate, 50g

вот мой CSV-файл для отформатированной ячейки:

Index, Product's Name, Ingredients01, Ingredients01 Qty
First Page,A21:D21, K20, J20
Second Page,A48:D48, K68, J68

Это только пример, но в реальных данных гораздо больше ингредиентов

вот код пока

public partial class Form1: Form
{
Form2 f2;

public Dictionary<string, string[]> recipeDict;
private Dictionary<string, string[]> formattedCell; //excel format

public Dictionary<string, string[]> FormattedCell;
//property of the first form
public Form1()
        {
            this.AutoSize = true;
            InitializeComponent();

            recipeDict = File
                .ReadAllLines(recipePath)
                .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());

            FormattedCell = new Dictionary<string, string[]>();
            FormattedCell = formattedCell;
         }
}

private void DataGridView1_MouseDoubleClick(object sender, MouseEventArgs e)
{
     f2 = new Form2();
     char tempID;
     //debugging
     Console.WriteLine(tempID = dataGridView1.CurrentRow.Cells[0].Value.ToString()[0]);

     if(tempID == "A")
    {
       formattedCell = 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());


     }
      f2.ShowDialog();
}


//2nd form
public partial class Form2: Form
{
      string[] firstPageCells, secondPageCell;
      Form1 f1;

//property
public Form2()
{
     f1 = new Form1();
     InitializeCellsArray();
}
private void InitializeCellsArray()
        {
            var valueLength = f1.FormattedCell.Max(t => t.Value.Length);
            //initialize every cellsArray
            firstPageCells = new string[valueLength];
            secondPageCells = new string[valueLength];


            //insert arrays from dictionary list
            f1.FormattedCell.TryGetValue("First Page", out firstPageCells);
            f1.FormattedCell.TryGetValue("Second Page", out secondPageCells);
}
}

Однако, f1.FormattedCell возвращаетнуль.

Ответы [ 4 ]

0 голосов
/ 21 сентября 2019

Проверьте эти строки, пожалуйста:

// свойство public Form2 () {f1 = new Form1 ();InitializeCellsArray ();}

Вы создаете новый экземпляр Form1, с которым не связаны никакие данные.Например, если ваше имя Form1 «MyForm», вы должны иметь что-то вроде:

f1 = MyForm
0 голосов
/ 21 сентября 2019

Оператор FormattedCell = formattedCell; находится в конструкторе Form1, поэтому он инициализирует ноль, поскольку он (formattedCell) равен нулю.

может потребоваться снова назначить FormattedCell = formattedCell в DataGridView1_MouseDoubleClick () событие.

, а также, char tempID; является символом, поэтому его нельзя сравнить с хардкорной строкой "A"

DataGridView1_MouseDoubleClick()
{
     if(tempID == 'A')
      {
       //Your code
       FormattedCell = formattedCell;
      }
}
0 голосов
/ 21 сентября 2019

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, и все не настроено прямо в переменных класса

0 голосов
/ 21 сентября 2019

Вы инициализируете FormattedCell новым словарем, а затем быстро перезаписываете его с null:

FormattedCell = new Dictionary<string, string[]>();
FormattedCell = formattedCell;

Типы ссылок в C # имеют значение null, если вы не назначаетечто-нибудь для них, и вы не инициализировали formattedCell в любом случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...