Problem z odświeżeniem Data Grida w UserControl

0

Cześć,
Mam problem z którym walczę od kilku dnia ale nie mogę sobie poradzić.
Piszę aplikację w WPF i używam EF.
W głównym oknie używam UserControl

<UserControl x:Class="BK.UserControlSettings"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:BK"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <DataGrid x:Name="DBGrid"  HorizontalAlignment="Stretch" Height="auto"  Margin="5,5,5,5" VerticalAlignment="Top" Width="auto" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow" IsReadOnly="True">

            <DataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Usuń" Click="MenuItem_Click" />
                </ContextMenu>
            </DataGrid.ContextMenu>
            <DataGrid.Columns>
                <DataGridTextColumn Header="ID" Binding="{Binding id}"/>
                <DataGridTextColumn Header="Nazwa" Binding="{Binding name}"/>
                <DataGridTextColumn Header="Paramet" Binding="{Binding parametr}"/>
                <DataGridTextColumn Header="Opis" Binding="{Binding description}"/>
                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Text="Akcja" />
                        </DataTemplate>
                    </DataGridTemplateColumn.HeaderTemplate>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Button x:Name="insertBtn" Content="Dodaj" Click="insertBtn_Click"  />
                                <Button x:Name="updateBtn" Content="Zmień" Click="updateBtn_Click"/>
                                <Button x:Name="deleteBtn" Content="Usuń" Click="deleteBtn_Click" />
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</UserControl>

Natomiast plik cs wygląda następująco


namespace BK
{
    
    public partial class UserControlSettings : UserControl
    {
        bkEntities _db = new bkEntities();
        
        public UserControlSettings()
        {
            InitializeComponent();
            DBGrid.ItemsSource = _db.settings.ToList();
            

        }

        private void insertBtn_Click(object sender, RoutedEventArgs e)
        {
            SettingsAddWindow settingsAddWindow = new SettingsAddWindow();
            settingsAddWindow.Show();

        }

        private void updateBtn_Click(object sender, RoutedEventArgs e)
        {
            int Id = (DBGrid.SelectedItem as setting).id;
            var editSetting = _db.settings.Where(u => u.id == Id).Single();
            SettingsEditWindow settingsEditWindow = new SettingsEditWindow(editSetting);
            settingsEditWindow.Show();

        }

        private void deleteBtn_Click(object sender, RoutedEventArgs e)
        {
            int Id = (DBGrid.SelectedItem as setting).id;
            var deleteSetting = _db.settings.Where(u => u.id == Id).Single();
            CustomMaterialMessageBox msg = new CustomMaterialMessageBox
            {
                TxtMessage = { Text = "Czy na pewno chcesz usunąć: " + deleteSetting.id + " - " + deleteSetting.name , Foreground = Brushes.Black },
                TxtTitle = { Text = "Uwaga!", Foreground = Brushes.White },
                BtnOk = { Content = "Tak" },
                BtnCancel = { Content = "Nie" },
         
            };

            msg.Show();
            MessageBoxResult results = msg.Result;
            if (results == MessageBoxResult.OK)
            {
                _db.settings.Remove(deleteSetting);
                _db.SaveChanges();
                DBGrid.ItemsSource = _db.settings.ToList();
            }
            else
            {

            }
        }
    }
}

Grid jak widać wyświetla mi zawartość tabeli settings która składa się z 3 kolumn.
Na podstawie bazy wygenerowałem w EF model i klasę.


namespace BK
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;

    public partial class setting 
    { 
        public int id { get; set; }
        public string name { get; set; }
        public string parametr { get; set; }
        public string description { get; set; }

        
    }
}

W celu dodania danych do bazy wywołuję okno - settingsAddWindow

<Window x:Class="BK.SettingsAddWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BK"
        mc:Ignorable="d"
        Title="Dodaj parametr" Height="300" Width="300" WindowStyle="None" WindowStartupLocation="CenterScreen">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="60"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Label Content="Dodaj parametr" Margin="5,20,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Left" Grid.Row="0"/>
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
           </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label Content="Nazwa" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" />
            <Label Content="Parametr" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"/>
            <Label Content="Opis" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"/>
            <TextBox x:Name="tbNazwa"  Grid.Row="0" Grid.Column="1" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center" />
            <TextBox x:Name="tbParametr" Grid.Row="1" Grid.Column="1" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center" />
            <TextBox x:Name="tbOpis" Grid.Row="2" Grid.Column="1" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center"  />
        </Grid>
        <Button x:Name="btnZapisz" Grid.Row="2" Content="Zapisz" HorizontalAlignment="Right" Margin="0,10,100,0" VerticalAlignment="Top" Width="79" Click="btnZapisz_Click"/>
        <Button x:Name="btnAnuluj" Grid.Row="2" Content="Anuluj" HorizontalAlignment="Right" Margin="5,10,5,5" VerticalAlignment="Top" Width="79" Click="btnAnuluj_Click"/>
    </Grid>
</Window>

Plik cs wygląda następująco

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using BespokeFusion;

namespace BK
{
    /// <summary>
    /// Interaction logic for SettingsAddWindow.xaml
    /// </summary>
    public partial class SettingsAddWindow : Window
    {
        bkEntities _db = new bkEntities();
        public SettingsAddWindow()
        {
            InitializeComponent();
        }

