0

В окне 2 элемента: TextBox - в который вводится текст, и Label - в который этот текст передается. При запуске программы Label считывает дефолтные данные из TextBox, но если впоследствии менять текст, то в Label измененный текст не отображается.

<Window x:Class="Example_INotifyPropertyChenged.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:Example_INotifyPropertyChenged.ViewModels"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="c0"></ColumnDefinition>
        <ColumnDefinition x:Name="c1"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition x:Name="r0"></RowDefinition>
        <RowDefinition x:Name="r1" ></RowDefinition>
    </Grid.RowDefinitions>
    <TextBox x:Name="textBoxtText" Grid.Row="0" Grid.Column="0" Text="{Binding Mode=TwoWay, Path=TextBoxText, UpdateSourceTrigger=PropertyChanged}"></TextBox>
    <Label x:Name="label" Grid.Row="0" Grid.Column="1" Content="{Binding Mode=Default, Path=LabelContent}"></Label>

</Grid>

и сама ViewModal

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.Controls;
using System.Windows.Data;

namespace Example_INotifyPropertyChenged.ViewModels { public class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)
    {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
private string _textBoxText=&quot;textBox&quot;;
public string TextBoxText
{
    get =&gt; _textBoxText;
    set
    {
        if(_textBoxText!=value)
        _textBoxText = value;
        OnPropertyChanged(LabelContent);
    }
}        
public string LabelContent { get =&gt; TextBoxText;}

}

}

  • Что вы видите тут? OnPropertyChanged([CallerMemberName] string PropertyName = null), а что вы видите здесь OnPropertyChanged(LabelContent);? – EvgeniyZ Feb 22 '21 at 09:56
  • Прошу прощения, не понял вопрос. А что я должен был там увидеть? – Максим Галушко Feb 22 '21 at 10:13
  • Наверно то, что для INPС требуется PropertyName, а вы пихаете значение свойства LableContent, которое у вас textBox. Чтоб этот пример заработал, достаточно OnPropertyChanged(LabelContent); заменить на OnPropertyChanged("LabelContent");. – EvgeniyZ Feb 22 '21 at 10:15
  • Евгений, еще раз извиняюсь, но можете привести пример кода, т.к. я не совсем понимаю, что Вы имеете ввиду. Взяв в кавычки имя свойства, проблема не решилась. p.s. мне искренне интересно как еще можно решить данную проблему, тк приведенный пример, это просто пример, чтобы разобраться в некоторых тонкостях...Ниже я привел пример своего решения. – Максим Галушко Feb 22 '21 at 10:25
  • Ну как так не решилась, вот ваш код, где я только взял в кавычки LabelContent, вот XAML, он как видите без каких-либо изменений. Ну и все работает. Понимайте метод OnPropertyChanged() как "ей, интерфейс, тут свойство (имя) изменило значение, подтяни новые данные!" оно не обновляет все другие свойства, оно лишь обновляет то, что ему укажут. В вашем случае, вы пишете OnPropertyChanged("textBox"), где свойства textBox соответственно нету и обновлять нечего. – EvgeniyZ Feb 22 '21 at 10:40

1 Answers1

0

Ошибка заключалась в том, что свойство TextBoxTex тоже нужно было извещать о том, что оно изменилось:

            set
        {
            if(_textBoxText!=value)
            _textBoxText = value;
            OnPropertyChanged();//извещение всех кто привязан к этому свойству о том, что оно изменилось...
            OnPropertyChanged(nameof(TextBlogText));//извещение всех кто привязан к свойству LabelContent о том, что оно  изменилось
        }
  • 1
    Вообще у вас весьма странно тут все реализовано. 1. Зачем вам тут 2-е свойство, которое дублирует первое? Почему нельзя привязаться сразу к одному свойству? 2. if(_textBoxText!=value) - лучше перенести в OnPropertyChanged() метод. 3. Сам INPC лучше вынести в отдельный класс. 4. Названия... TextBoxText, x:Name="textBoxtText". 5. Зачем в XAML у вас везде x:Name? 6. DataContext в XAML плохо. – EvgeniyZ Feb 22 '21 at 10:13
  • 1
    //извещение всех кто привязан к этому свойству - нет, это аналог OnPropertyChanged(nameof(TextBoxText));, только nameof(TextBoxText) за вас пишет компилятор из-за атрибута [CallerMemberName]. Соответственно и /извещение всех кто привязан к свойству LabelContent тоже мимо. – EvgeniyZ Feb 22 '21 at 10:22
  • Переписал код, сведя все к одному свойству, спасибо за рекомендации. Первичная реализация была аналогична примеру из "учебника". Про имена элементов, тоже уже прочитал. А вот про DataContext в xaml пока не понятно, почему это плохо? – Максим Галушко Feb 22 '21 at 10:34
  • Я ведь дал ссылку, где все описано, не? MVVM, это подход, где все разбивается на мало связанных друг с другом слои, особенно UI (View) слой должен быть полностью отделен от кода. И вот теперь представьте, UI вдруг создает сам себе VM слой, содержит его, отвечает за его жизненный цикл и вовсе жить не может без своей VM. Нарушение-ли это? Определенно да. Также чтоб использовать основную VM где-либо еще, вам надо будет обратиться к окну, взять его DataContext и только тогда использовать VM, где надо и тут опять приходим к проблеме, где мы строго завязаны на UI и постоянно обращаемся к ней. – EvgeniyZ Feb 22 '21 at 10:50