I have a ListBox
that is bound to an ObservableCollection<double>
. Inside this ListBox I defined my own template that simply has some text and a textbox for modifying the value. The goal is the user can type in the 2nd textbox to update the 2nd value in the Values list. However, this doesn't seem to update the source, even with TwoWay mode. I am stumped. Is this even the best approach, or am I doing work that I don't need to do? I recreated the issue in a sample project, here is the code:
XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:DoubleToStringConverter x:Key="DoubleToStringConv" />
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Path=Values}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Text="Height" Padding="0"/>
<TextBox Margin="20 0 0 0" Width="50" Text="{Binding Path=., Converter={StaticResource DoubleToStringConv}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" KeyDown="TextBox_KeyDown" />
<Label Content=" and the value is" Padding="0" />
<TextBlock Margin="20 0 0 0" Width="50" Text="{Binding Path=., Converter={StaticResource DoubleToStringConv}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Code
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private ObservableCollection<double> _values = new ObservableCollection<double>();
public ObservableCollection<double> Values
{
get { return _values; }
set
{
_values = value;
OnPropertyChanged("Values");
}
}
public MainWindow()
{
DataContext = this;
InitializeComponent();
Values.Add(10);
Values.Add(10);
Values.Add(10);
}
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
TextBox box = sender as TextBox;
if (sender is TextBox)
{
if (e.Key == Key.Enter)
{
BindingExpression exp = box.GetBindingExpression(TextBox.TextProperty);
exp.UpdateSource();
}
}
}
}
public class DoubleToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return value.ToString();
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
double val = 0;
double.TryParse(value.ToString(), out val);
return val;
}
}
}
Screenshot
I have tried various ways up using different binding update methods (explicit, on property change, etc) and nothing seems to make a difference. The binding's DataItem and ResolvedSource always equal the initial value of the textbox even when the text changes. Could this have something to do with that I am working with a primitive data type?
I don't think that the example I posted would update the displayed value because there is no property changed event for double
. I did put a breakpoint in the ConvertBack
converter function as I would at least expect that to be called when I change the value and it should be reflected back in the textbox? Or is that not how it works?