[WPF C#] DataGrid w połączeniu z localDB

0

Witam!
Chciałem Was prosić o poradę bo utknąłem w martwym punkcie. Mianowicie chciałbym napisać pewną aplikację bazodanową. Zacząłem od przygotowania panelu do dodawania danych. Wcześniej programowałem trochę w technologii Windows Form, teraz próbuję ugryźć WPF. Utworzyłem w Visual Studio źródła danych, stworzyłem adapter, wypełniłem danymi kontrolkę DataGrid. Chciałbym aby dodawanie danych, akutalizacja i usuwanie odbywały się poprzez tą kontrolkę, bez zbędnych formularzy. Wszystkie pola w przypadku DataGridTextColumn działają prawidłowo. Natomiast mam potrzebę by w kolumnie, w której przechowywana jest ścieżka do pliku, jej dodanie odbywało się poprzez kliknięcie w komórkę co spowoduje otwarcie okna dialogowego w celu wybrania pliku. Udało mi się to zrealizować połowicznie przy użyciu DataGridTemplateColumn. Połowicznie, gdyż po wczytaniu pliku ścieżka jest widoczna w komórce DataGrid, ale nie jest zapisywana w bazie danych. Próbowałem wczoraj z tym sobie poradzić, jednak bezskutecznie.
Zastanawiam się także czy dobrą drogę obrałem. Datagrid jest wypełniany bezpośrednio z adaptera pracującego na źródle danych. Może powinien być połączony z jakąś strukturą (np. obiekt klasy lista). Szukając materiałów na ten temat trafiłem na kurs w którym kontrolka DataGrid połączona jest z obiektem klasy lista i poszczególne tabele mają swoją reprezentację w postaci klas. Czy można w ten sposób zaprojektować aplikację a potem "jakoś w prosty sposób połączyć z bazą danych"? Trafiłem także na materiały związane z Entity Framework i w sumie od natłoku koncepcji rozbolała mnie głowa. Czy w związku z tym mogę Was prosić o poradę w jaki sposób najlepiej zaprojektować taką aplikację?

0

Pracuję na UWP ze względu na dostęp do MS Store i osobiście nie wiem, czy będę w stanie pomóc, bo nie wiem czy dobrze zrozumiałem, więc proszę o jakiś fragment, bym to sobie mógł zwizualizować. W szczególności fragment axml z DataGrid i logikę jego wypełniania. Jak tworzysz procedurę zdarzeń typu SelectionChanged dla GridView, możesz dla konkretnego indeksu kontrolek wewnątrz DataGrid wykonać jakieś zadanie, np. aktualizację danych w bazie. Po związaniu kontrolek z objektami dane w obie strony będą wymieniane automatycznie gdy edytujesz kontrolkę, bądź prześlesz z programu dane do związanego obiektu. Być może chodzi Ci o INotifyPropertyChanged, ale nie wiem, bo bez przykładu nie skumam o co Ci chodzi..

0
namespace HB_test
{
       public partial class Dzwiek_uc : UserControl
    {
        DB_HBDataSetTableAdapters.DzwiekTableAdapter adapter = new DB_HBDataSetTableAdapters.DzwiekTableAdapter();
        DB_HBDataSet.DzwiekDataTable table = new DB_HBDataSet.DzwiekDataTable();

        public Dzwiek_uc()
        {
            InitializeComponent();
          
            adapter.Fill(table);
            Dzwiek_dg.ItemsSource = table.DefaultView;
            Dzwiek_dg.Items.Refresh();
        }
        
        private void aktualizacja_bazy ()
        {
            try
            {
                adapter.Update(table);
            }

            catch (Exception ex)
            {
                if (ex.Message.Contains("UNIQUE")) MessageBox.Show("Już istnieje w bazie danych!", "Alert", MessageBoxButton.OK, MessageBoxImage.Error);
                if (ex.Message.Contains("DELETE")) MessageBox.Show("Nie można usunąć", "Alert", MessageBoxButton.OK, MessageBoxImage.Error);

                adapter.Fill(table);
            }
}

        private void Dzwiek_dg_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            aktualizacja_bazy();
        }

        private void TextBlock_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
         

          
            TextBlock tb = sender as TextBlock;
            tb.Text = "To jest test";
            aktualizacja_bazy();
        }
    }
}

XAML:
<DataGridTemplateColumn Header="Nazwa dźwięku">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock PreviewMouseLeftButtonUp="TextBlock_PreviewMouseLeftButtonUp">
                                    <TextBlock.Text>
                                        <Binding Mode="TwoWay"  Path="Nazwa_dzwieku"></Binding>
                                    </TextBlock.Text>
                                </TextBlock>
                             </DataTemplate>
                         </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>

