Solución:
Tuve este mismo problema y, como algunos de los usuarios son nuevos en WPF, luché para que la solución dada por Einar Guðsteinsson funcionara. Entonces, en apoyo de su respuesta, pego aquí los pasos para que esto funcione. (O más exactamente cómo hice que esto funcionara).
Primero cree una clase de cuadro combinado personalizado que herede de la clase Combobox. Consulte el código a continuación para ver la implementación completa. Puede cambiar el código en OnDropSelectionChanged para que se adapte a sus necesidades individuales.
espacio de nombres MyCustomComboBoxApp {using System.Windows.Controls;
public class MyCustomComboBox : ComboBox
{
private int caretPosition;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var element = GetTemplateChild("PART_EditableTextBox");
if (element != null)
{
var textBox = (TextBox)element;
textBox.SelectionChanged += OnDropSelectionChanged;
}
}
private void OnDropSelectionChanged(object sender, System.Windows.RoutedEventArgs e)
{
TextBox txt = (TextBox)sender;
if (base.IsDropDownOpen && txt.SelectionLength > 0)
{
txt.CaretIndex = caretPosition;
}
if (txt.SelectionLength == 0 && txt.CaretIndex != 0)
{
caretPosition = txt.CaretIndex;
}
}
}
Asegúrese de que esta clase combinada personalizada exista en el mismo proyecto. Luego, puede usar el código a continuación para hacer referencia a este combo en su interfaz de usuario.
<Window x:Class="MyCustomComboBoxApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:MyCustomComboBoxApp"
Title="MainWindow" Height="350" Width="525" FocusManager.FocusedElement="{Binding ElementName=cb}">
<Grid>
<StackPanel Orientation="Vertical">
<cc:MyCustomComboBox x:Name="cb" IsEditable="True" Height="20" Margin="10" IsTextSearchEnabled="False" KeyUp="cb_KeyUp">
<ComboBoxItem>Toyota</ComboBoxItem>
<ComboBoxItem>Honda</ComboBoxItem>
<ComboBoxItem>Suzuki</ComboBoxItem>
<ComboBoxItem>Vauxhall</ComboBoxItem>
</cc:MyCustomComboBox>
</StackPanel>
</Grid>
</Window>
¡Eso es todo! ¡Cualquier duda, por favor pregunte! Haré todo lo posible para ayudar.
¡Gracias a Einar Guðsteinsson por su solución!
Más vale tarde que nunca y si alguien más se enfrenta a este problema, podría usarlo.
No se puede hacer esto si anula el cuadro combinado. Primero controle el cuadro de texto que se usa en la plantilla y regístrese en el evento selectionchanged.
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var element = GetTemplateChild("PART_EditableTextBox");
if (element != null)
{
var textBox = (TextBox)element;
textBox.SelectionChanged += OnDropSelectionChanged;
}
}
private void OnDropSelectionChanged(object sender, RoutedEventArgs e)
{
// Your code
}
Luego, en el controlador de eventos, puede volver a configurar la selección como desee. En mi caso, estaba llamando a IsDropDownOpen en código. La selección guardada allí y luego vuelva a colocarla en el controlador de eventos. Feo pero funcionó.
Creo que en la solución proporcionada por Andrew N falta algo, ya que cuando lo probé, el evento Selection Changed del TextBox estaba colocando el símbolo de intercalación en el lugar equivocado. Así que hice este cambio para solucionar eso.
namespace MyCustomComboBoxApp { using System.Windows.Controls;
public class MyCustomComboBox : ComboBox
{
private int caretPosition;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var element = GetTemplateChild("PART_EditableTextBox");
if (element != null)
{
var textBox = (TextBox)element;
textBox.SelectionChanged += OnDropSelectionChanged;
}
}
private void OnDropSelectionChanged(object sender, System.Windows.RoutedEventArgs e)
{
TextBox txt = (TextBox)sender;
if (base.IsDropDownOpen && txt.SelectionLength > 0)
{
caretPosition = txt.SelectionLength; // caretPosition must be set to TextBox's SelectionLength
txt.CaretIndex = caretPosition;
}
if (txt.SelectionLength == 0 && txt.CaretIndex != 0)
{
caretPosition = txt.CaretIndex;
}
}
}