С Новым годом! Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.72/32: Рейтинг темы: голосов - 32, средняя оценка - 4.72
215 / 149 / 48
Регистрация: 28.12.2016
Сообщений: 716
1
WPF

Привязать свойство в коде с Text у TextBox

19.05.2019, 22:05. Показов 6221. Ответов 9
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System.Windows;
using System.Windows.Controls;
 
namespace HelloWorld.UsersControl
{
    /// <summary>
    /// Логика взаимодействия для NumericUpDown.xaml
    /// </summary>
    public partial class NumericUpDown : UserControl
    {
        public int Price { get; set; }
 
        public NumericUpDown()
        {
            InitializeComponent();
        }
 
        
        private void BtnUp_Click(object sender, RoutedEventArgs e)
        {
            Price++;
        }
        private void BtnDown_Click(object sender, RoutedEventArgs e)
        {
            Price--;
        }
 
    }
}
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<UserControl x:Class="HelloWorld.UsersControl.NumericUpDown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" Height="89.133" Width="100">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button x:Name="btnUp" Content="Up"  Grid.Row="0"  Click="BtnUp_Click"/>
        <TextBox x:Name="tbView"  Text="{Binding Price}" Foreground="Black" Grid.Row="1"/>
        <Button x:Name="btnDown" Content="Down"  Grid.Row="2" Click="BtnDown_Click" />
    </Grid>
</UserControl>
Price привязать к TextBox Text. {Binding Price} так не работает
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.05.2019, 22:05
Ответы с готовыми решениями:

TextBox и свойство text
Как записать начальный текст в текстбокс столбиком: текст текст текст В Windows Forms есть...

Назначить TextBox свойство Text?
Например у меня есть текстовое поле search1 для поиска по сайту: &lt;asp:Button id=&quot;Search_Submit&quot;...

Задать свойство Text элемента TextBox
Начал писать программу калькулятор и на textBox1 должен показываться ноль но при textBox1.Text =...

Как сохранить свойство Text элемента TextBox после закрытия программы?
Собственно. Ну то ест программа работает, текст правится вручную. Программу закрываем, текст...

9
Модератор
Эксперт .NET
15853 / 10999 / 2854
Регистрация: 21.04.2018
Сообщений: 32,283
Записей в блоге: 2
19.05.2019, 22:43 2
Цитата Сообщение от Defences Посмотреть сообщение
так не работает
Работает, но не происходит обновление значения в WPF элементе.
Если Вы проверите в коде C#, то увидите, что свойство имеет другое значение.
Для обновления значения в привязке к CLR свойству, это свойство должно уведомить об изменении своего значения через интерфейс INotifyPropertyChanged.

Для Вашего примера, подойдёт такая реализация.
C#
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    // <summary>
    /// Логика взаимодействия для NumericUpDown.xaml
    /// </summary>
    public partial class NumericUpDown : UserControl, INotifyPropertyChanged
    {
 
        /// <summary>Событие для извещения об изменения свойства</summary>
        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>Метод для вызова события извещения об изменении свойства</summary>
        /// <param name="propertyName">Изменившееся свойство</param>
        public void OnPropertyChanged([CallerMemberName]string propertyName = "") =>
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 
        private int _price;
        public int Price
        {
            get => _price;
            set
            {
                if (_price != value)
                {
                    _price = value;
                    OnPropertyChanged();
                }
            }
        }
 
        public NumericUpDown() => InitializeComponent();
        private void BtnUp_Click(object sender, RoutedEventArgs e) => Price++;
        private void BtnDown_Click(object sender, RoutedEventArgs e) => Price--;
 
    }