Przyznam, że trochę nabałaganiłem w kodzie, więc żeby przesłać przykład musiałem jeszcze raz się pochylić i przypadkiem połowicznie zaczęło mi działać. Problem polega na tym iż gdy komórka dostaje tekst, to baza jest aktualizowana metodą Dzwiek_dg_SelectionChanged - czyli po zmianie komórki w datagrid, a nie w momencie przypisana tekstu do komórki. Przykład jest poglądowy, zamiast przypisywania tekstu zrobię sobie OpenDialog.

0

Nie widzę w ogóle elementu, do którego podpiąłeś kontrolkę i myślę, że niepotrzebnie też wydłużasz kod interfejsu. Akurat z ogólnie z axml zacząłem dopiero niedawno, ale fajnie się go pisze.

<TextBlock PreviewMouseLeftButtonUp="TextBlock_PreviewMouseLeftButtonUp">
<TextBlock.Text>
<Binding Mode="TwoWay"  Path="Nazwa_dzwieku"></Binding>
</TextBlock.Text>

Tam gdzie wystarczy Ci podstawowa struktura spokojnie możesz napisać prościej:

<TextBlock Text="{Bingding Nazwa_dzwieku}" Mode="TwoWay"/>

Takie coś jest bardziej czytelne. Co innego np. jakbyś chciał coś w kontrolce zrobić inaczej, np. miałbyś kontrolkę z wartością Icon, ale chciałbyś użyć niestandardowej ikony. Taki myślę przykład kiedy warto rozbijać podstawową konstrukcję kontrolki.

Np. Podstawowa jest taka:

<NavigationViewItem x:Name="NVIBing" Content="Bing" Tag="Bing" Icon="Nie ma ikony bing"/>

Ale ponieważ nie ma ikony bing rozbijam:

 <NavigationViewItem x:Name="NVIBing" Content="Bing wallpapers" Tag="Bing">
                    <NavigationViewItem.Icon>
                        <PathIcon x:Uid="PathIconBing" Data="{Binding}"/>
                    </NavigationViewItem.Icon>
</NavigationViewItem>

Podłączyłem Data, czyli wartość kodu Path ikony SVG do klucza PathIconBing.Data w pliku zasobów Resources.resw Dzięki temu mam niestandardową ikonę i nie muszę zawartości trzymać bezpośrednio w Data. Oczywiście przykład taki trochę z d*, ale myślę, że wiesz o co mi chodzi. Potem jest porządek w tym i łatwiej się połapać. Oczywiście w sumie jestem w tym nowy, więc tylko taka sugestia, pewnie można jeszcze prościej.

Jeśli chodzi o stronę z kodem, to tutaj masz wytłumaczone jak wymieniać dane i łapać zmiany:

Dokumentacja:
https://docs.microsoft.com/pl-pl/dotnet/framework/wpf/data/how-to-implement-property-change-notification

Jakiś wideo-poradnik:

Jedyny problem, który kiedykolwiek z tą metodą aktualizacji danych się może pojawić, to np. przy obrazach, czy plikach, gdzie ścieżki do źródła się nie zmieniają, ale pliki tak. Wówczas event nie wykryje zmiany, a nawet jak mu powiesz, że zmiana zaszła, to nie przeładuje danych. np. obrazy w interfejsie się nie zmienią, bo ścieżki się nie zmieniły i z wymuszaniem odświeżania miałem problem, bo nie działało, ale to jakoś udało mi się obejść.

0

Może trochę namieszałem i nie do końca się zrozumieliśmy. Zamiast tekstu który wstawiam będzie okno dialogowe do wskazania pliku. Baza ma przechowywać ścieżkę do pliku. Dlatego w XAML kontrolka jest rozbudowana. Po prostu po kliknięciu w komórkę kolumny powinno pojawić się okno dialogowe i ścieżka do wskazanego pliku powinna być zapisana w bazie po jego wybraniu z okna dialogowego. Udało mi się zrealizować mniej więcej tą funkcjonalność, ale zamiana wartości komórki datagrid z poziomu code-behind

tb.Text=dlg.Filname;

albo nawet

tb.Text="jakiś tam takst"

nie aktualizuje bazy. Może po prostu czegoś brakuje w kodzie. Może nie do końca rozumiem co napisałeś bo staram się dopiero jakoś ogarniać ten WPF :)

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