2

Есть база данных MSSQL SERVER (library) в ней есть таблица Teachers нужно с помощью WPF взаимодействовать с таблицей (CRUD - операции)
Сделал интерфейс окна - MainWindow.xaml:

<Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Margin" Value="20 8 20 8" />
            <Setter Property="Width" Value="100" />
            <Setter Property="Height" Value="30" />
            </Style>
        </Window.Resources>
&lt;DockPanel&gt;
    &lt;Menu DockPanel.Dock=&quot;Top&quot; Height=&quot;25&quot; VerticalAlignment=&quot;Top&quot; FontFamily=&quot;Comic Sans MS&quot; FontSize=&quot;14&quot;&gt;
        &lt;MenuItem Header=&quot;Create&quot; Click=&quot;Create_Click&quot;/&gt;
        &lt;MenuItem Header=&quot;Read&quot; Click=&quot;Read_Click&quot;/&gt;
        &lt;MenuItem Header=&quot;Update&quot;/&gt;
        &lt;MenuItem Header=&quot;Delete&quot;/&gt;
    &lt;/Menu&gt;

    &lt;Grid&gt;
        &lt;Grid.RowDefinitions&gt;
            &lt;RowDefinition Height=&quot;*&quot; /&gt;
            &lt;RowDefinition Height=&quot;Auto&quot; /&gt;
        &lt;/Grid.RowDefinitions&gt;
        &lt;DataGrid AutoGenerateColumns=&quot;False&quot; Name=&quot;GridContent&quot;&gt;
            &lt;DataGrid.Columns&gt;
                &lt;DataGridTextColumn Binding=&quot;{Binding Id}&quot; Header=&quot;Id&quot; Width=&quot;120&quot;/&gt;
                &lt;DataGridTextColumn Binding=&quot;{Binding FN}&quot; Header=&quot;FirstName&quot; Width=&quot;125&quot;/&gt;
                &lt;DataGridTextColumn Binding=&quot;{Binding LN}&quot; Header=&quot;LastName&quot; Width=&quot;80&quot;/&gt;
            &lt;/DataGrid.Columns&gt;
        &lt;/DataGrid&gt;
    &lt;/Grid&gt;
&lt;/DockPanel&gt;

Подключился к бд, сделал запрос на чтение данных, как теперь отобразить данные в grid?
xaml.cs:

public partial class MainWindow : Window
    {
        string connectString;
        public MainWindow()
        {
            connectString = ConfigurationManager.ConnectionStrings["Connect"].ConnectionString;
            InitializeComponent();
        }
    private void Read_Click(object sender, RoutedEventArgs e)
    {
       try
       {
            using (SqlConnection sqlConnection = new SqlConnection(connectString))
            {
                sqlConnection.Open();

                SqlCommand sqlCommand = new SqlCommand()
                {
                    CommandText = &quot;SELECT Id, FirstName, LastName FROM Teachers&quot;,
                    Connection = sqlConnection,
                };

                DataTable dataTable = new DataTable();
                SqlDataAdapter adapter = new SqlDataAdapter(sqlCommand); 


                using (SqlDataReader reader = sqlCommand.ExecuteReader())
                { 
                    while (reader.Read()) //&lt;----------------вот здесь!!!!
                    {
                        adapter.Fill(dataTable);
                        GridContent.ItemsSource = dataTable.AsDataView(); 

                    }
                    reader.Close();
                }

            }
       }
       catch(Exception ex)
       {
            MessageBox.Show(ex.Message);
       }
    }
}

app.congif:

<connectionStrings>
            <add name="Connect" 
                 connectionString="Data Source=localhost\SQLEXPRESS; Initial Catalog=library; Integrated Security=True"/>
        </connectionStrings>
  • 1
    Нынче так не пишут, тем более для WPF. Вам нужно создать модель предметной области, в вашем случае класс Teacher с нужными свойствами. Для быстрого создания прототипа приложения БД не нужна совсем, используйте тестовые данные из памяти. Отделите работу с БД в отдельный класс репозитория, используйте привязки вместо событий. Посмотрите ответ https://ru.stackoverflow.com/a/1043980/222542 который я писал для WinForms. – Bulson Nov 28 '20 at 13:57
  • @Bulson Понял, а есть пример на каком-то ресурсе как это делать на WPF, а то не нашел –  Nov 28 '20 at 15:01

1 Answers1

3

Сделал специально для вас тот же пример, что и ранее написанный для WinForms пример работы Данный пример гитхабе здесь.

В качестве модели используется тот же класс Employee. Интерфейс для работы с БД такой

public interface IEmployeeRepository
{
    //получение всех
    Task<List<Employee>> GetEmployees();
    //добавление
    Task<int> AddEmployee(Employee employee);
    //удаление
    Task<int> RemoveEmployee(int id);
    //обновление
    Task<int> UpdateEmployee(Employee emp);
}

Репозиторий с тестовыми данными такой

