#c# #wpf #xaml #mvvm
#c# #wpf #xaml #mvvm
Вопрос:
У меня есть 2 пары текстовых полей для пользовательского ввода (см. XAML ниже). В подавляющем большинстве случаев входные данные для A1 и A2 будут идентичны B1 и B2, поэтому я добавил привязки для txtDataB1
и txtDataB2
для «зеркального отображения» входных данных для A1 и A2, что работает в пользовательском интерфейсе. Данные, введенные в A1 / A2, сохраняются нормально, поскольку они привязаны к dataStore
, но у меня есть некоторые проблемы:
Как мне сохранить значения, введенные в txtDataB1
и txtDataB2
(либо из ручного ввода пользователем, либо зеркальные данные из A1 / A2) в dataStore
объект? Я недостаточно знаком с XAML / MVVM / etc, чтобы знать, есть ли «чистый XAML» способ сделать это с помощью многосвязей или чего-то еще, или если бы была какая-то логика, которую я должен был бы создать / вызвать в модели представления.
<!-- Data A -->
<TextBox Name="txtDataA1" Text="{Binding dataStore.A1}" />
<TextBox Name="txtDataA2" Text="{Binding dataStore.A2}" />
<!-- Data B -->
<TextBox Name="txtDataB1" Text="{Binding ElementName=txtDataA1, Path=Text, Mode=OneWay}" />
<TextBox Name="txtDataB2" Text="{Binding ElementName=txtDataA2, Path=Text, Mode=OneWay}" />
Комментарии:
1. Я думаю, это должно сработать: привязать txtDataB? в хранилище данных.B? (реализация INotifyPropertyChanged), которое, в свою очередь, изменяется при изменении хранилища данных.A?.
2. Это не привело бы к обновлению пользовательского интерфейса, не так ли? Или, я думаю, когда срабатывает INotifyPropertyChanged, я мог бы обновить пользовательский интерфейс вручную
3. Реализация INotifyPropertyChanged означает, что вы вызываете PropertyChanged — это обновило бы пользовательский интерфейс.
Ответ №1:
Забудьте о попытке реализовать подобную логику приложения в «чистом XAML» и вместо этого реализуйте ее в модели представления. XAML — это язык разметки.
Параметр A1
должен быть установлен B1
, а параметр A2
должен быть установлен B2
, например:
public class ViewModel : INotifyPropertyChanged
{
private string _a1;
public string A1
{
get { return _a1; }
set { _a1 = value; NotifyPropertyChanged(); B1 = value; }
}
private string _b1;
public string B1
{
get { return _b1; }
set { _b1 = value; NotifyPropertyChanged(); }
}
// the same for A2 and B2
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
Сохранение данных — это тогда просто вопрос получения значений из свойств B1
и B2
, не имеет значения, как они были установлены.
Комментарии:
1. Это имеет смысл, однако у меня нет двух независимых свойств,
B1
иB2
в виртуальной машине они находятся внутри,ObserveableCollection<DataStore>
гдеDataStore
— пользовательский объект для этого проекта.2. @zakparks31191: Я не понимаю вашей проблемы. Если у вас нет свойств, вы, конечно, должны добавить их к любому объекту, к которому вы привязываете.
3. Да, это был правильный способ сделать это. Основная проблема заключалась в том, что структура MVVM всего этого проекта была выполнена неправильно, поэтому после переписывания, а затем реализации этого предложения, все сработало, как ожидалось.
Ответ №2:
Это можно решить с помощью двухполосной привязки, но текстовое поле по LostFocus
умолчанию обновляется, также необходимо изменить его UpdateSourceTrigger
, код будет следующим:
<!-- Data A -->
<TextBox Name="txtDataA1" Text="{Binding dataStore.A1, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Name="txtDataA2" Text="{Binding dataStore.A2, UpdateSourceTrigger=PropertyChanged}"/>
<!-- Data B -->
<TextBox Name="txtDataB1" Text="{Binding ElementName=txtDataA1, Path=Text, Mode=TwoWay}" />
<TextBox Name="txtDataB2" Text="{Binding ElementName=txtDataA2, Path=Text, Mode=TwoWay}" />
Комментарии:
1. Это дает те же результаты, что и код, который я привел в вопросе.
2. @zakparks31191 Реализовали ли вы NotifyPropertyChanged для хранилища данных. A1?