WPF TextBox 입력값 실시간 업데이트(재업)

안녕하세요. WPF 바인딩에 관한 기초적인 질문입니다.

<TextBox x:Name=“txtTest” Margin=“0,5,0,0” Text=“{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}”

private TextTestVM textVM = new TextTestVM();

txtTest.DataContext = textVM;

private class TextTestVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public TextTestVM()
{
}

private string text;
public string Text
{
    get { return text; }
    set
    {
        Console.WriteLine($"Text : {value}");
        text = value;
        OnPropertyChanged("Text");
    }
}

protected void OnPropertyChanged(string propertyName)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

}

위 소스와 같이 txtTest 텍스트 박스를 TextTestVM 에 양방향(TwoWay) 실시간(PropertyChanged) 바인딩을 하고
txtTest 에 사용자가 텍스트 입력을 해도 TextTestVM의 Text 프로퍼티에 실시간 입력이 되지않더군요.
실시간 입력이 된다면 Console.WriteLine($“Text : {value}”) 에서 실시간으로 입력값을 찍어야하는데
포커스를 잃을때만 호출이 됩니다.
이게 원래 TextBox 입력이 실시간(PropertyChanged)을 지원하지않아서 인가요 아니면 제가 뭔가 잘못한게 있는건가요?

  1. markdown형식 코드 스타일이 제대로 안되어 있어 읽기가 힘듭니다.

  2. TextBox의 Text속성은 UpdateSourceTrigger=PropertyChanged 정상적으로 동작 됩니다.

  3. 재현되는 프로젝트를 첨부해주시면 다른 문제점이 있는 부분을 확인 할 수 있을 것 같습니다.

  4. (혹시나.,) 혹시 한글입력 같은 조합형 글자는 변경 통보가 바로 업데이트 되지 않고, 완성 되었을때 변경 통보가 됩니다.

2 Likes
<Window x:Class="DataContextSample.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:DataContextSample"
        mc:Ignorable="d"
        Title="MainWindow" Height="180" Width="305.094">
    <StackPanel Margin="15">
        <WrapPanel>
            <TextBlock Text="Window title:  " />
            <TextBox Name="txtWindowTitle" Text="{Binding Title, UpdateSourceTrigger=Explicit}" Width="150" />
            <Button Name="btnUpdateSource" Click="btnUpdateSource_Click" Margin="5,0" Padding="5,0">*</Button>
        </WrapPanel>
        <WrapPanel Margin="0,10,0,0">
            <TextBlock Text="Window dimensions: " />
            <TextBox Text="{Binding Width, UpdateSourceTrigger=LostFocus}" Width="50" />
            <TextBlock Text=" x " />
            <TextBox Text="{Binding Height, UpdateSourceTrigger=PropertyChanged}" Width="50" />
        </WrapPanel>
        <Button x:Name="btnTest" Margin="0,5,0,0" Click="btnTest_Click">Test</Button>
        <TextBox x:Name="txtTest" Margin="0,5,0,0" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
</Window>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DataContextSample
{
///


/// MainWindow.xaml에 대한 상호 작용 논리
///

public partial class MainWindow : Window
{
private TextTestVM textVM = new TextTestVM();

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;
        txtTest.DataContext = textVM;
    }

    private void btnUpdateSource_Click(object sender, RoutedEventArgs e)
    {
        BindingExpression binding = txtWindowTitle.GetBindingExpression(TextBox.TextProperty);
        binding.UpdateSource();
    }

    private void btnTest_Click(object sender, RoutedEventArgs e)
    {
        textVM.Text = "this is test";
    }

    private class TextTestVM : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public TextTestVM()
        {
        }

        private string text;
        public string Text
        {
            get { return text; }
            set
            {
                Console.WriteLine($"Text : {value}");
                text = value;
                OnPropertyChanged("Text");
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

}

소스코드 올리는 법을 몰랐었어 다시 올립니다.
위에 첫번째 소스는 MainWindow.xaml 이고 그 다음이 MainWindow.xaml.cs 입니다
txtTest 부분만 보시면 됩니다.

<Window x:Class="TextBoxBind.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:TextBoxBind"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TextBox Text="{Binding InputText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TextBoxBind
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private string inputText;

        public string InputText
        {
            get { return inputText; }
            set
            {
                if (inputText != value)
                {
                    Console.WriteLine($"InputText : {value}");
                    inputText = value;
                    OnPropertyChanged("InputText");
                }
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged;

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

예제를 단순화해서 MainWindow에 TextBox 한개 붙이고 바인딩을 시켜도 실시간 호출이 안되네요.
그런데 신기한게 문자 입력후에 delete 키로 삭제하는 동안에는 실시간 호출이 됩니다

set에 BP 걸어 보시고 하셨을때
바로 호출이 안되나요 ?

네. 엔터를 쳐야 호출이 되네요

소스코드 수정한거 전혀 없는데 방금전부터 실시간 호출이 잘 되네요.
아무래도 제 pc 환경이 이상한거 같습니다.
도움 주셔서 감사합니다.