Помогите сделать составной DataGridComboBoxColumn для вывода ФИ

WPF
  1. 5 года назад
    Добавлено 5 года назад pilik

    Наверняка задача стандартная и многие кто работает с БД сталкивался ее реализовывают, Есть БД (SQLServer) в которой есть таблица Employee с полями Surname Name и MiddleName, так же есть форма wpf с датагридом в которой есть комбобокс в который требуется вывести составное ФИО из вышеперечисленных полей.
    Вот как у меня реализовано для вывода одного какого нить поля (например Surname)
    Разметка XAML

    <Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase" x:Class="frm_restrictions"
        Title="WPF" Height="600" Width="800" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" VerticalContentAlignment="Center">
        <Window.Resources>
            <CollectionViewSource x:Key="EVS" Source="{Binding Employee, Source={StaticResource DS}}" IsLiveSortingRequested="True" >
                <CollectionViewSource.SortDescriptions>
                    <ComponentModel:SortDescription Direction="Ascending" PropertyName="Surname"></ComponentModel:SortDescription>
                </CollectionViewSource.SortDescriptions>
            </CollectionViewSource>
        </Window.Resources>
    ....
                    <DataGridComboBoxColumn 
                        ItemsSource="{Binding Source={StaticResource EVS}}"
    					Header="Сотрудник"
    					SelectedValuePath="ID"
    					SelectedValueBinding="{Binding EmployeeID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        DisplayMemberPath="Surname"
                        Width="Auto"></DataGridComboBoxColumn>
    

    в коде происходит заполнение коллекции данными и все работает, но выводит только одну фамилию, но как сделать что бы выводило ФИО я так и не смог добиться (вариант с впихиванием в комбобокс нескольких textbox пока не рассматриваю, потому как хочу разобраться с привязкой данных).

    Был вариант использовать <Multibinding></Multibinding>
    И Вот как я его использовал:

                    <DataGridComboBoxColumn 
                        ItemsSource="{Binding Source={StaticResource EVS}}"
    					Header="Сотрудник"
    					SelectedValuePath="ID"
    					SelectedValueBinding="{Binding EmployeeID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                        Width="Auto">
                        <DataGridComboBoxColumn.DisplayMemberPath>
                            <MultiBinding StringFormat="{}{0}, {1}" >
                                <Binding Path="Surname"></Binding>
                                <Binding Path="Name"></Binding>
                            </MultiBinding>
                        </DataGridComboBoxColumn.DisplayMemberPath>
                        
                    </DataGridComboBoxColumn>

    в результате получил в выводе ошибку и значение в каждой строке system.data.datagridviewRow

    System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Name; DataItem=null; target element is 'DataGridComboBoxColumn' (HashCode=56342263); target property is 'DisplayMemberPath' (type 'String')

    После модификации в:

     <DataGridComboBoxColumn.DisplayMemberPath>
                            <MultiBinding StringFormat="{}{0}, {1}" >
                                <Binding Path="Surname" Source="{StaticResource EVS}"></Binding>
                                <Binding Path="Name" Source="{StaticResource EVS}"></Binding>
                            </MultiBinding>
                        </DataGridComboBoxColumn.DisplayMemberPath>

    в выводе ошибка пропала но результат так же вместо ФИО отображается значение в каждой строке system.data.datagridviewRow.

    Подскажите как решить эту элементарную задачу 4 вариантами (как я полагаю она может быть решена) дабы расставить все точки над i и наконец понять что и как делать:

    1. Через привязку как я пытаюсь сделать БЕЗ конвертера
    2. Через привязку, с использованием конвертера ( если по другому нельзя)
    3. Через составные части в комбобоксе (например текст боксы)
    4. Возможно как то можно через статическое свойство (property) определяемое в коде.

    p.s. Конечно можно попробовать сделать новую таблицу в которой в запросе собирать требуемую строку и подавать уже в компонент, но я не знаю насколько рекомендуется это делать и является ли это легким вариантам в сравнении с привязкой данных в wpf.
    Спасибо.

  2. Alexandr_Erohin

    Apr 17 Администратор
    Добавлено 5 года назад Alexandr_Erohin

    Ну если вы объясните к чему привязывается CollectionViewSource:

    {Binding Employee, Source={StaticResource DS}}

    Если тут приводится ссылка на колекцию пользовательских классов данных, то мне кажется легче добавить доп. свойство, например FullName и привязывать его к DataGridComboBoxColumn.DisplayMemberPath

    public string FullName {
        get { return Name + MiddleName + Surname; }
    }

    Можно написать конвертер если нельзя или нежелательно менять структуру базового класса данных

  3. StaticResource DS

    Да это stong typed class (DataSet) полученный из БД. Создание еще одного столбца на основе данных которые уже хранятся в бд как то неразумно.
    Можете поподробнее куда свойство вставить, внутрь класса Employee?
    И если не трудно можете привести полное описание конвертера.
    Спасибо.

  4. В итоге сделал в БД представление в котором собрал ФИО как строку из нескольких и занес в проект как строго типизированную сущность, после чего привязал ее к DataGridComboBoxColumn.DisplayMemberPath.

  5. Найти это сообщение Alexandr_Erohin Если тут приводится ссылка на колекцию пользовательских классов данных, то мне кажется легче добавить доп. свойство, например FullName и привязывать его к DataGridComboBoxColumn.DisplayMemberPath

    public string FullName {
        get { return Name + MiddleName + Surname; }
    }

    Можно написать конвертер если нельзя или нежелательно менять структуру базового класса данных

    Подскажите как привязать свойство к DataGridComboBoxColumn.DisplayMemberPath, т.е. как будет выглядеть непосредственно строка привязки. Не могу понять какая это привязка, точнее к чему resource, staticresource или просто FullName.
    Надо ли как то объявлять коллекцию.

  6. Alexandr_Erohin

    Apr 22 Администратор
    Добавлено 5 года назад Alexandr_Erohin

    В DisplayMemberPath указывается имя свойства - для DataSet это название столбца DataColumn к которому осуществляется привязка. Я бы мог помочь вам написать конвертер, но мне не хватает данных из приведенного кода (структура БД и объект DataSet к которому осуществляется привязка). Скиньте пример проекта с тестовой базой данных в *.mdf, если это возможно.

    И кстати зачем используется DataGridComboBoxColumn если нужно отобразить просто строку ФИО а не список данных?

  7. Найти это сообщение Alexandr_Erohin И кстати зачем используется DataGridComboBoxColumn если нужно отобразить просто строку ФИО а не список данных?

    что бы можно в табличном интерфейсе (представлении) менять значения в базе данных, и не заморачиваться с созданием отдельного интерфейса под таблицу.

    Найти это сообщение Alexandr_Erohin Скиньте пример проекта с тестовой базой данных в *.mdf, если это возможно.

    А куда скинуть и как?

    Появился еще вопрос, после получения ФИО мне нужно отсортировать список по этим ФИО (средствами datagridView), но когда я щелкаю по заголовку столбца возникает сортировка по значению (valuepath) а не по отображению (displaypath). Готов выслать пример бд и проекта.

или зарегистрируйтесь чтобы ответить