2015-07-17 5 views
3

Мой первый вопрос в StackExchange, так скажите мне, если я что-то сделаю неправильно.Настройка ItemSource в DataGridComboBoxColumn Использование отдельной таблицы базы данных

Я преобразовываю старый код winforms в WPF, и я склоняю их обоих по пути. Я был успешным большую часть времени, но я привязываю свою первую таблицу данных с привязкой данных. Кажется, что самое сложное преобразование, поскольку привязка обрабатывается в основном в xaml, а не в коде.

В качестве дополнительного примечания используется CSLA, который, насколько я понимаю, является структурой кода, подобной MVVM (все еще изучая, что это такое).

С небольшим количеством экспериментов мне удалось создать функционирующую сетку данных, но мне нужно реализовать один из столбцов как поле со списком. Он представлен в настоящее время как число (1-10), но мне нужно описание, которое идет с номером, который находится в другой таблице в базе данных.
Число, которое изначально отображалось перед переключением его в выпадающий список, было неосуществимым. Я хочу, чтобы это значение было выбранным в данный момент элементом в поле со списком.

Не можете размещать изображения, так вот моя попытка показывает структуру таблиц базы данных:

modreview

  • reviewnum
  • intcaseno
  • newreferral
  • screendate
  • имеет право
  • noneligibilityreason (это тот, чтобы сделать в ComboBox)

noneligreason (это субтаблица, который совпадет с noneligibilityreason)

  • noneligreasonid
  • noneligreasondesc

Код включает эту функцию Тион, который, кажется, чтобы создать коллекцию, которая должна быть, как мне кажется, ItemsSource:

NERList.GetNameValueList(); 

Что касается ItemsSource, я хочу все noneligreasondesc значений. Конечно, тогда возникает вопрос о том, чтобы нелимитируемый разум соответствовал неэлигрэзониду.Я нашел this example, который, кажется, делает то же самое, но без базы данных, используя классы вместо:

Я попытался повторить это, как я думал, что он должен работать здесь, в моем XAML:

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:WpfTestProject"  x:Class="WpfTestProject.MainWindow" 
    Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded"> 
<Window.Resources> 
    <local:caseviewDataSet x:Key="caseviewDataSet"/> 
    <CollectionViewSource x:Key="modreviewViewSource" 
          Source="{Binding modreview, Source={StaticResource caseviewDataSet}}"/> 
    <CollectionViewSource x:Key="noneligibilityViewSource" 
          Source="{Binding noneligreason, Source={StaticResource caseviewDataSet}}"/> 
</Window.Resources> 
<Grid DataContext="{StaticResource modreviewViewSource}"> 
    <Grid.RowDefinitions> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 
    <DataGrid x:Name="modreviewDataGrid" 
       RowDetailsVisibilityMode="VisibleWhenSelected" 
       ItemsSource="{Binding}" 
       EnableRowVirtualization="True" 
       AutoGenerateColumns="False">    
     <DataGrid.Columns> 
      <DataGridTextColumn x:Name="reviewnumColumn" Width="SizeToHeader" Header="reviewnum" Binding="{Binding reviewnum}"/> 
      <DataGridTextColumn x:Name="intcasenoColumn" Width="SizeToHeader" Header="intcaseno" Binding="{Binding intcaseno}"/> 
      <DataGridCheckBoxColumn x:Name="newreferralColumn" Width="SizeToHeader" Header="newreferral" Binding="{Binding newreferral}"/> 
      <DataGridTemplateColumn x:Name="screendateColumn" Width="Auto" Header="screendate"> 
       <DataGridTemplateColumn.CellTemplate> 
        <DataTemplate> 
         <DatePicker SelectedDate="{Binding screendate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"/> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellTemplate> 
      </DataGridTemplateColumn> 
      <DataGridCheckBoxColumn x:Name="eligibleColumn" Width="SizeToHeader" Header="eligible" Binding="{Binding eligible}"/> 
      <DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason" 
            ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}" 
            SelectedValueBinding="{Binding noneligibilityreason}" 
            DisplayMemberPath="Value" 
            SelectedValuePath="Key" 
             /> 

     </DataGrid.Columns> 
    </DataGrid> 
</Grid> 

И код позади:

using CslaFactoryBusinessObjects; 
... 

namespace WpfTestProject 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 

      WpfTestProject.caseviewDataSet caseviewDataSet = ((WpfTestProject.caseviewDataSet)(this.FindResource("caseviewDataSet"))); 
      // Load data into the table modreview. You can modify this code as needed. 
      WpfTestProject.caseviewDataSetTableAdapters.modreviewTableAdapter caseviewDataSetmodreviewTableAdapter = new WpfTestProject.caseviewDataSetTableAdapters.modreviewTableAdapter(); 
      caseviewDataSetmodreviewTableAdapter.Fill(caseviewDataSet.modreview); 
      System.Windows.Data.CollectionViewSource modreviewViewSource =  ((CollectionViewSource)(this.FindResource("modreviewViewSource"))); 
      modreviewViewSource.View.MoveCurrentToFirst(); 

      noneligibilityreasonColumn.ItemsSource = NERList.GetNameValueList(); 
    } 
} 

}