1
215 / 149 / 48
Регистрация: 28.12.2016
Сообщений: 716
19.05.2019, 23:00  [ТС] 3
Элд Хасп, ваше решение не работает, может быть что-то в xaml прописать нужно?
0
Модератор
Эксперт .NET
15853 / 10999 / 2854
Регистрация: 21.04.2018
Сообщений: 32,283
Записей в блоге: 2
19.05.2019, 23:23 4
Цитата Сообщение от Defences Посмотреть сообщение
ваше решение не работает, может быть что-то в xaml прописать нужно?
Да, нужно - я и не посмотрел там.
У Вас же не установлен DataContext! Привязку Вы к чему собственно делаете? Binding - это привязка к DataContext.

Добавлено через 2 минуты
На свойство UC можно сослаться через ElementName
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<UserControl x:Class="HelloWorld.UsersControl.NumericUpDown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" Height="89.133" Width="100"
             x:Name="numericUpDown">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button x:Name="btnUp" Content="Up"  Grid.Row="0"  Click="BtnUp_Click"/>
        <TextBox x:Name="tbView"  Text="{Binding Price, ElementName=numericUpDown}" Foreground="Black" Grid.Row="1"/>
        <Button x:Name="btnDown" Content="Down"  Grid.Row="2" Click="BtnDown_Click" />
    </Grid>
</UserControl>
Добавлено через 11 минут
Можно сослаться на тип родительского элемента
XML
15
        <TextBox x:Name="tbView"  Text="{Binding Price, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:NumericUpDown}}}" Foreground="Black" Grid.Row="1"/>
1
215 / 149 / 48
Регистрация: 28.12.2016
Сообщений: 716
19.05.2019, 23:55  [ТС] 5
Элд Хасп, спасибо! Можно еще 1 вопрос чтобы окончательно закрыть тему.

А как сделать привязку к DataContext, чтобы просто писать Binding Price, Binding Name и т.д, без ElementName=numericUpDown.

Так почему то не работает, критует "System.StackOverflowException" при запуске программы
XML
1
2
3
  <UserControl.DataContext>
        <local:NumericUpDown/>
    </UserControl.DataContext>
0
Модератор
Эксперт .NET
15853 / 10999 / 2854
Регистрация: 21.04.2018
Сообщений: 32,283
Записей в блоге: 2
20.05.2019, 00:21 6
Лучший ответ Сообщение было отмечено Defences как решение

Решение

Цитата Сообщение от Defences Посмотреть сообщение
А как сделать привязку к DataContext
DataContext - это свойство для подключения VM. Если в UC не передаётся внешняя VM и источником данных служит он сам, то можно использовать его CB в качестве VM.
Подключение можно сделать как в CB, так и в XAML.
Выберите тот вариант, который Вам удобнее. Я предпочитаю в XAML.

Вариант №1
В CB окна указывается ссылка на самого себя
C#
33
34
35
36
37
        public NumericUpDown()
        {
            InitializeComponent();
            DataContext = this;
        }
В XAML указывается тип привязки
XML
1
2
3
4
5
6
7
<UserControl x:Class="HelloWorld.UsersControl.NumericUpDown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" Height="90" Width="100"
             DataContext="{x:Type local:NumericUpDown}">
1
Модератор
Эксперт .NET
15853 / 10999 / 2854
Регистрация: 21.04.2018
Сообщений: 32,283
Записей в блоге: 2
20.05.2019, 00:22 7
Лучший ответ Сообщение было отмечено Defences как решение

Решение

Вариант №2
CB не трогается в XAML указывается ссылка на самого себя
C#
35
        public NumericUpDown() => InitializeComponent();
XML
1
2
3
4
5
6
7
<UserControl x:Class="HelloWorld.UsersControl.NumericUpDown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" Height="90" Width="100"
             DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}">
1
Модератор
Эксперт .NET
15853 / 10999 / 2854
Регистрация: 21.04.2018
Сообщений: 32,283
Записей в блоге: 2
20.05.2019, 00:22 8
Лучший ответ Сообщение было отмечено Defences как решение

Решение

