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?
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
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}" />