WFP c# - Combobox z ID i Etykietą

0

Próbuję zrozumieć C# od nowa, na przykładzie prostej apki, która ma wyświetlić dane z bazy.
Chciałbym, aby pierwszym krokiem do warunku drugiego zapytania, było id pobrane poprzez comboBox.
W bazie zrobiłem kilka tabelek, no i pierwsza, która miałby ograniczać ma ID, Nazwa, bo to by później wyfiltrować sobie wiersze z views'a albo w dalszym etapie pobrać dane przez procedurę czy funkcję.
No więc, poczytałem sobie, podłączyłem bazę i.... wyświetlam dane z kolumny Nazwa.
I tu moje pytanie czy da się to tak zrobić, żeby pobrać z bazy zarówno id jak i Nazwę, nazwę wyświetlić w rozwijanej liście, a Id przekazać dalej.
Na początku chciałbym wyświetlić te wartości w textBoxie czy labelu.
Czy może, ktoś z was pomóc???

0

Spróbuj dodać do kontrolki w XAMLu

DisplayMemberPath="TwojaNazwa"
SelectedValuePath="TwojeId" 

W kontrolce będzie wyświetlana tylko nazwa, a id powinno być przekazywane dalej, tak mi się wydaje :)

0

Hmm, ale wg. mnie to co mam indeksuje nie wg. id z sqla tylko wg indeksu comboBox'a.

0

Bo szukasz w SelectedIndex a nie w SelectedValue

0

Ok, rzeczywiście.
Ale teraz próbowałem przypisać wartości i powiem szczerze, pogubiłem się.

Mam w C# zapytanie do bazy, na Id oraz Nazwe i mam pętlę:
while (dr.Read())
{
int Id = dr.GetInt32(0);
string Nazwa = dr.GetString(1);
//comboBox1.Items.Add(new ComboBoxItem { Content = Nazwa, Tag = Id.ToString() });
comboBox1.Items.Add(Nazwa.ToString());
}
A w .xaml tak:
<ComboBox x:Name="comboBox1" ItemsSource="{Binding}" HorizontalAlignment="Left" Margin="10,47,0,0" VerticalAlignment="Top" Width="134"
SelectedValue="{Binding Path=Id}" SelectedValuePath="{Nazwa}" SelectionChanged="comboBox1_SelectionChanged">
<ComboBox.Items>
<ComboBoxItem/>
</ComboBox.Items>
</ComboBox>
I nie za bardzo, to rozumiem

0

Nie powiedziałeś że nie używasz MVVM (większość Tutoriali jest z jego wykorzystaniem).
while (dr.Read())
{
int Id = dr.GetInt32(0);
string Nazwa = dr.GetString(1);
comboBox1.Items.Add(new ComboBoxItem { Content = Nazwa, Tag = Id });
}
<combobox x:name="comboBox1" itemssource="{Binding}" horizontalalignment="Left" margin="10,47,0,0" verticalalignment="Top" width="134" selectionchanged="comboBox1_SelectionChanged">
<combobox.items>
<comboboxitem />
</combobox.items>
</combobox>

odczyt:
int selectedId = 0;
ComboboxItem item = (combobox1.SelectedItem as ComboBoxItem);
if (item <> null)
{
selectedId = (int)item.Tag;
}

0

No nie do końca, chcę użyć klasycznego ADO.NET i użyć jakieś pętli do tego.
Uczyłem się C# jak zaczęto mówić o Linq i robiłem jakieś drobiazgi jak już był, ale nigdy nie używałem, bo pisząc na codzień w T-SQL'u wolę pisać zapytania sam ;)
A co do tutoriali to te co znalazłem są z czymś takim jak Entity Model czy jakoś tak.
Tak więc, chciałem zostać przy ADO bo to było dla mnie jasne.

0

Skasuj jeszcze z tego xamla itemssource="{Binding}"

0

Tak wiem, tam jest jeszcze drobny błąd w ifie.
Chyba powinno być tak: if (item != null)
Wielkie dzięki, za pomoc.
Choć i tak nie do końca wiem czemu np. nie można przekazać contentu do labela, tylko np. w taki sposób:
string SelectedNazwaValue_Str = ((ComboBoxItem)comboBox1.SelectedItem).Content.ToString();

