0

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

Example

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?

densegoo
  • 104
  • 6
  • 3
    `Could this have something to do with that I am working with a primitive data type?` - very possible, try to wrap the double into a class which implements `INotifyPropertyChanged`. – kennyzx Mar 08 '16 at 16:43
  • @kennyzx Tried a wrapper `NotifyDouble` class and that seems to be working so far in the sample application. I'll try the same thing on my main application, but it is looking promising. – densegoo Mar 08 '16 at 16:55
  • 1
    Here is the answer: http://stackoverflow.com/questions/13953962/wpf-twoway-binding-of-listbox-using-datatemplate – EngineerSpock Mar 08 '16 at 17:06
  • Also see here http://stackoverflow.com/questions/21124473/xaml-two-way-binding-of-textbox-to-observable-collection – EngineerSpock Mar 08 '16 at 17:16
  • @EngineerSpock is correct that TwoWay binding requires an actual property to work... my best guess it is has something to do with the way WPF updates properties. If you change `Values` from a collection of double to a collection of objects that contain a double property (and implements `INotifyPropertyChanged`), it works just fine. – Rachel Mar 08 '16 at 17:39

0 Answers0