据我所知,当手动更改所选 ComboBox 项目的名称并且此名称未显示在 ComboBox ItemSource 中时,您需要更新上一个上次选择的值。这是我的建议,它是您的 ComboBox 控件数据绑定和 ViewModel 中定义的逻辑的组合。
绑定说明
- 由于 ComboBox ItemsSource 是 Cd 的集合(ComboModels 的集合),因此
TextSearch.TextPath 绑定应定义为 CDType.Name,其中 CdType 是在描述子模型的 ComboModel 中定义的属性,而名称是描述子模型的实际搜索路径。
- ComboBox Text 属性绑定到 AssignmentText 属性以在组合失去焦点时触发更新逻辑(如绑定中所定义)。
- 如您的示例代码中定义的那样,ItemsSource 很简单。
- 选定的值将带来整个模型进行更新(以防我们更改选定的值名称)。
- 由于 ComboBox ItemsSource 是 Cd 的集合(我们称之为 ComboModel),
DisplayMemberPath 绑定应定义为 CDType.Name,其中 CdType 是在描述子模型的 ComboModel 中定义的属性,Name 是描述子模型的实际搜索路径。
Xaml 代码:
<Grid VerticalAlignment="Bottom">
<Grid.DataContext>
<comboBoxWhenNoAnySelectedHelpAttempt:ComboboxDataContext/>
</Grid.DataContext>
<StackPanel Orientation="Vertical">
<ComboBox x:Name="ddlCDType"
IsTextSearchEnabled="True"
IsTextSearchCaseSensitive="False"
StaysOpenOnEdit="True"
TextSearch.TextPath="CDType.Name"
Text="{Binding AssignmentText,
UpdateSourceTrigger=LostFocus, Mode=TwoWay,
ValidatesOnDataErrors=True}"
ItemsSource="{Binding CDTypes}"
SelectedValue="{Binding Assignment}"
DisplayMemberPath="CDType.Name"
IsEditable="True"
HorizontalAlignment="Left"
Margin="98,10,0,0"
VerticalAlignment="Top"
Width="136" />
<!--added to see changes in updated combo box item-->
<TextBlock >
<Run Text="Name:"/>
<Run Text="{Binding Assignment.CDType.Name, UpdateSourceTrigger=PropertyChanged}"></Run>
<Run Text="Id:"/>
<Run Text="{Binding Assignment.CDType.ID, UpdateSourceTrigger=PropertyChanged}"></Run>
</TextBlock>
</StackPanel>
</Grid>
虚拟机代码
public class ComboboxDataContext:BaseObservableObject
{
private ObservableCollection<ComboModel> _cdTypes;
private ComboModel _assignment;
private string _assignmentText;
private string _lastAcceptedName;
public ComboboxDataContext()
{
CDTypes = new ObservableCollection<ComboModel>
{
new ComboModel
{
CDType = new ComboModelSubModel
{
Name = "Cd-1",
ID = "1",
},
},
new ComboModel
{
CDType = new ComboModelSubModel
{
Name = "Cd-2",
ID = "2",
}
},
new ComboModel
{
CDType = new ComboModelSubModel
{
Name = "Cd-3",
ID = "3",
},
},
new ComboModel
{
CDType = new ComboModelSubModel
{
Name = "Cd-4",
ID = "4",
}
}
};
Assignment = CDTypes.FirstOrDefault();
}
public ObservableCollection<ComboModel> CDTypes
{
get { return _cdTypes; }
set
{
_cdTypes = value;
OnPropertyChanged();
}
}
public ComboModel Assignment
{
get { return _assignment; }
set
{
if (value == null)
_lastAcceptedName = _assignment.CDType.Name;
_assignment = value;
OnPropertyChanged();
}
}
//on lost focus when edit is done will check and update the last edited value
public string AssignmentText
{
get { return _assignmentText; }
set
{
_assignmentText = value;
OnPropertyChanged();
UpDateSourceCollection(AssignmentText);
}
}
//will do the the update on combo lost focus to prevent the
//annessasary updates (each property change will make a lot of noice in combo)
private void UpDateSourceCollection(string assignmentText)
{
var existingModel = CDTypes.FirstOrDefault(model => model.CDType.Name == assignmentText);
if (existingModel != null) return;
if (_lastAcceptedName == null)
{
CDTypes.Add(new ComboModel{CDType = new ComboModelSubModel{ID = string.Empty, Name = assignmentText}});
}
else
{
var existingModelToEdit = CDTypes.FirstOrDefault(model => model.CDType.Name == _lastAcceptedName);
if(existingModelToEdit == null) return;
existingModelToEdit.CDType.Name = assignmentText;
existingModelToEdit.CDType.ID = string.Empty;
}
}
}
public class ComboModel:BaseObservableObject
{
private ComboModelSubModel _cdType;
public ComboModelSubModel CDType
{
get { return _cdType; }
set
{
_cdType = value;
OnPropertyChanged();
}
}
}
public class ComboModelSubModel:BaseObservableObject
{
private string _id;
private string _name;
public string ID
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged();
}
}
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
}
BaseObservableObject 代码
/// <summary>`enter code here`
/// implements the INotifyPropertyChanged (.net 4.5)
/// </summary>
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
问候。