12

次のWPFDataGrid+ComboBoxシナリオを使用します。

私は次のようなクラスのセットを持っています。

class Owner
{
    int ID { get; }
    string Name { get; }

    public override ToString()
    { 
        return this.Name;
    }
}

class House
{
    int ID { get; }
    Owner HouseOwner { get; set; }
}

class ViewModel
{
    ObservableCollection<Owner> Owners;
    ObservableCollection<House> Houses
}

これで、希望する結果は、 Houseタイプの行のリストを表示するDataGridであり、列の1つに、ユーザーがHouse.HouseOwnerの値を変更できるComboBoxがあります。

このシナリオでは、グリッドのDataContextはViewModel.Housesであり、ComboBoxの場合、ItemsSourceをViewModel.Ownersにバインドする必要があります。

これも可能ですか?私はこれに頭を悩ませています...私ができる最善のことは、ItemsSourceを正しくバインドすることですが、ComboBox(DataGridTemplateColumn内)は各行にHouse.HouseOwnerの正しい値を表示していません。

注:ComboBoxを画像から取り出し、代わりにTextBlockをDataTemplateに配置すると、各行の値を正しく表示できますが、ItemsSourceの両方を取得し、選択範囲に正しい値を表示することはできません。 ..。。

コードビハインド内で、ウィンドウのDataContextをViewModelに設定し、グリッドのDataContextをViewModel.Housesに設定しました。このコンボボックス以外のすべてについては、機能しています...

問題のある列のXAMLは次のようになります。

<DataGridTemplateColumn Header="HouseOwner">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox ItemsSource="{Binding Path=DataContext.Owners, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                        DisplayMemberPath="Name"
                        SelectedItem="{Binding HouseOwner, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                        SelectedValue="{Binding HouseOwner.ID, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Mode=OneWay}"
                        SelectedValuePath="ID" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

これについての助けが欲しいです...しかし、少しのブードゥーが必要なようです...

4

4 に答える 4

15

default.kramerが言ったように、このようにバインディングからを削除する必要があります(RelativeSourceコンボボックスの変更がモデルに反映されるように、バインディングに追加する必要があることに注意してください)。SelectedItemSelectedValueMode=TwoWay

<DataGridTemplateColumn Header="House Owner">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox
                ItemsSource="{Binding Path=DataContext.Owners, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                DisplayMemberPath="Name"
                SelectedItem="{Binding HouseOwner, Mode=TwoWay}"
                SelectedValue="{Binding HouseOwner.ID}"
                SelectedValuePath="ID"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

ただし、彼が言ったのとは異なり、のバインディングを削除する必要はありませんSelectedValue。実際、これを削除すると、機能しなくなります(これまでと同様に、ここで設定する必要がSelectedValueありSelectedValuePathます)。これにより、バインディングメカニズムがコンボボックスからDataGridのHouseOwnerプロパティへの選択を識別できるようになります。

SelectedValue/SelectedValuePath組み合わせはとても面白いです。現在選択されているオブジェクトのプロパティがその値を表すことをデータバインディングに通知し、その値SelectedValuePathDataGridで選択されたオブジェクトであるにバインドされる必要があることを通知します。IDOwnerSelectedValueHouseOwner.ID

したがって、これらのバインディングを削除すると、データバインディングメカニズムが認識するのは「選択されたオブジェクト」だけであり、ComboBoxでHouseOwner選択されたアイテムとDataGridで選択されたアイテムのプロパティを対応させるには、次のことを行う必要があります。 「同じオブジェクト参照」である。たとえば、次のことは機能しません。

Owners = new ObservableCollection<Owner>
                {
                    new Owner {ID = 1, Name = "Abdou"},
                    new Owner {ID = 2, Name = "Moumen"}
                };
Houses = new ObservableCollection<House>
                {
                    new House {ID = 1, HouseOwner = new Owner {ID = 1, Name = "Abdou" }},
                    new House {ID = 2, HouseOwner = new Owner {ID = 2, Name = "Moumen"}}
                };

(Housesコレクションの "HouseOwners"は、Ownersコレクションのものとは(新しい)異なることに注意してください)。ただし、以下機能します。

Owners = new ObservableCollection<Owner>
                {
                    new Owner {ID = 1, Name = "Abdou"},
                    new Owner {ID = 2, Name = "Moumen"}
                };
Houses = new ObservableCollection<House>
                {
                    new House {ID = 1, HouseOwner = Owners[0]},
                    new House {ID = 2, HouseOwner = Owners[1]}
                };

お役に立てれば :)

更新: 2番目のケースでは、クラスでEqualsをオーバーライドすることにより、参照を同じにすることなく同じ結果を得ることができますOwner(当然、最初にオブジェクトを比較するために使用されるため)。(以下のコメントでこれに注意してくれた@ RJ Lohanに感謝します)

于 2011-08-17T07:26:45.433 に答える
9

すべての助けに感謝します-私はついにComboBoxアイテムを選択できなかった理由を理解しました-DataGridComboBoxColumnを使用していたときにセルスタイルにアタッチしたマウスプレビューイベントハンドラーが原因でし

他の援助に感謝します。

また、メモとして; これが私にとってうまくいく唯一の方法は、追加することです。

IsSynchronizedWithCurrentItem="False"

ComboBoxに追加されました。それ以外の場合は、何らかの理由ですべて同じ値が表示されます。

また、バインドにSelectedValue / SelectedValuePathプロパティが必要ないようです。これは、バインドされた所有者タイプのEqualsをオーバーライドしたためだと思います。

そして最後に、明示的に設定する必要があります。

Mode = TwoWay、UpdateSourceTrigger = PropertyChanged

バインドでは、ComboBoxが変更されたときに値がバインドされたアイテムに書き戻されるようにします。

したがって、バインディングの最終的な(機能する)XAMLは次のようになります。

    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox 
                ItemsSource="{Binding Path=DataContext.Owners,  
                RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                IsSynchronizedWithCurrentItem="False"
                SelectedItem="{Binding HouseOwner, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>

乾杯!

rJ

于 2011-08-18T00:03:02.630 に答える
3

これは間違いなく可能であり、のAncestorTypeバインディングを使用して正しい方向に進んでいItemsSourceます。しかし、私はいくつかの間違いを見ていると思います。

まず、あなたは正しいではなく、ItemsSourceに拘束する必要がありますか?ビューモデルの所有者のコレクションをドロップダウンに表示する必要があります。したがって、最初に、を変更して、次のように選択関連のものを取り出します。DataContext.OwnersDataContext.HousesItemsSource

<ComboBox ItemsSource="{Binding Path=DataContext.Owners, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
          DisplayMemberPath="Name" />

次に、テストして、ItemsSourceが正しく機能していることを確認します。この部分が機能するまで、選択をいじってみないでください。

選択に関しては、拘束力があるべきだと思いSelectedItemますSelectedValue。このバインディングでは、バインディングは必要ありません。DataContextRelativeSourceは単一にHouseなるため、直接バインドできますHouseOwner。私の推測はこれです:

<ComboBox ItemsSource="{Binding Path=DataContext.Owners, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
          DisplayMemberPath="Name"
          SelectedItem="{Binding HouseOwner}" />

最後に、バインディングのデバッグについては、Visual Studioの[出力]ウィンドウを表示するか、 SnoopWPFInspectorなどのツールにステップアップできます。多くのWPFを実行する予定の場合は、Snoopを早めに開始することをお勧めします。

于 2011-08-17T05:53:06.887 に答える
0

AbdouMoumenの提案に基づく完全な例。SelectedValueとSelectedValuePathも削除されました。

ここに画像の説明を入力してください

//---------
//CLASS STRUCTURES.    
//---------
//One grid row per house.    
public class House
{
    public string name { get; set; }
    public Owner ownerObj { get; set; }
}

//Owner is a combobox choice.  Each house is assigned an owner.    
public class Owner
{
    public int id { get; set; }
    public string name { get; set; }
}

//---------
//FOR XAML BINDING.    
//---------
//Records for datagrid.  
public ObservableCollection<House> houses { get; set; }

//List of owners.  Each house record gets an owner object assigned.    
public ObservableCollection<Owner> owners { get; set; }

//---------
//INSIDE “AFTER CONTROL LOADED” METHOD.  
//---------
//Populate list of owners.  For combobox choices.  
owners = new ObservableCollection<Owner>
{
    new Owner {id = 1, name = "owner 1"},
    new Owner {id = 2, name = "owner 2"}
};

//Populate list of houses.  Again, each house is a datagrid record.  
houses = new ObservableCollection<House>
{
    new House {name = "house 1", ownerObj = owners[0]},
    new House {name = "house 2", ownerObj = owners[1]}
};


<DataGrid ItemsSource="{Binding Path=houses, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" >
    <DataGrid.Columns>
        <DataGridTextColumn Header="name" Binding="{Binding name}" />
        <DataGridTextColumn Header="owner (as value)" Binding="{Binding ownerObj.name}"/>

        <DataGridTemplateColumn Header="owner (as combobox)" >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox
                            ItemsSource="{Binding Path=owners, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                            DisplayMemberPath="name"
                            SelectedItem="{Binding ownerObj, Mode=TwoWay}"
                            />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>

</DataGrid>
于 2017-08-20T00:24:28.600 に答える