DataGrid ComboBox 模板列中的选择更改会清除其他行中的值
Selection change in DataGrid ComboBox template column clears values in other rows
在我的项目中,我有一个 DataGrid
,其中包含两个模板列,每个模板列都包含一个 ComboBox
。当我更改任何行中 ComboBox
之一的选择时,更改会反映在所有行中。
我试过设置 IsSynchronizedWithCurrentItem="False"
,但这没有帮助。
任何人都可以提供解决此问题的方法吗?这是我的代码。
Xaml
<DataGrid
x:Name="dtg"
CanUserAddRows="False"
AutoGenerateColumns="False"
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Pdts, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
IsEditable="True"
ItemsSource="{Binding DataContext.TypeCollection, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
DisplayMemberPath="TypeName"
SelectedItem="{Binding Type}"
SelectedValuePath="Id"
SelectionChanged="ComboBox_SelectionChanged_1"
SelectedValue="{Binding TypeId, Mode= TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Name" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
IsEditable="True"
KeyUp="ComboBox_KeyUp_1"
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding DataContext.PdtCollection, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
DisplayMemberPath="PdtName"
SelectedItem="{Binding Pdt}"
SelectedValuePath="Id"
SelectedValue="{Binding Id, Mode= TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
视图模型
public class MainWindowViewModel : Base {
public ObservableCollection<Type> TypeCollection { get; set; }
public ObservableCollection<Pdt> PdtCollection { get; set; }
public ObservableCollection<PdtAndType> Pdts { get; set; }
public MainWindowViewModel() {
TypeCollection = new ObservableCollection<Type>();
PdtCollection = new ObservableCollection<Pdt>();
Pdts = new ObservableCollection<PdtAndType>();
TypeCollection.Add(new Type {Id = 1, TypeName = "one"});
TypeCollection.Add(new Type {Id = 2, TypeName = "two"});
TypeCollection.Add(new Type {Id = 3, TypeName = "three"});
TypeCollection.Add(new Type {Id = 4, TypeName = "four"});
TypeCollection.Add(new Type {Id = 5, TypeName = "five"});
addPdt();
}
public void add(int typeId = 1) {
Random r = new Random();
int x = r.Next(10);
PdtCollection.Clear();
for (int i = 0; i < x; i++) {
PdtCollection.Add(new Pdt {Id = 1, PdtName = "P" + i + 1});
}
}
public void addPdt() {
Pdts.Add(new PdtAndType());
}
}
型号classPdt
public class Pdt : Base {
private int _ID;
public int Id {
get { return _ID; }
set {
if (_ID != value) {
_ID = value;
onPropertyChanged("Id");
}
}
}
private String _PdtName;
public String PdtName {
get { return _PdtName; }
set {
if (_PdtName != value) {
_PdtName = value;
onPropertyChanged("PdtName");
}
}
}
private int _typeId;
public int TypeId {
get { return _typeId; }
set {
if (_typeId != value) {
_typeId = value;
onPropertyChanged("TypeId");
}
}
}
}
型号class类型
public class Type : Base {
private int _ID;
public int Id {
get { return _ID; }
set {
if (_ID != value) {
_ID = value;
onPropertyChanged("Id");
}
}
}
private String _typeName;
public String TypeName {
get { return _typeName; }
set {
if (_typeName != value) {
_typeName = value;
onPropertyChanged("TypeName");
}
}
}
}
型号classPdtAndtype
public class PdtAndType : Base {
private int _typeId;
public int TypeId {
get { return _typeId; }
set {
if (_typeId == value) return;
_typeId = value;
onPropertyChanged(nameof(TypeId));
}
}
private int _pdtId;
public int PdtId {
get { return _pdtId; }
set {
if (_pdtId == value) {
return;
}
_pdtId = value;
onPropertyChanged(nameof(PdtId));
}
}
private Type _type;
public Type Type {
get { return _type; }
set {
if (_type == value) {
return;
}
_type = value;
onPropertyChanged(nameof(Type));
}
}
private Pdt _pdt;
public Pdt Pdt {
get { return _pdt; }
set {
if (_pdt == value) {
return;
}
_pdt = value;
onPropertyChanged(nameof(Pdt));
}
}
}
您似乎将 SelectedItem 绑定到 ViewModel 上的同一个对象。
我猜你没有 post 整个 ViewModel,但这是我能做出的唯一结论。
我建议你为每一行制作模型,其中包含一个 SelectedType 和一个 SelectedPdt 属性。
如果您post关于 ViewModel 和模型的更多细节,我很乐意详细说明。
编辑
好的,我现在可以看到问题了。
您的组合框仅使用了 1 个 ViewModel。
在您的 KeyUp 事件处理程序中,您替换了 PdtCollection.
中的项目
这个集合是单一的,所有的组合框都绑定到这个单一的集合。
如果我理解你的目标,你想为每一行制作一个不同的集合。
由于 DataGrid 中的一行由 Pdts 集合表示,我建议您将 PdtCollection inside 你的 Pdt 对象。这样,您就可以将每一行的组合框绑定到行模型中的相关集合。
为了让事情更简单,
你 Pdt 应该看起来像这样:
class Pdt : Base
{
/*
Other properties
*/
private ObservableCollection<Pdt> _pdts;
public ObservableCollection<Pdt> Pdts
{
get { return _pdts; }
set { _pdts = value; }
}
}
之后,您可以将 Window 的 DataContext 中的单个集合上的列绑定到 ROW 数据上下文。这应该看起来像这样:
<DataGridTemplateColumn Header="Name" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox IsEditable="True"
KeyUp="ComboBox_KeyUp_1"
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding PdtCollection}"
DisplayMemberPath="PdtName"
SelectedItem="{Binding Pdt}"
SelectedValuePath="Id"
SelectedValue="{Binding Id, Mode= TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
我认为您需要稍微调整一下代码(选择和显示的成员等,当然还要将内部 PdtCollection 初始化为您想要的任何值),但总体思路是这样的。
我希望我说得够清楚了。
快乐的编码。 :)
在我的项目中,我有一个 DataGrid
,其中包含两个模板列,每个模板列都包含一个 ComboBox
。当我更改任何行中 ComboBox
之一的选择时,更改会反映在所有行中。
我试过设置 IsSynchronizedWithCurrentItem="False"
,但这没有帮助。
任何人都可以提供解决此问题的方法吗?这是我的代码。
Xaml
<DataGrid
x:Name="dtg"
CanUserAddRows="False"
AutoGenerateColumns="False"
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Pdts, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Type" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
IsEditable="True"
ItemsSource="{Binding DataContext.TypeCollection, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
DisplayMemberPath="TypeName"
SelectedItem="{Binding Type}"
SelectedValuePath="Id"
SelectionChanged="ComboBox_SelectionChanged_1"
SelectedValue="{Binding TypeId, Mode= TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Name" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
IsEditable="True"
KeyUp="ComboBox_KeyUp_1"
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding DataContext.PdtCollection, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
DisplayMemberPath="PdtName"
SelectedItem="{Binding Pdt}"
SelectedValuePath="Id"
SelectedValue="{Binding Id, Mode= TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
视图模型
public class MainWindowViewModel : Base {
public ObservableCollection<Type> TypeCollection { get; set; }
public ObservableCollection<Pdt> PdtCollection { get; set; }
public ObservableCollection<PdtAndType> Pdts { get; set; }
public MainWindowViewModel() {
TypeCollection = new ObservableCollection<Type>();
PdtCollection = new ObservableCollection<Pdt>();
Pdts = new ObservableCollection<PdtAndType>();
TypeCollection.Add(new Type {Id = 1, TypeName = "one"});
TypeCollection.Add(new Type {Id = 2, TypeName = "two"});
TypeCollection.Add(new Type {Id = 3, TypeName = "three"});
TypeCollection.Add(new Type {Id = 4, TypeName = "four"});
TypeCollection.Add(new Type {Id = 5, TypeName = "five"});
addPdt();
}
public void add(int typeId = 1) {
Random r = new Random();
int x = r.Next(10);
PdtCollection.Clear();
for (int i = 0; i < x; i++) {
PdtCollection.Add(new Pdt {Id = 1, PdtName = "P" + i + 1});
}
}
public void addPdt() {
Pdts.Add(new PdtAndType());
}
}
型号classPdt
public class Pdt : Base {
private int _ID;
public int Id {
get { return _ID; }
set {
if (_ID != value) {
_ID = value;
onPropertyChanged("Id");
}
}
}
private String _PdtName;
public String PdtName {
get { return _PdtName; }
set {
if (_PdtName != value) {
_PdtName = value;
onPropertyChanged("PdtName");
}
}
}
private int _typeId;
public int TypeId {
get { return _typeId; }
set {
if (_typeId != value) {
_typeId = value;
onPropertyChanged("TypeId");
}
}
}
}
型号class类型
public class Type : Base {
private int _ID;
public int Id {
get { return _ID; }
set {
if (_ID != value) {
_ID = value;
onPropertyChanged("Id");
}
}
}
private String _typeName;
public String TypeName {
get { return _typeName; }
set {
if (_typeName != value) {
_typeName = value;
onPropertyChanged("TypeName");
}
}
}
}
型号classPdtAndtype
public class PdtAndType : Base {
private int _typeId;
public int TypeId {
get { return _typeId; }
set {
if (_typeId == value) return;
_typeId = value;
onPropertyChanged(nameof(TypeId));
}
}
private int _pdtId;
public int PdtId {
get { return _pdtId; }
set {
if (_pdtId == value) {
return;
}
_pdtId = value;
onPropertyChanged(nameof(PdtId));
}
}
private Type _type;
public Type Type {
get { return _type; }
set {
if (_type == value) {
return;
}
_type = value;
onPropertyChanged(nameof(Type));
}
}
private Pdt _pdt;
public Pdt Pdt {
get { return _pdt; }
set {
if (_pdt == value) {
return;
}
_pdt = value;
onPropertyChanged(nameof(Pdt));
}
}
}
您似乎将 SelectedItem 绑定到 ViewModel 上的同一个对象。
我猜你没有 post 整个 ViewModel,但这是我能做出的唯一结论。
我建议你为每一行制作模型,其中包含一个 SelectedType 和一个 SelectedPdt 属性。
如果您post关于 ViewModel 和模型的更多细节,我很乐意详细说明。
编辑
好的,我现在可以看到问题了。
您的组合框仅使用了 1 个 ViewModel。 在您的 KeyUp 事件处理程序中,您替换了 PdtCollection.
中的项目这个集合是单一的,所有的组合框都绑定到这个单一的集合。 如果我理解你的目标,你想为每一行制作一个不同的集合。
由于 DataGrid 中的一行由 Pdts 集合表示,我建议您将 PdtCollection inside 你的 Pdt 对象。这样,您就可以将每一行的组合框绑定到行模型中的相关集合。
为了让事情更简单, 你 Pdt 应该看起来像这样:
class Pdt : Base
{
/*
Other properties
*/
private ObservableCollection<Pdt> _pdts;
public ObservableCollection<Pdt> Pdts
{
get { return _pdts; }
set { _pdts = value; }
}
}
之后,您可以将 Window 的 DataContext 中的单个集合上的列绑定到 ROW 数据上下文。这应该看起来像这样:
<DataGridTemplateColumn Header="Name" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox IsEditable="True"
KeyUp="ComboBox_KeyUp_1"
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding PdtCollection}"
DisplayMemberPath="PdtName"
SelectedItem="{Binding Pdt}"
SelectedValuePath="Id"
SelectedValue="{Binding Id, Mode= TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
我认为您需要稍微调整一下代码(选择和显示的成员等,当然还要将内部 PdtCollection 初始化为您想要的任何值),但总体思路是这样的。
我希望我说得够清楚了。 快乐的编码。 :)