class TestRepository : IEmployeeRepository
{
    private List<Employee> _employees;
    public TestRepository()
    {
        _employees = new List<Employee>
        {
            new Employee(1, "Иван", "Голунов", "+7561234567"),
            new Employee(2, "Сергей", "Смирнов", "+77861234567"),
            new Employee(3, "Дарья", "Смирнова", "+798475563"),
            new Employee(4, "Кристина", "Семяжко", "+7304985023"),
            new Employee(5, "Владимир", "Драгунов", "+73431234567"),
        };
    }
public Task&lt;List&lt;Employee&gt;&gt; GetEmployees()
{
    var result = new List&lt;Employee&gt;();
    foreach (var e in _employees)
    {
        var emp = new Employee(e.Id, e.FirstName, e.LastName, e.Phone);
        result.Add(emp);
    }

    return Task.FromResult(result);
}

public Task&lt;int&gt; AddEmployee(Employee employee)
{
    if (employee is null)
        throw new ArgumentNullException(nameof(employee));
    if (String.IsNullOrWhiteSpace(employee.FirstName)
        || String.IsNullOrEmpty(employee.FirstName))
    {
        return Task.FromResult(0);
    }
    if (String.IsNullOrWhiteSpace(employee.LastName)
        || String.IsNullOrEmpty(employee.LastName))
    {
        return Task.FromResult(0);
    }

    if (employee is null || employee.Id &gt; 0)
        throw new ArgumentNullException(nameof(employee));

    if (_employees.Count &gt; 0)
    {
        employee.Id = _employees.Max(e =&gt; e.Id) + 1;
    }
    else
    {
        employee.Id = 1;
    }
    _employees.Add(employee);

    return Task.FromResult(employee.Id);
}

public Task&lt;int&gt; RemoveEmployee(int id)
{
    if (id &lt;= 0)
        throw new ArgumentException(nameof(id));

    var emp = _employees.FirstOrDefault(e =&gt; e.Id == id);
    if (emp != null)
    {
        _employees.Remove(emp);
    }

    return Task.FromResult(id);
}

public Task&lt;int&gt; UpdateEmployee(Employee employee)
{
    if (employee is null)
        throw new ArgumentNullException(nameof(employee));
    if (String.IsNullOrWhiteSpace(employee.FirstName)
        || String.IsNullOrEmpty(employee.FirstName))
    {
        return Task.FromResult(0);
    }
    if (String.IsNullOrWhiteSpace(employee.LastName)
        || String.IsNullOrEmpty(employee.LastName))
    {
        return Task.FromResult(0);
    }

    var emp = _employees.FirstOrDefault(e =&gt; e.Id == employee.Id);
    if (emp != null)
    {
        emp.FirstName = employee.FirstName;
        emp.LastName = employee.LastName;
        emp.Phone = employee.Phone;
    }

    return Task.FromResult(employee.Id);
}

}

Для примера еще есть реализация для SqlServer в классе SqlRepository.

Проект написан с использованием MVVM. View основана на UserControl и отображается в окне программы, сорян мне было лень, потому набросал контролы просто на канву, в реальном приложении так делать конечно не надо.

<UserControl x:Class="WpfUI.Views.MainView"
         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:WpfUI.Views"
         mc:Ignorable="d" 
         d:DesignHeight="400" d:DesignWidth="750">
<Canvas Height="400" Width="750">
    <TextBlock Canvas.Left="70" Canvas.Top="99" Text="Имя"/>
    <TextBlock Canvas.Left="70" Canvas.Top="135" Text="Фамилия"/>
    <TextBlock Canvas.Left="70" Canvas.Top="171" Text="Телефон"/>
    <TextBox Canvas.Left="134" Canvas.Top="99" Text="{Binding FirstName}"  Width="120"/>
    <TextBox Canvas.Left="134" Canvas.Top="133" Text="{Binding LastName}" Width="120"/>
    <TextBox Canvas.Left="134" Canvas.Top="169" Text="{Binding Phone}" Width="120"/>
    <Button Content="Добавить" Command="{Binding Add}" Canvas.Left="62" Canvas.Top="225"/>
    <Button Content="Сохранить" Command="{Binding Save}" Canvas.Left="128" Canvas.Top="225" Width="75"/>
    <Button Content="Удалить" Command="{Binding Delete}" Canvas.Left="214" Canvas.Top="225"/>
    <Button Content="Назад" Command="{Binding Prev}" Canvas.Left="82" Canvas.Top="268"/>
    <Button Content="Вперед" Command="{Binding Next}" Canvas.Left="214" Canvas.Top="268"/>
    <DataGrid Height="358"
              Width="450"
              Canvas.Left="282"
              Canvas.Top="21"
              IsReadOnly="True"
              AlternatingRowBackground="LightCyan"
              AutoGenerateColumns="False"
              ItemsSource="{Binding People}"
              SelectedItem="{Binding SelectedEmployee}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="П/Н" Binding="{Binding OrderNumber}" Width="50"/>
            <DataGridTextColumn Header="Фамилия" Binding="{Binding LastName}" Width="150"/>
            <DataGridTextColumn Header="Имя" Binding="{Binding FirstName}" Width="100"/>
            <DataGridTextColumn Header="Телефон" Binding="{Binding Phone}" Width="100"/>
        </DataGrid.Columns>
    </DataGrid>
