简体   繁体   中英

Implementation Of INotifyPropertyChanged In C# 6.0 - Why No Results?

So I have bound a property in the ViewModel to a property in a TextBox and I am using an implementation of INotifyPropertyChanged for notifications to be raised in the appropriate place. However, I am not seeing data being updated in the TextBox. Where is my error?

// ViewModel
namespace App1
{
    public class Result
    {        
        public string Message { get; set; }
    }

    public class ResultViewModel : INotifyPropertyChanged
    {
        private StringBuilder sb = new StringBuilder();
        private CoreDispatcher dispatcher;

        public event PropertyChangedEventHandler PropertyChanged;        
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

        public string Results
        {
            get { return sb.ToString(); }
        }

        public int Count()
        {
            return sb.Length;
        }

        public ResultViewModel()
        {
            dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
        }

        public async Task Clear()
        {
            await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => sb.Clear());
        }

        public async Task Add(Result result)
        {
            await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => sb.Append(result.Message));            
            OnPropertyChanged(nameof(Results));
        }
    }
}

Add gets called by a function in MainPage.xaml.cs as follows...

private async void ShowResult(Result result)
{
    await this.ViewModel.Add(result);
}

As for TextBox looks like this...

// XAML
<TextBox x:Name="content"
                     Margin="0,10,0,10"
                     RelativePanel.AlignLeftWithPanel="True"
                     RelativePanel.Below="header"
                     RelativePanel.AlignRightWithPanel="True"
                     RelativePanel.Above="genButton"
                     TextWrapping="Wrap"
                     Text="{Binding Path=ViewModel.Results, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                     TextChanged="content_TextChanged"/>

As @JeroenvanLangen, already said the signature of Add doesn't make sense.

Instead you can rise notifications specifying affected by method properties names:

OnPropertyChanged(nameof(Results));

The syntax with CallerMemberName is useful for property setters:

string _test;
public string Test
{
    get { return _test; }
    set
    {
        _test = value;
        OnPropertyChanged(); // will pass "Test" as propertyName
    }
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = "") =>
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

Calling this from some other place obviously doesn't make sense, eg:

void SomeMethod()
{
   ...
   OnPropertyChanged(); // will pass "SomeMethod", huh? 
}

View will receive this notification, but will do nothing.

Hint: you can also pass empty string "" if you want to update all properties, this will equally works in your case (or if you make Count also property and want to bind to it, then just one notification with "" update both Results and Count in the view).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM