86

2つの単純なModelクラスと1つのViewModelがあります...

public class GridItem
{
    public string Name { get; set; }
    public int CompanyID { get; set; }
}

public class CompanyItem
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class ViewModel
{
    public ViewModel()
    {
        GridItems = new ObservableCollection<GridItem>() {
            new GridItem() { Name = "Jim", CompanyID = 1 } };

        CompanyItems = new ObservableCollection<CompanyItem>() {
            new CompanyItem() { ID = 1, Name = "Company 1" },
            new CompanyItem() { ID = 2, Name = "Company 2" } };
    }

    public ObservableCollection<GridItem> GridItems { get; set; }
    public ObservableCollection<CompanyItem> CompanyItems { get; set; }
}

...そしてシンプルなウィンドウ:

<Window x:Class="DataGridComboBoxColumnApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" >
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" />
                <DataGridComboBoxColumn ItemsSource="{Binding CompanyItems}"
                                    DisplayMemberPath="Name"
                                    SelectedValuePath="ID"
                                    SelectedValueBinding="{Binding CompanyID}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

ViewModelはDataContext、App.xaml.csのメインウィンドウに設定されています。

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        MainWindow window = new MainWindow();
        ViewModel viewModel = new ViewModel();

        window.DataContext = viewModel;
        window.Show();
    }
}

ご覧のとおりItemsSource、DataGridGridItemsのをViewModelのコレクションに設定しました。この部分は機能し、名前が「Jim」の単一のグリッド線が表示されます。

ItemsSourceまた、すべての行のComboBoxCompanyItemsのをViewModelのコレクションに設定したいと思います。この部分は機能しません。ComboBoxは空のままで、デバッガー出力ウィンドウにエラーメッセージが表示されます。

System.Windows.Dataエラー:2:ターゲット要素の支配的なFrameworkElementまたはFrameworkContentElementが見つかりません。BindingExpression:Path = CompanyItems; DataItem = null; ターゲット要素は'DataGridComboBoxColumn'(HashCode = 28633162); ターゲットプロパティは「ItemsSource」(タイプ「IEnumerable」)です。

WPFは、そうではないCompanyItemsプロパティであると期待していると思いGridItemます。それが、バインディングが失敗する理由です。

私はすでにaなどで作業しようとしましRelativeSourceAncestorType

<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems, 
    RelativeSource={RelativeSource Mode=FindAncestor,
                                   AncestorType={x:Type Window}}}"
                        DisplayMemberPath="Name"
                        SelectedValuePath="ID"
                        SelectedValueBinding="{Binding CompanyID}" />

しかし、それは私にデバッガー出力で別のエラーを与えます:

System.Windows.Dataエラー:4:参照'RelativeSource FindAncestor、AncestorType ='System.Windows.Window'、AncestorLevel='1''でバインドするためのソースが見つかりません。BindingExpression:Path = CompanyItems; DataItem = null; ターゲット要素は'DataGridComboBoxColumn'(HashCode = 1150788); ターゲットプロパティは「ItemsSource」(タイプ「IEnumerable」)です。

質問:DataGridComboBoxColumnのItemsSourceをViewModelのCompanyItemsコレクションにバインドするにはどうすればよいですか?それは可能ですか?

よろしくお願いします!

4

8 に答える 8

130

pls、以下のDataGridComboBoxColumnxamlが機能するかどうかを確認してください。

<DataGridComboBoxColumn 
    SelectedValueBinding="{Binding CompanyID}" 
    DisplayMemberPath="Name" 
    SelectedValuePath="ID">

    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="{x:Type ComboBox}">
            <Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>

ここで、直面している問題の別の解決策を見つけることができます。WPFDataGridでコンボボックスを使用する

于 2011-03-23T18:37:23.603 に答える
48

に関するMSDNItemsSourceDataGridComboBoxColumnのドキュメントには、静的リソース、静的コード、またはコンボボックスアイテムのインラインコレクションのみをバインドできると記載されていItemsSourceます。

ドロップダウンリストにデータを入力するには、最初に次のいずれかのオプションを使用して、ComboBoxのItemsSourceプロパティを設定します。

  • 静的リソース。詳細については、StaticResourceMarkupExtensionを参照してください。
  • x:Staticコードエンティティ。詳細については、x:StaticMarkupExtensionを参照してください。
  • ComboBoxItemタイプのインラインコレクション。

私がそれを正しく理解していれば、DataContextのプロパティにバインドすることはできません。

そして確かに:ViewModelで静的CompanyItemsプロパティを作成すると...

public static ObservableCollection<CompanyItem> CompanyItems { get; set; }

...ViewModelが配置されている名前空間をウィンドウに追加します...

xmlns:vm="clr-namespace:DataGridComboBoxColumnApp"

...そしてバインディングを...に変更します

<DataGridComboBoxColumn
    ItemsSource="{Binding Source={x:Static vm:ViewModel.CompanyItems}}" 
    DisplayMemberPath="Name"
    SelectedValuePath="ID"
    SelectedValueBinding="{Binding CompanyID}" />

...それからそれは働きます。ただし、ItemsSourceを静的プロパティとして使用しても問題がない場合もありますが、必ずしも必要なものとは限りません。

于 2011-03-23T20:22:32.190 に答える
42

正しい解決策は次のようです:

<Window.Resources>
    <CollectionViewSource x:Key="ItemsCVS" Source="{Binding MyItems}" />
</Window.Resources>
<!-- ... -->
<DataGrid ItemsSource="{Binding MyRecords}">
    <DataGridComboBoxColumn Header="Column With Predefined Values"
                            ItemsSource="{Binding Source={StaticResource ItemsCVS}}"
                            SelectedValueBinding="{Binding MyItemId}"
                            SelectedValuePath="Id"
                            DisplayMemberPath="StatusCode" />
