簡體   English   中英

WPF DataGrid:DataGridComboxBox ItemsSource 綁定到集合的集合

[英]WPF DataGrid: DataGridComboxBox ItemsSource Binding to a Collection of Collections

情況:

我在 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_
};
//...

任何幫助將不勝感激!

筆記:

好的,所以在閱讀了前兩個答案后,我注意到了一些事情。 我的綁定真的不對! 現在,我想做的是類似於 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")
});

錯誤:“無法將類型‘System.Windows.Data.Binding’隱式轉換為‘System.Collections.IEnumerable’。”

如何將 ItemsSource 綁定到 Data?

首先,這應該很容易……其次,為什么要在 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;
}

結果:

帶有動態組合框選項的 WPF 網格 http://www.singingeels.com/Articles/Articles/UserImage.aspx?ImageID=b1e3f880-c278-4d2b-bcc2-8ad390591200

我認為錯誤在於您如何完成綁定。 定義列時,綁定與由特定行表示的對象相關。 因此,據我所知,您對每一行都有一個 StatsOperation,因此 TextBox 列綁定到操作,這就是您擁有它的方式,而 ComboBox 列 ItemsSource 應該綁定到一個集合。 現在看起來它綁定到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回答了您的問題。 可以?

部分 - 我認為您所說的內容存在混淆。 您說您需要每行中的字符串集合集合,以便組合框可以為不同的行顯示不同的字符串。 但是,對於顯示一組字符串的組合框,每行只需要一個字符串集合,而不是字符串集合的集合。

現在,由於您需要每行的字符串集合,您可能會認為您需要字符串集合的集合。

我對你的問題的理解正確嗎? 如果是這樣,那么您提到的字符串集合集合是錯誤的。

您真正需要的是 StatOperations 的集合,其中每個 StatOperation 都應該有一個字符串集合。 這正是你在上面的課程中所展示的。

為了取得進展,我建議您編輯您的問題並指出在按照 AndyG 的建議修復綁定后您到底卡在哪里。

讓我們將 ComboBox 的 ItemsSource 綁定到一個屬性,例如您的視圖模型的 CurrentChoices。 此屬性應根據您當前的數據網格行選擇返回一個過濾列表。 CompareWithSelectedRow 只是一個用於說明示例的偽函數。 每次,當您單擊 ComboBox 以填充選擇列表時,此屬性將被調用並返回正確的選擇列表。 參見下面的例子,EntireChoiceList 是一個由字符串和列表組成的元組列表。 有改進的空間,例如使用字典或查找。

    List<(string Key, List<string> Choices)> EntireChoiceList= new List<(string, List<string>)>();

    public List<string> CurrentChoices
    {
      get => CurrentChoices.Where(q => CompareWithSelectedRow(q.Key, CurrentRow )).FirstOrDefault().Choices;
    }

public object CurrentRow { get => ItemsView.CurrentItem; }

bool CompareWithSelectedRow(string key, object row)
{
    return key == row; // here you should define compare expression
}

使用 CollectionViewSource 獲取數據網格中的選定行。 項目是綁定到數據網格的視圖模型中的列表。

      ItemsView = (CollectionView)CollectionViewSource.GetDefaultView(Items);
      ItemsView.CurrentItem

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM