Sin*_*atr 4 c# wpf binding combobox
我希望有 ComboBox用户可以在其中输入一些文本或从下拉列表中选择文本。当用户Enter在键入后按下或从下拉列表中简单选择项目时,绑定源应该更新(本例中为最佳视图行为)。
UpdateSourceTrigger=PropertyChange设置(默认),源更新将在每个字符之后触发,这不好,因为属性设置器调用很昂贵;UpdateSourceTrigger=LostFocus设置,然后从下拉列表中选择项目将需要一个更大的动作实际上失去焦点,这是不是很人性化(点击后需要额外的点击来选择项目)。我尝试使用UpdateSourceTrigger=Explicit,但效果不佳:
<ComboBox IsEditable="True" VerticalAlignment="Top" ItemsSource="{Binding List}"
Text="{Binding Text, UpdateSourceTrigger=LostFocus}"
SelectionChanged="ComboBox_SelectionChanged"
PreviewKeyDown="ComboBox_PreviewKeyDown" LostFocus="ComboBox_LostFocus"/>
public partial class MainWindow : Window
{
private string _text = "Test";
public string Text
{
get { return _text; }
set
{
if (_text != value)
{
_text = value;
MessageBox.Show(value);
}
}
}
public string[] List
{
get { return new[] { "Test", "AnotherTest" }; }
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
((ComboBox)sender).GetBindingExpression(ComboBox.TextProperty).UpdateSource();
}
private void ComboBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if(e.Key == Key.Enter)
((ComboBox)sender).GetBindingExpression(ComboBox.TextProperty).UpdateSource();
}
private void ComboBox_LostFocus(object sender, RoutedEventArgs e)
{
((ComboBox)sender).GetBindingExpression(ComboBox.TextProperty).UpdateSource();
}
}
Run Code Online (Sandbox Code Playgroud)
此代码有2个问题:
我有点害怕陷入XY问题,这就是为什么我发布原始要求(也许我走错了方向?)而不是要帮助我解决上述问题之一的原因。
您响应特定事件而更新源的方法是正确的,但是在ComboBox更新事物的方式上还需要考虑更多。另外,您可能希望将其UpdateSourceTrigger设置为,LostFocus以便没有太多要处理的更新案例。
您还应该考虑将代码移至可重用的附加属性,以便将来将其应用于组合框。碰巧我在过去创建了这样的属性。
/// <summary>
/// Attached properties for use with combo boxes
/// </summary>
public static class ComboBoxBehaviors
{
private static bool sInSelectionChange;
/// <summary>
/// Whether the combo box should commit changes to its Text property when the Enter key is pressed
/// </summary>
public static readonly DependencyProperty CommitOnEnterProperty = DependencyProperty.RegisterAttached("CommitOnEnter", typeof(bool), typeof(ComboBoxBehaviors),
new PropertyMetadata(false, OnCommitOnEnterChanged));
/// <summary>
/// Returns the value of the CommitOnEnter property for the specified ComboBox
/// </summary>
public static bool GetCommitOnEnter(ComboBox control)
{
return (bool)control.GetValue(CommitOnEnterProperty);
}
/// <summary>
/// Sets the value of the CommitOnEnterProperty for the specified ComboBox
/// </summary>
public static void SetCommitOnEnter(ComboBox control, bool value)
{
control.SetValue(CommitOnEnterProperty, value);
}
/// <summary>
/// Called when the value of the CommitOnEnter property changes for a given ComboBox
/// </summary>
private static void OnCommitOnEnterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
ComboBox control = sender as ComboBox;
if (control != null)
{
if ((bool)e.OldValue)
{
control.KeyUp -= ComboBox_KeyUp;
control.SelectionChanged -= ComboBox_SelectionChanged;
}
if ((bool)e.NewValue)
{
control.KeyUp += ComboBox_KeyUp;
control.SelectionChanged += ComboBox_SelectionChanged;
}
}
}
/// <summary>
/// Handler for the KeyUp event attached to a ComboBox that has CommitOnEnter set to true
/// </summary>
private static void ComboBox_KeyUp(object sender, KeyEventArgs e)
{
ComboBox control = sender as ComboBox;
if (control != null && e.Key == Key.Enter)
{
BindingExpression expression = control.GetBindingExpression(ComboBox.TextProperty);
if (expression != null)
{
expression.UpdateSource();
}
e.Handled = true;
}
}
/// <summary>
/// Handler for the SelectionChanged event attached to a ComboBox that has CommitOnEnter set to true
/// </summary>
private static void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!sInSelectionChange)
{
var descriptor = DependencyPropertyDescriptor.FromProperty(ComboBox.TextProperty, typeof(ComboBox));
descriptor.AddValueChanged(sender, ComboBox_TextChanged);
sInSelectionChange = true;
}
}
/// <summary>
/// Handler for the Text property changing as a result of selection changing in a ComboBox that has CommitOnEnter set to true
/// </summary>
private static void ComboBox_TextChanged(object sender, EventArgs e)
{
var descriptor = DependencyPropertyDescriptor.FromProperty(ComboBox.TextProperty, typeof(ComboBox));
descriptor.RemoveValueChanged(sender, ComboBox_TextChanged);
ComboBox control = sender as ComboBox;
if (control != null && sInSelectionChange)
{
sInSelectionChange = false;
if (control.IsDropDownOpen)
{
BindingExpression expression = control.GetBindingExpression(ComboBox.TextProperty);
if (expression != null)
{
expression.UpdateSource();
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是在xaml中设置属性的示例:
<ComboBox IsEditable="True" ItemsSource="{Binding Items}" Text="{Binding SelectedItem, UpdateSourceTrigger=LostFocus}" local:ComboBoxBehaviors.CommitOnEnter="true" />
Run Code Online (Sandbox Code Playgroud)
我认为这将为您提供所需的行为。可以按原样使用它,也可以根据自己的喜好对其进行修改。
行为实现存在一个问题,即如果您开始键入现有值(并且不按Enter),然后从下拉列表中选择相同的值,则在这种情况下,直到按Enter键并更改源才更新焦点,或选择其他值。我相信可以解决,但是花时间在我身上并没有什么问题,因为这不是正常的工作流程。
| 归档时间: |
|
| 查看次数: |
5282 次 |
| 最近记录: |