Вариант №3
Для UC есть ещё нюанс. UC - это WPF элемент. А у WPF элемента должны быть не CLR-свойства, а DP-свойства.
Представьте себе использование UC в View. Там у Вас есть VM тоже с CLR-свойствами. И как теперь связать между собой два CLR-свойства? Это целый геморрой!

Поэтому делать надо так
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    /// <summary>
    /// Логика взаимодействия для NumericUpDown.xaml
    /// </summary>
    public partial class NumericUpDown : UserControl
    {
 
        public int Price
        {
            get { return (int)GetValue(PriceProperty); }
            set { SetValue(PriceProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for Price.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PriceProperty =
            DependencyProperty.Register("Price", typeof(int), typeof(NumericUpDown), new PropertyMetadata(0));
 
 
 
        public NumericUpDown() => InitializeComponent();
        private void BtnUp_Click(object sender, RoutedEventArgs e) => Price++;
        private void BtnDown_Click(object sender, RoutedEventArgs e) => Price--;
 
    }
1
Модератор
Эксперт .NET
15853 / 10999 / 2854
Регистрация: 21.04.2018
Сообщений: 32,283
Записей в блоге: 2
20.05.2019, 01:03 9
Лучший ответ Сообщение было отмечено Defences как решение

Решение

Вариант №4
Другой нюанс. Все эти варианты - это варианты с неизолированной локальной VM. Что это означает...
При создании UC запускается конструктор в CB. Оттуда вызывается InitializeComponent() в котором происходит инициализация XAML разметки. Если в ней указан DataContext, то он тоже устанавливается.
После вызова InitializeComponent код CB работает дальше. Если в нём указано присвоение DataContext, то DataContext изменяет значение. После создания элемента он передаётся в код откуда вызывалось его создание. И теперь если в коде опять установится DataContext (а если хоть на каком-то уровне выше идёт привязка к VM, то он тоже устанавливается), то DataContext UC изменится и может нарушится его работа.

Допустим, если бы не установили тип DataContext
XML
1
2
3
4
5
6
7
<UserControl x:Class="HelloWorld.UsersControl.NumericUpDown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" Height="90" Width="100"
             DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}">
То при создании UC в View не было бы проверки типа, привязка Text="{Binding Price}" искала бы свойство во внешнем DataContext. А кнопки меняли бы внутренний, в результате - неправильная работа.
Но установка проверки типа не защищает от ошибок.
Допустим, если объявление UC в View делать так, то работа UC нарушится
XML
1
        <local:NumericUpDown DataContext="{Binding}"/>
Поэтому в UC с неизолированной локальной VM все элементы должны работать с этой VM, а не c View UC.
То есть методы инкремента/декремента в кнопках тоже должны работать не с просто Price, а с этим свойством DataContext.
Получить его можно через рефлексию.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    public partial class NumericUpDown : UserControl
    {
 
        public int Price
        {
            get { return (int)GetValue(PriceProperty); }
            set { SetValue(PriceProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for Price.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PriceProperty =
            DependencyProperty.Register("Price", typeof(int), typeof(NumericUpDown), new PropertyMetadata(0));
 
 
 
        public NumericUpDown() => InitializeComponent();
        private void BtnUp_Click(object sender, RoutedEventArgs e) => AddPrice(1);
        private void BtnDown_Click(object sender, RoutedEventArgs e) => AddPrice(-1);
 
        private void AddPrice(int value)
        {
            var priceProperty = DataContext.GetType().GetProperty(nameof(Price));
            if (priceProperty?.PropertyType != typeof(int))
                return;
            priceProperty.SetValue(DataContext, (int)priceProperty.GetValue(DataContext) + value);
        }
 
    }
Теперь если во внешней VM будет свойство Price, то UC будет его нормально отображать и менять.
1
Модератор
Эксперт .NET
15853 / 10999 / 2854
Регистрация: 21.04.2018
Сообщений: 32,283
Записей в блоге: 2
20.05.2019, 01:25 10
Лучший ответ Сообщение было отмечено Defences как решение

Решение

Вариант №5
Но всегда ли нужно такое поведение?
Допустим, если сейчас проверить в View значение свойств Price у ViewModel и UC то они окажутся разными!

Код ViewModel
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
    public class PriceVM : INotifyPropertyChanged
    {
        private int price;
 
        /// <summary>Событие для извещения об изменения свойства</summary>
        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>Метод для вызова события извещения об изменении свойства</summary>
        /// <param name="propertyName">Изменившееся свойство</param>
        public void OnPropertyChanged([CallerMemberName]string propertyName = "") =>
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 
        public int Price { get => price; set { price = value; OnPropertyChanged(); } }
    }
XAML View
XML
10
11
12
13
14
15
16
17
    <StackPanel>
        <StackPanel.DataContext>
            <local:PriceVM/>
        </StackPanel.DataContext>
        <local:NumericUpDown x:Name="numericUpDown" DataContext="{Binding}"/>
        <TextBlock Text="{Binding Price}"/>
        <TextBlock Text="{Binding Price, ElementName=numericUpDown}"/>
    </StackPanel>
Вроде UC работает, отображаемое значение меняется, но свойство самого UC остаются неизменными! То есть нужно ещё и согласованное изменение свойств самого UC. И это тоже надо делать через рефлексию.
Но всегда ли это нужно? Если у нас в UC есть внешнее DP-свойство которое при необходимости мы можем привязать к VM, нужна ли нам VM ещё и в DataContext? По разному. Очень часто не нужна.
В этом случае надо изолировать локальную VM.
Один из простых способов это задать DataContext не самому UC, а его главному контейнеру. В данном случае это Grid.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<UserControl x:Class="WPF1903.NumericUpDown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPF1903"
             mc:Ignorable="d" 
             Width="100" Height="90">
    <Grid DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:NumericUpDown}}}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button x:Name="btnUp" Content="Up"  Grid.Row="0"  Click="BtnUp_Click"/>
        <TextBox x:Name="tbView"  Text="{Binding Price}" Foreground="Black" Grid.Row="1"/>
        <Button x:Name="btnDown" Content="Down"  Grid.Row="2" Click="BtnDown_Click" />
    </Grid>
</UserControl>
Теперь изменение из вне DataContext самого UC не повлияет на его работу. Если запустить предыдущий пример View, то отображаемое значение в UC равно значению его свойства Price. Но не меняется значение свойства Price у ViewModel.
Это свойство теперь надо явно привязать к свойству UC.
XML
10
11
12
13
14
15
16
17
    <StackPanel>
        <StackPanel.DataContext>
            <local:PriceVM Price="100"/>
        </StackPanel.DataContext>
        <local:NumericUpDown x:Name="numericUpDown" Price="{Binding Price, Mode=TwoWay}" />
        <TextBlock Text="{Binding Price}"/>
        <TextBlock Text="{Binding Price, ElementName=numericUpDown}"/>
    </StackPanel>
Теперь всё синхронно меняется.
1
20.05.2019, 01:25
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.05.2019, 01:25
Помогаю со студенческими работами здесь

Template и свойство TextBox-а "Text"
В ControlTemplate что-то типа: &lt;Border Background=&quot;{TemplateBinding Background}&quot;&gt; &lt;TextBox...

Как заставить свойство "Text" компонента Label забиндиться на свойство TheChar из пользовательского класса
Здравствуйте, не получается заставить свойство &quot;Text&quot; компонента Label забиндиться на свойство...

Сохранение текста (label.text или textBox.text) для повторного использования
В общем когда пользователь входит необходимо чтоб он авторизовался, а для того чтоб этого не делать...

Как привязать свойство к переменной?
В общем я вроде привязал свойство к переменной и при запуске оно принимает ее вид. Но в дальнейшем,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru