0

Не понимать, почему он не выводит в TextBlock

User.cs:

class User
    {
        public string name { get; set; } = "IVAN";
        public string surname { get; set; } = "IVANOV";
    }

MainWindow.xaml:

<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBox Width="130" Height="30"/>
            <TextBox Width="130" Height="30" Margin="0,10,0,0"/>
        </StackPanel>
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Right" Background="Black" Width="130" Margin="10">
            <TextBlock Text="{Binding name}" Foreground="White"/>
            <TextBlock Text="{Binding surname}" Margin="0,10,0,0" Foreground="White"/>
        </StackPanel>
        <Button Width="130" Height="30" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="10" Content="REFRESH" Click="Button_Click"/>

MainWindow.cs:

        private User user { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            //user = DataContext as User;
        }
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        DataContext = user;
    }

введите сюда описание изображения

UPDATE: Решил усложнить. Теперь нужно запихнуть данные из TextBox в User. Но очевидно не сработало, передает null в user

MainWindow.cs:

private void Button_Click(object sender, RoutedEventArgs e)
        {
            user = DataContext as User;
            DataContext = user;
        }
gw gw
  • 95
  • 6
  • 2
    private User user { get; set; }= new User();? – tym32167 Feb 20 '23 at 23:41
  • В конструкторе DataContext установите, а не по нажатию на кнопку и, конечно же, экземпляр объекта создайте, как написал комментатор выше. – OwDafuq Feb 21 '23 at 05:15
  • @LiptonDev слишком не понятно написали. В конструкторе DataContext это как? где вы взяли конструктор. По нажатию сделал, чисто для проверки, ничего более – gw gw Feb 21 '23 at 07:01
  • Что не понятного? Что такое конструктор класса? Проверка чего, вы присваиваете DataContext'y ViewModel, что она по вашему должна сделать в этот момент? Если есть проблемы с базовым C#, то вы рано взялись за WPF. – OwDafuq Feb 21 '23 at 07:04
  • @LiptonDev спасибо за совет) – gw gw Feb 21 '23 at 07:10

2 Answers2

2

С привязками данных надо понять один нюанс. Если при использовании обработчиков событий и прямом доступе к контролам, вы из кода присваиваете значение свойств контролов, то с привязками всё наоборот, контрол сам берёт значение из привязанного свойства и кладёт туда измененное значение в случае его модификации. А из кода вы просто работаете с этим свойством.

Назначаение DataContext выглядит так. Класс User при этом должен быть public.

user = new User();
DataContext = user;

DataContext обычно назначается в конструкторе окна или обработчике события Window.Loaded. Второе предпочтительней.

Когда изменяется DataContext, View внутри себя вызывает событие DataContextChanged и обновляет содержимое всех контролов. Но это сработает только один раз.

Если ничего не дорабатывать, то будет работать только односторонняя привязка View->ViewModel. То есть при изменении руками значений текстбоксов, значения свойств вьюмодели изменятся. При этом здесь имеет значение поведение привязки данных, по умолчанию сам факт изменения произойдет по потере фокуса текстбокса, который например произойдет автоматически когда вы нажмете на кнопку.

Попробуйте что-то поменять в текстбоксе, а затем нажать кнопку с таким кодом.

MessageBox.Show($"{user.name} {user.surname}");

И вы увидите изменения, которые внесли в текстбоксы.

Но на самом деле привязка данных может быть двухсторонней. А так же привязывать можно к одному свойству несколько контролов.

Двухсторонняяя привязка реализуется с помощью интерфейса INotifyPropertyChanged для вьюмодели. Для этого существет уже написанная шаблонная примочка - реализация данного интерфейса.

public class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    =&gt; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

}

Просто вставьте этот класс в проект, и затем унаследуйтесь от него во вьюмодели. (давайте публичные свойства называть с большой буквы, так принято в C#)

public class User : NotifyPropertyChanged
{
    private string name;
    private string surname;
public string Name
{
    get =&gt; name;
    set
    {
        name = value;
        OnPropertyChanged(); // сообщает контролу что свойство изменилось
    }
}

public string Surname
{
    get =&gt; surname;
    set
    {
        surname = value;
        OnPropertyChanged();
    }
}

}

Теперь можно в коде сделать так

user.Name = "Test name";

И оно моментально поменяется в интерфейсе.

Сделайте 2 контрола, чтобы понять как это работает.

<TextBox Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}"/>

Попробуйте поменять значение из текстбокса и из кода.

Попробуйте поменять поведение привязки вот так.

<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>

И посмотрите что поменяется.

aepot
  • 49,560
  • 1
    браво, самое четкое пояснение, огромный thanks – gw gw Feb 21 '23 at 07:15
  • правда мне еще нужно использовать страницы) и там немножко не понятно, где DataContext прописать – gw gw Feb 21 '23 at 07:24
  • @gwgw https://ru.stackoverflow.com/a/1266479/373567 – aepot Feb 21 '23 at 07:24
0

MainWindow.cs:

private User user { get; set; }= new User();
gw gw
  • 95
  • 6