Большая часть этого кода была сгенерирована, когда я перетаскивал данные из источников данных, но последняя строка в коде позади - это то место, где я думаю, что я должен был добавить ItemSource. Не уверен, что он принадлежит Loaded, но похоже, что все в порядке. Также не уверен, есть ли способ сделать это в XAML.

Я понимаю, что я дублировал настройки ItemsSource в XAML и коде, но никто не работает должным образом, поэтому я включил оба, чтобы показать, какие параметры я попробовал.

Наконец, я думаю, что должен показать старый код winforms, который я пытаюсь подражать в преобразовании WPF (не уверен, что этого достаточно кода). Я думаю, что он использует скрытый выпадающий настроить связывание, а затем добавляет его к столу:

//from Program.cs used in setupModRvwGrdHdr() 
public static void ListControlBinding(ref UltraCombo comboBox, object lkupdataSource, string displayMember, 
              string valueMember, object objDataSource, string objProp) { 
     comboBox.DataSource = lkupdataSource; 
     comboBox.DisplayMember = displayMember; 
     if (!string.IsNullOrEmpty(valueMember)) 
      comboBox.ValueMember = valueMember; 
     if (objDataSource != null) 
      comboBox.DataBindings.Add("Value", objDataSource, objProp); 
    } 


//from the code for the specific winform 
private void setupModRvwGrdHdr() { 
     cbNonEligReason.DataBindings.Clear(); 
     grdModReviews.DataSource = bsModRvws; 

     Program.ListControlBinding(ref cbNonEligReason, NERList.GetNameValueList(), "Value", "Key", bsModRvws, 
      "NonEligibleReasonIDStr"); 
     cbNonEligReason.DisplayLayout.Bands[0].Columns["Key"].Hidden = true; 
     cbNonEligReason.DisplayLayout.Bands[0].Columns["Value"].Header.Caption = "Noneligiblity Reason"; 

     grdModReviews.DisplayLayout.Bands[0].Columns["reviewnum"].CellActivation = Activation.NoEdit; 
     grdModReviews.DisplayLayout.Bands[0].Columns["intcaseno"].Hidden = true; 
     grdModReviews.DisplayLayout.Bands[0].Columns["noneligibilityreason"].Hidden = true; 

     grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].Hidden = false; 
     grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].Header.Caption = "Date of Screen"; 
     grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].Width = 100; 
     grdModReviews.DisplayLayout.Bands[0].Columns["screendate"].EditorComponent = dteModRvwDate; 

     grdModReviews.DisplayLayout.Bands[0].Columns["eligible"].Hidden = false; 
     grdModReviews.DisplayLayout.Bands[0].Columns["eligible"].Header.Caption = "Eligible"; 
     grdModReviews.DisplayLayout.Bands[0].Columns["eligible"].Width = 70; 

     grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Hidden = false; 
     grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Header.Caption = 
      "Reason for Noneligibility"; 
     grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Width = 250; 
     grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].EditorComponent = cbNonEligReason; 
     grdModReviews.DisplayLayout.Bands[0].Columns["NonEligibleReasonIDStr"].Nullable = 
      Infragistics.Win.UltraWinGrid.Nullable.Nothing; 
    } 

Это достаточно большая программа, и там могут быть некоторые полезные функции в классах CslaFactoryBusinessObjects, но я думаю, что я должен научиться, как это сделать, чтобы лучше понять манипуляции с данными в WPF.

Я искал решение в течение нескольких дней и не нашел случая, подобного моему. Я просто не уверен, как работает каждый из свойств привязки и как они применяются в этом конкретном случае. Наконец пришлось бросить полотенце и сделать счет здесь. Извините за длину, но я хотел быть конкретным и показать, что я был на это некоторое время.

Пожалуйста, помогите!

ответ

1

Здесь много полезной информации, и хорошее начало для вопроса SO.

Учитывая ваш XAML связывания:

<DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason" 
            ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}" 
            SelectedValueBinding="{Binding noneligibilityreason}" 
            DisplayMemberPath="Value" 
            SelectedValuePath="Key" 
             /> 

Что это сказать, что (для каждой строки из DataGrid - который, в свою очередь, является modreview объект/грести из DataTable внутри DataSet) контроль COMBOBOX должен использовать noneligibilityViewSource для своего списка выбираемых товаров.

(Давайте проигнорируем противоречивую настройку источника элемента в событии Window_Loaded).

В нем также говорится, что для дисплея combobox (который визуально отображается в элементе управления) должен исходить из свойства «Значение», как указано в DisplayMemberPath. Это будет соответствовать тому же именованному свойству из элемента в коллекции, заданного ItemSource.

Поскольку элементы combobox предоставлены привязкой ItemSource, то они будут поступать из noneligibilityViewSource, поэтому следующий вопрос - это то, что находится внутри этого noneligibilityViewSource?

