WPF DataGrid:コレクションのコレクションへのDataGridComboxBox ItemsSourceバインディング
-
06-07-2019 - |
質問
状況:
XAMLでDataGridを作成しました。ItemsSourceは、プロパティを含む特定のクラスのObservableCollectionにバインドされています。次に、C#でDataGridTextColumnとDataGridComboBoxColumnを作成し、ObservableCollection内のオブジェクトのプロパティにバインドしました。 DataGridComboBoxColumnをシンプルなコレクションにバインドできますが、行ごとにDataGrid内のComboBoxが異なる文字列のコレクションを持つように、文字列のコレクションのコレクションにバインドします。失敗しました...
質問:
DataGridCombBoxColumnをバインドして、このタイプの列の行ごとに異なる文字列のコレクションを作成するにはどうすればよいですか?
コードサンプル:
XAML:
<Window>
<!-- ... -->
WPFToolkit:DataGrid
x:Name="DG_Operations"
Margin="10,5,10,5"
Height="100"
HorizontalAlignment="Stretch"
FontWeight="Normal"
ItemsSource="{Binding Path=OperationsStats}"
AlternatingRowBackground="{DynamicResource SpecialColor}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
SelectionMode="Extended"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserResizeRows="True"
CanUserSortColumns="True"
AutoGenerateColumns="False"
IsReadOnly="False"
IsEnabled="True"
BorderThickness="1,1,1,1"
VerticalAlignment="Stretch"/>
<!-- ... -->
</Window>
C#:
public class DataModelStatsOperations
{
public ObservableCollection<IStatsOperation> OperationsStats { get; set; }
}
public interface IStatsOperation
{
string Operation { get; set; }
Collection<string> Data{ get; set; }
}
public class StatsOperation : IStatsOperation
{
public StatsOperation(string operation, Collection<string> data)
{
Operation = operation;
Data = data;
}
public string Operation { get; set; }
public Collection<string> Data{ get; set; }
}
private ObservableCollection<IStatsOperation> dataOperations_ =
new ObservableCollection<IStatsOperation>();
//...
Binding items = new Binding();
PropertyPath path = new PropertyPath("Operation");
items.Path = path;
DG_Operations.Columns.Add(new DataGridTextColumn()
{
Header = "Operations",
Width = 133,
Binding = items
});
DG_Operations.Columns.Add(new DataGridComboBoxColumn()
{
Header = "Data",
Width = 190,
ItemsSource = /*???*/,
SelectedValueBinding = new Binding("Data"),
TextBinding = new Binding("Data")
});
dataOperations_.Add(new StatsOperation(CB_Operation.SelectedItem.ToString(),
dataCollection));
DG_Operations.DataContext = new DataModelStatsOperations
{
OperationsStats = dataOperations_
};
//...
ご協力いただければ幸いです!
注:
さて、最初の2つの答えを読んだ後、何かに気付きました。私のバインディングは本当に正しくありません!今、私がやりたいことは、AndyGが提案したものに似たものです:
DG_Operations.Columns.Add(new DataGridComboBoxColumn()
{
Header = "Data",
Width = 190,
ItemsSource = new Binding("Data"), //notice this here does not work (have a look at the following error)
SelectedValueBinding = new Binding("Operation"),
TextBinding = new Binding("Operation")
});
エラー:<!> quot;型 'System.Windows.Data.Binding'を暗黙的に 'System.Collections.IEnumerable'に変換できません。<!> quot;
ItemsSourceをデータにバインドするにはどうすればよいですか
解決
第一に、これは簡単なはずです...第二に、なぜC#で列を構築(およびバインド)するのですか?ええ。
XAML (私は怠け者なので通常のグリッドを使用しています):
<ListView Name="MyListView">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn DisplayMemberBinding="{Binding Operation}" />
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Choices}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
C#:
void Window1_Loaded(object sender, RoutedEventArgs e)
{
var dahList = new List<StatsOperation>();
dahList.Add(new StatsOperation
{
Operation = "Op A",
Choices = new string[] { "One", "Two", "Three" },
});
dahList.Add(new StatsOperation
{
Operation = "Op B",
Choices = new string[] { "4", "5", "6" },
});
this.MyListView.ItemsSource = dahList;
}
結果:
他のヒント
間違いは、バインディングをどのように行ったかにあると思います。列を定義すると、バインディングは特定の行で表されるオブジェクトに関連付けられます。私が理解しているように、各行にStatsOperationがあるため、TextBox列はoperationにバインドされており、これがどのようになっているのか、ComboBox列ItemsSourceはCollectionにバインドされる必要があります。今はCollection<Collection<string>>
にバインドされているように見えます。
コードビハインドで列を定義したことがないので、XAMLの例を次に示します。 ComboBoxColumnは時々トリッキーになることがあるので、TemplateColumnまたはComboBoxColumnを使用して列にコンボボックスを配置する方法を示しました。私は自分のコードから貼り付けたので、「dg」を「WPFToolkit」に置き換えてください:
<dg:DataGrid
...
...>
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Binding="{Binding Operation}" CanUserReorder="True" CanUserResize="True" Header="Operation" />
<dg:DataGridTemplateColumn CanUserReorder="True" CanUserResize="True" Header="Template Column">
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Data}" SelectedItem="{Binding Operation}" />
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
<dg:DataGridComboBoxColumn
Header="ComboBox Column"
SelectedValueBinding="{Binding Operation}"
SelectedItemBinding="{Binding Operation}">
<dg:DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
<Setter Property="ItemsSource" Value="{Binding Data}" />
</Style>
</dg:DataGridComboBoxColumn.ElementStyle>
<dg:DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Data}" />
<Setter Property="IsDropDownOpen" Value="True" />
</Style>
</dg:DataGridComboBoxColumn.EditingElementStyle>
</dg:DataGridComboBoxColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
Operationは選択されたアイテムであり、Dataは選択するアイテムであり、DataGridはStatsOperationのコレクションにバインドされていると仮定しています。がんばって!
ItemsSourceバインディングエラーを修正するには、次の形式を使用します。
BindingOperations.SetBinding(new DataGridComboBoxColumn(), DataGridComboBoxColumn.ItemsSourceProperty, new Binding("Data"));
明らかに、初期化ではこれを行うことができないので、宣言を少し移動する必要がありますが、更新時にそのエラーを処理する必要があります。
編集すみません、真夜中に少し遅くなります:)。更新された回答があります。 Vincent Sibalの素晴らしい記事のようです WPF DataGrid-DataGridComboBoxColumn v1 Intro が質問に答えます。ありますか?
部分的-あなたが言っていることに混乱があると思います。コンボボックスが行ごとに異なる文字列を表示できるように、各行に文字列のコレクションのコレクションが必要だと言いました。ただし、コンボボックスに文字列のセットを表示するには、文字列のコレクションのコレクションではなく、行ごとの文字列のコレクションのみが必要です。
行ごとに文字列のコレクションが必要なため、文字列のコレクションのコレクションが必要になると考えているかもしれません。
あなたの質問に対する私の理解は正しいですか?もしそうなら、文字列のコレクションのコレクションについてのあなたの言及は間違っています。
実際に必要なのは、各StatOperationが文字列のコレクションを持つStatOperationsのコレクションです。これは、上記のクラスで示したとおりです。
進行するには、質問を編集し、AndyGが示唆するようにバインディングを修正した後に正確にスタックした場所を指摘することをお勧めします。