</Canvas>

На что следует обратить внимание? На привязки:

  • для DataGrid источник данных это свойство People у ViewModel ItemsSource="{Binding People}", выделенная строка это свойство SelectedEmployee SelectedItem="{Binding SelectedEmployee}";
  • текстбокс для Имя привязан к свойству FirstName у ViewModel Text="{Binding FirstName}";
  • к кнопке Сохранить привязано свойство Save в качестве команды Command="{Binding Save}".

Вот класс для ViewModel

class MainViewModel : INotifyPropertyChanged
{
    private Employee _selectedEmployee;
    private Employee _editableEmployee = new Employee(0);
    private List<Employee> _people;
public event PropertyChangedEventHandler PropertyChanged;

public MainViewModel(IEmployeeRepository employeeRepository)
{

    EmployeeRepository = employeeRepository;
    Add = new AddEmployeeCommand(this);
    Save = new SaveEmployeeCommand(this);
    Delete = new DeleteEmployeeCommand(this);
    Next = new SelectNextCommand(this);
    Prev = new SelectPreviosCommand(this);

    LoadPeople().Await(HandleException);
}

//Загрузка из БД списка сотрудников
public async Task LoadPeople()
{
    var employees = await EmployeeRepository.GetEmployees();

    int id = 0;
    employees.ForEach(e =&gt; e.OrderNumber = ++id);
    People = employees;
}

//Обработка ошибки в случае LoadPeople()
private void HandleException(Exception ex)
{
    People = new List&lt;Employee&gt;();
}

//Ссылка на класс репозитория для работы с БД
public IEmployeeRepository EmployeeRepository { get; }

//--Команды для кнопок
public ICommand Add { get; }
public ICommand Save { get; }
public ICommand Delete { get; }
public ICommand Next { get; }
public ICommand Prev { get; }

//--Свойства
//Отображаемая в DataGrid коллекция сотрудников
public List&lt;Employee&gt; People
{
    get =&gt; _people;
    set
    {
        _people = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(People)));
    }
}

//Выделенный в DataGrid сотрудник
public Employee SelectedEmployee
{
    get =&gt; _selectedEmployee;
    set
    {
        if (value == _selectedEmployee)
            return;
        _selectedEmployee = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedEmployee)));
        //Делаем копию для редактируемого сотрудника
        if (_selectedEmployee != null)
        {
            EditableEmployee = Employee.GetClone(_selectedEmployee);
        }
    }
}

//Редактируемый сотрудник
public Employee EditableEmployee
{
    get =&gt; _editableEmployee;
    set
    {
        _editableEmployee = value;
        //оповещаем View об изменении значений свойств
        //c помощью вызова события PropertyChanged для каждого привязанного свойства
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(FirstName)));
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LastName)));
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Phone)));
    }
}

//Имя редактируемого
public string FirstName
{
    get =&gt; _editableEmployee.FirstName;
    set =&gt; _editableEmployee.FirstName = value;
}

//Фамилия редактируемого
public string LastName
{
    get =&gt; _editableEmployee.LastName;
    set =&gt; _editableEmployee.LastName = value;
}

//Телефон редактируемого
public string Phone
{
    get =&gt; _editableEmployee.Phone;
    set =&gt; _editableEmployee.Phone = value;
}

}

Пример реализации команды для кнопки Сохранить такой

class SaveEmployeeCommand : ICommand
{
    private readonly MainViewModel _viewModel;
public event EventHandler CanExecuteChanged;

public SaveEmployeeCommand(MainViewModel viewModel)
{
    _viewModel = viewModel;
}

public bool CanExecute(object parameter)
{
    return true;
}

public async void Execute(object parameter)
{
    int result = 0;
    //если редактируемый новый
    if (_viewModel.EditableEmployee.Id == 0)
    {
        //то добавляем его
        result = await _viewModel.EmployeeRepository
                                 .AddEmployee(_viewModel.EditableEmployee);
    }
    else
    {
        //иначе обновляем
        result = await _viewModel.EmployeeRepository
                                 .UpdateEmployee(_viewModel.EditableEmployee);
    }

    if (result &gt; 0)
    {
        _viewModel.EditableEmployee = new Employee(0);
        await _viewModel.LoadPeople();
    }
    else
    {
        //в случае неудачи...
    }
}

}

Связка между собой View, ViewModel и репозитория в файле App.xaml.cs

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
    //работа с данными в памяти
    var viewModel = new MainViewModel(new TestRepository());

    //или работа с данными из БД
    //var viewModel = new MainViewModel(new SqlRepository());

    //создаем въюшку
    var view = new MainView();
    //подключаем въюмодель в качестве источн.данных
    view.DataContext = viewModel;

    //окно программы
    var window = new MainWindow();
    //отображем въюшку
    window.Output.Content = view;
    //показываем окно
    window.Show();
}

}

Это конечно просто пример, а не законченное приложение.

Bulson
  • 9,411
  • Спасибо конечно, это пример много чего пояснил, но не стоило писать столько кода –  Nov 30 '20 at 21:41
  • Без много кода не получился бы полноценный пример – Bulson Dec 01 '20 at 12:43