Search code examples
wpfvb.netmvvmcombobox

WPF Combobox & Textbox Behavior


I made a simple test to try and isolate out an issue I was having with comboboxes. I want to give the user the opportunity to cancel the edit made to a control before triggering calculations.

In the test, a textbox gave me the result that I was looking for. When canceling, the control reverts back to what it was. When canceling the input in the combobox, the combobox appears as though it was not canceled. In both of these cases, the model and viewmodel are correct.

How can I have the combobox behave the same way the textbox does to allow the control to reflect the viewmodel correctly?

The textbox stays correct while the combobox is incorrect after canceling the edit of the combobox

Model and viewmodel:

Option Explicit On
Option Strict On
Imports System.ComponentModel

Public Class ViewModel
    Implements INotifyPropertyChanged
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    Protected Overridable Sub OnPropertyChanged(propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Public Sub New()
        Model = New Model
    End Sub

    Public Property Model As Model
    Public Property Text As String
        Get
            Return Model.Text
        End Get
        Set(value As String)
            If cancel() Then
                OnPropertyChanged("Text")
                Exit Property
            End If
            Model.Text = value
            OnPropertyChanged("Text")
        End Set
    End Property

    Private Function cancel() As Boolean
        If MsgBox("Cancel?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
            Return True
        Else Return False
        End If
    End Function
End Class

Public Class Model
    Public Sub New()
        Text = "Hello, World!"
    End Sub
    Public Property Text As String
End Class

View:

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:test"
        mc:Ignorable="d"
        Title="MainWindow" Height="241" Width="416" d:DataContext="{d:DesignInstance Type=local:ViewModel}">
    <Grid>
        <TextBox HorizontalAlignment="Left" Margin="108,95,0,0" TextWrapping="Wrap" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120"/>
        <ComboBox HorizontalAlignment="Left" Margin="108,144,0,0" VerticalAlignment="Top" Width="120" IsEditable="True" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>

Window code-behind:

Class MainWindow
    Public Sub New()
        InitializeComponent()
        DataContext = New ViewModel
    End Sub
End Class

Solution

  • Because the ComboBox contains a TextBox, when the user Cancel(), it does not affect the TextBox.Text, which is why this issue occurs.

    We can add a Button and in its Click event, obtain the Text property of the Model, ComboBox, and the TextBox inside the ComboBox.

    I'm using C# and I believe you should be able to understand.

    // in Button click event
    
    // get TextBox inside the ComboBox
    var textBox = cb.Template.FindName("PART_EditableTextBox", cb) as TextBox;
    
    MessageBox.Show($"model: {Model.Text}, cb: {cb.Text}, textBox: {textBox.Text}");
    

    I solved the problem using this method. You can give it a try.

    <ComboBox x:Name="cb" IsEditable="True" Text="{Binding Path=Text, Delay=5}" />