Label1_Txt.Content = SelectedNazwaValue_Str .ToString();

0

Ostatni ToString jest nadmiarowy. Cała biblioteka WPF jest pomyślana pod wzorzec MVVM i Binding. Dlatego gdy robimy niektóre rzeczy w Code behind trzeba się gimnastykować. SelectedValue/SelectedItem są typu object ponieważ mogą przechowywać dowolne wartości (zwłaszcza SelectedItem).

Teraz sobie pomyślałem że lepiej by było jakbyś zrobił sobie swoją klasę:

class MyComboItemModel 
{
    public int Id { get; set; }

    public string Nazwa { get; set; }
}

Potem odczyt z bazy robisz tak:

List<MyComboItemModel> list = new List<MyComboItemModel>();

while (dr.Read())
{
    int Id = dr.GetInt32(0);
    string Nazwa = dr.GetString(1);
    list.Add(new MyComboItemModel { Id = Id, Nazwa = Nazwa });
}

combo.ItemsSource = list;

potem w XAML musisz ustawić przynajmniej DisplayMemberPath (ewentualnie ItemTemplate).

Teraz z Combo możesz pobrać cały obiekt przedstawiany przez zaznaczony element (siedzi on w SelectedItem)

MyComboItemModel selected = combo.SelectedItem as  MyComboItemModel;

Daje to fajne możliwości gdy masz więcej właściwości w swojej klasie i zrobisz fajny DataTemplate. Ogólnie uważam że WPF i SL biją na głowę możliwościami w wizualizacji Windows Forms oraz to co mamy w HTML.

0

Wygląda to sto razy przejrzyściej ;)
Spróbuje z tym kodem, ale zastanawia mnie czemu i jak sobie z tym poradzić wypełnia się wielokrotnie tymi samymi wartościami?
I jeszcze jedno mnie nurtuje, mianowicie jak wartość (int czy string) z takiego combo który jest w MainWindow przekazać do nowego okna, które wywołuje buttonem na Mainie.

0

Gdzieś popełniam błąd, ale nie wiem gdzie, widzę że lista się wypełnia (choćby po długości), ale nie przekazuje żadnych danych.

W XAML'u mam tak:
<ComboBox x:Name="comboBoxNazwa" ItemsSource="{Binding MyComboItemModel}" DropDownOpened="comboBoxNazwa_DropDownOpened" DisplayMemberPath ="MyComboItemModel"/>

A w CB, tak:

    private void comboBoxNazwa_DropDownOpened(object sender, EventArgs e)
    {
        List<MyComboItemModel> list = new List<MyComboItemModel>();
        SqlConnection SQLcon = new SqlConnection(connectionString);
        try
        {
            SQLcon.Open();
            string RasaQ = "select r.Id, r.Nazwa from Test r WITH(NOLOCK) ORDER BY r.Id;";
            SqlCommand createCommand = new SqlCommand(RasaQ, SQLcon);
            SqlDataReader dr = createCommand.ExecuteReader();
            while (dr.Read())
            {
                int Id = dr.GetInt32(0);
                string Nazwa = dr.GetString(1);
                list.Add(new MyComboItemModel { Id = Id, Nazwa = Nazwa });
            }
            comboBox1.ItemsSource = list;
            //MyComboItemModel selected = comboBox1.SelectedItem as MyComboItemModel;
            SQLcon.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
   }
0

Zgodnie z tym co podał @szogun1987 dopisz sobie pod tym comboBox1.ItemsSource = list; jeszcze te dwie linie:

comboBox1.DisplayMemberPath = "Nazwa";
comboBox1.SelectedValuePath = "Id";

W kodzie XAML bez szaleństw, nie potrzeba dodawać {Binding CośTam}

0

Ok, no tak, teraz to działa pięknie, bardzo wam dziękuje.
Dopytam jeszcze o jedno jak to zrobić, żeby wybraną wartość z takiego combo, który jest w MainWindow przekazać okna (public partial class Dodaj : Window) które jest w tej samej przestrzeni nazw i otwierane jest z MainWindow przez Dodaj.show();
Sądziłem, że w ramach jednej przestrzeni nazw, elementy są "widoczne"

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