        private void btnZapisz_Click(object sender, RoutedEventArgs e)
        {
            
            var q = _db.settings.Where(s => s.name.ToUpper() == tbNazwa.Text.ToUpper()).FirstOrDefault();
            setting setting = new setting();
            setting.name = tbNazwa.Text;
            setting.parametr = tbNazwa.Text;
            setting.description = tbOpis.Text;
            if (q is null)
            {
                _db.settings.Add(setting);
                _db.SaveChanges();
                
                this.Close();


            }
            else
            {
                MaterialMessageBox.Show("Taki parametr już istnieje");
            }

        }

        private void btnAnuluj_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        
    }
}

Problem polega na tym, że klikając przycisk zapisz, dane zostają zapisane do bazy natomiast grid w usercontrol nie zostaje odświeżony.
Nie wiem w jaki sposób odświeżyć tego grida ponieważ nie mogę się do niego odwołać przez MainWindow.DBGrid.ItemSource w przycisku zapisz.
Zakładam, że powinienem dodać do klasy setting interfejs INotifyPropertyChanged ale za bardzo nie wiem gdzie ( w klasie setting ?) i w jaki sposób.
Bardzo proszę o pomoc ponieważ w przypadku usuwania danych czy ich edycji grid jest odświeżany.
Mam jeszcze jedno pytanie chciałem w xamlu zrobić edycję danych poprzez ich bindowanie w dwie strony. Działa mi to, niestety chciałbym aby zmiana była dopiero zrobiona w momencie naciśnięcia przycisku zapisz a nie wpisując dane w odpowiednie pola.
Czy można to zrobić w xamlu czy trzeba pisać kod w pliku cs.
Mój edit wygląda następująco

<Window x:Class="BK.SettingsEditWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BK"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance Type=local:setting, IsDesignTimeCreatable=True}"
        Title="SettingsEditWindow" Height="300" Width="300" WindowStyle="None" WindowStartupLocation="CenterScreen" >
    <Grid x:Name="formGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="60"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Label Content="Dodaj parametr" Margin="5,20,0,0" VerticalAlignment="Top" HorizontalContentAlignment="Left" Grid.Row="0"/>
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"/>
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label Content="Nazwa" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" />
            <Label Content="Parametr" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"/>
            <Label Content="Opis" Grid.Row="2" Grid.Column="0" VerticalAlignment="Center"/>
            <TextBox x:Name="tbNazwa"  Grid.Row="0" Grid.Column="1" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding name }"  />
            <TextBox x:Name="tbParametr" Grid.Row="1" Grid.Column="1" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding parametr}" />
            <TextBox x:Name="tbOpis" Grid.Row="2" Grid.Column="1" Width="100" HorizontalAlignment="Left" VerticalAlignment="Center"  Text="{Binding description}"/>
        </Grid>
        <Button x:Name="btnZapisz" Grid.Row="2" Content="Zapisz" HorizontalAlignment="Right" Margin="0,10,100,0" VerticalAlignment="Top" Width="79" Click="btnZapisz_Click"/>
        <Button x:Name="btnAnuluj" Grid.Row="2" Content="Anuluj" HorizontalAlignment="Right" Margin="5,10,5,5" VerticalAlignment="Top" Width="79" Click="btnAnuluj_Click"/>

    </Grid>
</Window>

Dzięki za pomoc i pozdrawiam

0

We Win Formsach jak taką zwykłą listę się owrapowało w typ pomocniczy, właśnie do tego przeznaczony, to zaczynało działać jak oczekujesz.

Jak sobie przypomnę, to przeredaguję.

UPD: chyba to pomoże

https://docs.microsoft.com/en-us/dotnet/desktop/wpf/controls/how-to-group-sort-and-filter-data-in-the-datagrid-control?view=netframeworkdesktop-4.8

0

@AnyKtokolwiek: Niestety nie do końca to rozumiem. Link jest bardzo ciekawy jeżeli chodzi o obsługę grida, ale jest tam też zaznaczone, że muszę mieć zaimplementowany interfejs INotifyPropertyChanged a tak jak pisałem wyżej mam z tym problem. Nie wiem czy mam go implementować w klasie setting która jest automatycznie generowana przez EF czy może w inny sposób.
Inna sprawa, że sam link pokazuje sortowanie, filtrowanie i grupowanie danych w gridzie ( co oczywiście też mi się przyda) a nie jego aktualizację po insercie z innego okna (ale może źle na to patrzę).
Pozdrawiam

0

Jak już i tak jest to pisane na kolanie, to spróbuj przekazać do kontrolki dodawania DataGrid z listą obiektów
SettingsAddWindow settingsAddWindow = new SettingsAddWindow(DBGrid);
A następnie po zapisaniu danych w bazie ustaw ponownie ItemSource na przekazanym do kontrolki DataGrid'zie przez parametr
DBGrid.ItemsSource = _db.settings.ToList();

PS Jeśli się uczysz WPF to zainteresuj się takim pojęciem jak MVVM

0

Sprawdź ten trop

grid.ItemsSource = new ObservableCollection<T>( _db.settings.ToList() )

(nie weryfikowane, pisane z palca)
https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=net-5.0

0

ItemsSource w DataGridzie powinno być zbindowane do listy w View Modelu. Wtedy nie ruszasz widoku tylko edytujesz listę. Obejrzyj dowolny poradnik jak z bindować ItemsSource i nie brnij dalej w swój przykład

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