</DataGrid>

上記のレイアウトは私にとっては完全にうまく機能し、他の人にとっても機能するはずです。この設計の選択も理にかなっていますが、どこにも十分に説明されていません。ただし、事前定義された値を持つデータ列がある場合、それらの値は通常、実行時に変更されません。したがってCollectionViewSource、データを作成して初期化することは理にかなっています。また、祖先を見つけてそのデータコンテキストにバインドするために、より長いバインディングを取り除きます(これは常に私には間違っていると感じていました)。

このバインディングに苦労している他の人のためにこれをここに残し、より良い方法があるかどうか疑問に思いました(このページは明らかに検索結果に表示されているので、それが私がここに到達した方法です)。

于 2015-01-29T04:46:11.793 に答える
24

この質問は1年以上前のものであることに気付きましたが、同様の問題に対処する際に偶然見つけたので、将来の旅行者(または後でこれを忘れて自分自身を見つけたとき)に役立つ可能性がある場合に備えて、別の解決策を共有したいと思いましたStackOverflowで、机の上の最も近いオブジェクトの悲鳴と投げの間でフロップします)。

私の場合、次のスニペットのように、DataGridComboBoxColumnの代わりにDataGridTemplateColumnを使用することで、必要な効果を得ることができました。[注意:私は.NET 4.0を使用しています。私が読んでいることから、DataGridは多くの進化を遂げたと思います。したがって、以前のバージョンを使用している場合はYMMV]

<DataGridTemplateColumn Header="Identifier_TEMPLATED">
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox IsEditable="False" 
                Text="{Binding ComponentIdentifier,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                ItemsSource="{Binding Path=ApplicableIdentifiers, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ComponentIdentifier}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
于 2012-08-13T21:09:42.253 に答える
8

RookieRickは正しいです。DataGridTemplateColumn代わりに使用するとDataGridComboBoxColumn、はるかに単純なXAMLが得られます。

さらに、CompanyItemから直接アクセスできるリストをGridItem配置すると、を取り除くことができますRelativeSource

私見、これはあなたに非常にきれいな解決策を与えます。

XAML:

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" >
    <DataGrid.Resources>
        <DataTemplate x:Key="CompanyDisplayTemplate" DataType="vm:GridItem">
            <TextBlock Text="{Binding Company}" />
        </DataTemplate>
        <DataTemplate x:Key="CompanyEditingTemplate" DataType="vm:GridItem">
            <ComboBox SelectedItem="{Binding Company}" ItemsSource="{Binding CompanyList}" />
        </DataTemplate>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}" />
        <DataGridTemplateColumn CellTemplate="{StaticResource CompanyDisplayTemplate}"
                                CellEditingTemplate="{StaticResource CompanyEditingTemplate}" />
    </DataGrid.Columns>
</DataGrid>

モデルを見る:

public class GridItem
{
    public string Name { get; set; }
    public CompanyItem Company { get; set; }
    public IEnumerable<CompanyItem> CompanyList { get; set; }
}

public class CompanyItem
{
    public int ID { get; set; }
    public string Name { get; set; }

    public override string ToString() { return Name; }
}

public class ViewModel
{
    readonly ObservableCollection<CompanyItem> companies;

    public ViewModel()
    {
        companies = new ObservableCollection<CompanyItem>{
            new CompanyItem { ID = 1, Name = "Company 1" },
            new CompanyItem { ID = 2, Name = "Company 2" }
        };

        GridItems = new ObservableCollection<GridItem> {
            new GridItem { Name = "Jim", Company = companies[0], CompanyList = companies}
        };
    }

    public ObservableCollection<GridItem> GridItems { get; set; }
}
于 2013-09-23T11:16:19.570 に答える
4

ComboBoxは、にバインドしようとしGridItem[x].CompanyItemsていますが、これは存在しません。

RelativeBindingは近いですが、DataContext.CompanyItemsWindow.CompanyItemsが存在しないため、バインドする必要があります

于 2011-03-23T17:39:39.120 に答える
2

私が使用する最も基本的な方法は、テキストブロックとコンボボックスを同じプロパティにバインドし、このプロパティはnotifyPropertyChangedをサポートする必要があります。

私はrelativeresourceを使用して親ビューのdatacontextにバインドしました。これは、バインド時にdatagridレベルを上げるためのusercontrolです。この場合、datagridはdatagrid.itemsourceで使用したオブジェクトを検索するためです。

<DataGridTemplateColumn Header="your_columnName">
     <DataGridTemplateColumn.CellTemplate>
          <DataTemplate>
             <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.SelectedUnit.Name, Mode=TwoWay}" />
           </DataTemplate>
     </DataGridTemplateColumn.CellTemplate>
     <DataGridTemplateColumn.CellEditingTemplate>
           <DataTemplate>
            <ComboBox DisplayMemberPath="Name"
                      IsEditable="True"
                      ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.UnitLookupCollection}"
                       SelectedItem="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.SelectedUnit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                      SelectedValue="{Binding UnitId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                      SelectedValuePath="Id" />
            </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
于 2017-02-10T01:00:12.580 に答える
0

これは私のために働いています:


<DataGridTemplateColumn Width="*" Header="Block Names">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox
                VerticalContentAlignment="Center"
                ItemsSource="{Binding DataContext.LayerNames,
                RelativeSource={RelativeSource Findancestor,
                AncestorType={x:Type Window}}}"
                SelectedItem="{Binding LayerName, Mode=TwoWay,
                UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
于 2021-08-16T08:04:58.640 に答える