0
votes

To simplify my problem, in my app I want to change the user's input to all uppercase. So "foo" should be displayed as "FOO" when the TextBox loses focus.

My Xaml:

<Page x:Class="App12.MainPage"
      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:local="using:App12"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Page.DataContext>
        <local:MainViewModel />
    </Page.DataContext>

    <StackPanel Margin="10,50,10,10" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Text="{Binding Name1, Mode=TwoWay}" />
        <TextBox Text="{x:Bind Path=vm.Name2, Mode=TwoWay}" />
        <Button HorizontalAlignment="Center">Just a control for the TextBox to lose focus</Button>
    </StackPanel>
</Page>

My ViewModel

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace App12
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public MainViewModel() 
        {

        }

        private string _name1 = "something";

        public string Name1
        {
            get
            {
                return _name1;
            }
            set
            {
                _name1 = (string)value.ToUpper();
                OnPropertyChanged();
            }
        }

        private string _name2 = "something";

        public string Name2
        {
            get
            {
                return _name2;
            }
            set
            {
                _name2 = (string)value.ToUpper();
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged( [CallerMemberName] string propertyName = null )
        {
            var handler = PropertyChanged;
            handler?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
        }
    }
}

And my code-behind

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace App12
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        MainViewModel vm;
        public MainPage()
        {
            this.InitializeComponent();
            DataContextChanged += MainPage_DataContextChanged;
        }

        private void MainPage_DataContextChanged( FrameworkElement sender, DataContextChangedEventArgs args )
        {
            vm = (MainViewModel)DataContext;
        }



    }
}

When I use classical binding in a UWP app (First TextBox), this code doesn't work

I see the setter being called, OnNotifyPropertyChanged gets called as well, and the handler is not null. Variable _text gets assigned its new value just fine (all uppercase), but then I never see the getter of public variable Text called. I've also tried a converter (with ConvertBack implemented), with the same result. Using x:Bind however (Second TextBox), it does work.

In WPF this also works as expected. Am I missing something or has Binding changed? According to what Microsoft tells us and what I've seen it shouldn't have.

1

1 Answers

0
votes

I found another Q/A in Stackoverflow which says:

The problem here is that the binding system in UWP is "intelligent". For TwoWay bindings, changes to the target will automatically propagate to the source and in this scenario, binding system assumes that the PropertyChanged event will fire for corresponding property in source and it ignores these events. So even you have RaisePropertyChanged or NotifyPropertyChanged in you source, the TextBox still won't update.

BTW I can't figure out how to create a workaround for this problem with the classic TwoWay Binding.