Вы это декларируется как ресурс для этого окна:

<CollectionViewSource x:Key="noneligibilityViewSource" Source="{Binding noneligreason, Source={StaticResource caseviewDataSet}}" /> 

Вышеуказанные состояния, что экземпляр CollectionViewSource (ака noneligibilityViewSource) исходит из свойства называется noneligreason на caseviewDataSet. Учитывая, как работают DataSets, я ожидаю либо DataTable по имени noneligreason, либо настраиваемый DataSet с добавленным свойством для этого. Вероятно, первый.

Теперь у вас есть противоречивый код в событии Window_Loaded, который программно устанавливает ItemSource для combobox для чего-то еще. В частности, к результату обращения к NERList.GetNameValueList();. Я говорю противоречиво, потому что в заявлении ресурса XAML говорится, что этот список значений нелимитирования поступает из соответствующего именованного свойства в DataSet, в то время как в коде в этом случае используется список объектов бизнес-объекта CSLA.

Вам нужно выяснить, какой из них вы хотите использовать.

PS: Скорее всего, если свойство noneligibility в DataSet содержит данные, то нет необходимости платить хит производительности доступа к базе данных снова с вызовом NERList.GetNameValueList();, потому что у вас есть данные уже доступны.

После того, как вы определили, какой «источник» содержит список элементов для вашего списка, то есть. noneligreason DataTable в caseviewDataSet или из списка бизнес-объектов CSLA, возвращенного вызовом NERList.GetNameValueList(); - только тогда вы можете узнать, какое свойство должно использоваться для DisplayMemberPath и какое свойство для SelectedValuePath.

Так что, если ItemSource для combobox соответствует объявленному XAML, а caseviewDataSet имеет другой DataTable, называемый noneligreason, то из этого вам нужно узнать, что такое имена свойств. Например, это может быть noneligreasonid и noneligreasondesc, но это может быть что-то еще в зависимости от того, что делает адаптер таблицы. Ваша привязка DisplayMemberPath может тогда быть noneligreasondesc, и тогда ваш SelectedValuePath может быть noneligreasonid.

Если ItemSource для combobox должен исходить от вызова до NERList.GetNameValueList();, то вам нужно определить, какие имена свойств возвращаемых объектов. Из соглашения об именах я предполагаю, что это «Имя» и «Значение», что означает, что DisplayMemberPath должно быть Value, а SelectedValuePath должно быть установлено на Name. Угадать нехорошо, поэтому идите и посмотрите на этот объект, или используйте отладчик для проверки значений.

SelectedValueBinding свойства относится к свойству на объекте modreview строк, который должен содержать значение выбранного элемента поля со списком, в частности, SelectedValuePath свойства из элемента будет поле со списком, приложенных к SelectedValueBinding собственности на экземпляре modreview.

Следующая документация MSDN должна помочь вам понять, что представляют собой различные свойства в DataGridComboBoxColumn.https://msdn.microsoft.com/en-us/library/system.windows.controls.datagridcomboboxcolumn(v=vs.110).aspx

Так, например, ваш XAML может измениться, чтобы быть одним из следующих двух заявлений:

<DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason" 
             ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}" 
             SelectedValueBinding="{Binding noneligibilityreason}" 
             DisplayMemberPath="noneligreasondesc" 
             SelectedValuePath="noneligreasonid" 
              /> 

или

<DataGridComboBoxColumn x:Name="noneligibilityreasonColumn" Width="SizeToHeader" Header="noneligibilityreason" 
             ItemsSource="{Binding Source={StaticResource noneligibilityViewSource}}" 
             SelectedValueBinding="{Binding noneligibilityreason}" 
             DisplayMemberPath="Value" 
             SelectedValuePath="Name" 
              /> 

Надежда, что помогает.

+0

Ваш первый пример заставил его работать. Кроме того, ваше объяснение (наряду с работающим примером для работы) позволило выяснить, что делает каждый из этих четырех свойств. Единственный вопрос, который я оставил, - это хороший способ сделать то, что я хочу. Из того, что я понимаю, CSLA - это все, что касается разделения слоев, с доступом к данным и пользовательским интерфейсом, насколько это возможно, для обеспечения безопасности и защиты данных. Для этого нужен адаптер для таблицы? Или я ошибочно пропускаю бизнес-уровень? – MichaelN

+1

@MichaelN Вы правы, что CSLA разрешает (как минимум) логическое расслоение, что, в свою очередь, позволяет вам физически распределять/распределять ваш код, если это необходимо для его нужд. Тем не менее, мы сейчас входим в архитектуру решения и не зная, какие компромиссы были сделаны над другими, и, самое главное, я не хочу комментировать «что лучше». Тем не менее, ваш пример, похоже, смешивает ADO.NET + DataSet с CSLA. Если это временный переходный штраф, а если нет, поймите почему. Книги по-прежнему актуальны (Expert C# Business Objects или CSLA 4 ebooks) https://goo.gl/z17bV3 – Jaans