C# DataGridView i zamiana NULLi w empty stringi

0

Witajcie,
problem następujący, chciałbym edytować MS SQLową bazę danych za pomocą programu w C#. Wszystko idzie świetnie, jednak gdy napotykam na kombinację DataGridView i puste wartości, jest to dla mnie mur nie do przejścia.

Pokrótce:

private void Form1_Load(object sender, EventArgs e)
        {
                dbc = new SqlConnection("user id=" + Settings.Default["dbUser"].ToString() + ";password=" + Settings.Default["dbPasswd"].ToString() + ";server=" + Settings.Default["dbSerwer"].ToString() + ";database=" + Settings.Default["dbName"].ToString() + ";connection timeout=10");
                dba = new SqlDataAdapter("SELECT id, symbol, nazwa FROM towar ORDER BY symbol", dbc);
                dbt = new DataTable();
                dbBs = new BindingSource();

                dba.Fill(dbt);
                dbBs.DataSource = dbt;
                
                dataGridView1.DataSource = dbBs;
        }

Zapis zmian ma się odbywać w tle, więc:

        private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
                dbBs.EndEdit();
                dbCmd = new SqlCommandBuilder(dba);
                dba.Update(dbt);
        }

... i wszystko OK, dopóki nie zdecyduję się na wymazanie zawartości komórki. Taka akcja powoduje, że SqlCommandBuilder tworzy kod, który usiłuje zapisać wartość NULL, w pole tabeli, gdzie nie jest to dozwolone. Jak wymusić żeby zamiast NULLa w tej sytuacji był zapisywany pusty ciąg - '' ?

0

puste pole w db powinno być nullem a nie pustym stringiem,
allow nulls i tyle

0

Nie mogę tak zrobić (chociaż chciałbym).

0

Dwie metody:

  1. Sprawdź, czy ta komórka jest pusta, jeśli tak, to wpisz do niej pusty ciąg: ""
  2. Niech kolumna w bazie danych zostanie NOT NULL, ale dodaj wartość domyślną - pusty ciąg. Tak naprawdę to chyba będzie po prostu spacja.
0

Genialne, dzięki bardzo! Problem rozwiązany, zostawię potomnym, (problem występował jedynie dla trzeciej kolumny).

private void dataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            if (dataGridView1.CurrentCell.ColumnIndex == 3 && string.IsNullOrEmpty(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()))
            {
                dataGridView1.CurrentCell.Value = string.Empty;
            }

Tak przyszłościowo, czy da się ustawić obsługę NULLa zbiorczo, najlepiej gdzieś na etapie DataTable?
(Tak, zdaję sobie sprawę, że te rozważania zalatują problemami akademickimi :-) )

0

@pragmatyk: to jest bardzo złe rozwiązanie i zemści się bardzo szybko. Co się stanie, gdy zmieni się kolejność kolumn? Albo będziesz musiał dodać kolejną kolumnę np. na drugim miejscu?

0

... nic dobrego :) . Podpowiedziałbyś coś?

edit: Nie było pytania :)

private void dataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            if (dataGridView1.CurrentCell.OwningColumn.HeaderText == "Uwagi" && string.IsNullOrEmpty(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()))
            {
                dataGridView1.CurrentCell.Value = string.Empty;
            }
        }
0

Dalej źle. A co jeśli CurrentCell z jakiegoś powodu da Ci inną komórkę niż dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] ? Po to masz te argumenty, żeby nimi się posługiwać. To te argumenty określają Ci jednoznacznie, o którą komórkę chodzi. Poza tym, co zrobisz w momencie, gdy szef nagle każe zmienić nagłówek: "Uwagi" na np. "Uwagi ważne"? Znowu dupa. Powinieneś posłużyć się nazwą kolumny, a nie nagłówka. Nazwy kolumn raczej się nie zmieniają. Nagłówki mogą, a indeksy kolumn - na bank się zmienią.

0

W jaki sposób poprawnie przypisać nazwy do kolumn? Za pomocą indexu?

dataGridView1.Columns[3].Name = "nazwa";
0

Przecież masz już powiązane kolumny w gridzie z kolumnami w bazie, nie? Inaczej nie mógłbyś niczego wyświetlić.

0

Po prostu szacun. Tak będzie dobrze?

private void dataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            // zamiana NULLa na pusty string w kolumnie uwagi
            if (dataGridView1.CurrentCell.OwningColumn.Name == "nazwa" && string.IsNullOrEmpty(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()))
            {
                dataGridView1.CurrentCell.Value = string.Empty;
            }
        }
1

Nie, masz nie używać CurrentCell w tym miejscu. Po co sobie tak życie utrudniasz? Powinieneś zrobić coś w stylu (pisane z głowy):

DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
if(cell != null)
{
  if(cell.OwingColumn.Name == "nazwa" && string.isNullOrEmpty(cell.Value.ToString())
    cell.Value = string.Empty;
}
0

Im dalej w las tym więcej drzew. To działa (!)

private void dataGridView1_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
            if (cell != null)
            {
                if (cell.OwningColumn.Name == "nazwa" && string.IsNullOrEmpty(cell.Value.ToString()))
                {
                    cell.Value = string.Empty;
                }
            }
        }

Mam ostatnią prośbę, czy mógłbyś wytłumaczyć wyższość tego rozwiązania nad CurrentCell?
Niemniej dziękuję.

1

CurrentCell zwraca Ci aktualnie wybraną komórkę. Czyli tą, która ma focus. Czy jesteś pewien, że w momencie wywołania tego zdarzenia CurrentCell zawsze zwróci Ci dobrą wartość? Bo ja nie. Natomiast NA PEWNO dobrą wartość masz przekazaną w argumencie e.

W argumentach zdarzeń są zawsze informacje o elementach, na rzecz których to zdarzenie zostało wywołane. I dzięki temu masz po prostu pewność, którego obiektu dotyczy zdarzenie. I zawsze powinieneś się nimi posługiwać.

Co więcej - masz parametr sender, z którego też powinieneś korzystać. Pewnie nie wiesz, co w nim siedzi, prawda? W sender zawsze masz obiekt, który wywołał to zdarzenie. W tym przypadku będzie to prawdopodobnie grid. Nie wiem.

Gdy masz zdarzenie Click jakiegoś buttona, to w senderze dostajesz buttona, który został kliknięty. I możesz zrobić coś takiego:

void button1_Click(object sender, EventArgs e)
{
   button1.Enabled = false;
}

Ale możesz zrobić też coś takiego:

void button1_Click(object sender, EventArgs e)
{
    //prostsza wersja:
    Button b = (Button)sender; //lub sender as Button;
    b.Enabled = false;

   //wersja jednolinijkowa
   ((Button)sender).Enabled = false;

   //wersja ze sprawdzeniem:
   if(sender is Button)
       ((Button)sender).Enabled = false;
}

To oczywiście wszystko zależy od tego, co chcesz tak naprawdę zrobić. Pamiętaj, że masz takie możliwości. I jeśli masz na formie kilka kontrolek, które po jakimś zdarzeniu mają zachować się tak samo (np. kilka buttonów, które po kliknięciu mają się deaktywować), to możesz do tego wykorzystać jedną metodę. Nie musisz mieć osobnych zdarzeń dla każdego takiego przycisku. To taka wiedza w gratisie ;)

0

Czapki z głów, dziękuję bardzo :) Pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1