Multibinding между 2 usercontrols
У меня есть 2 usercontrols. Usercontrol 1: панель меню с кнопками, такими как "Добавить", "Редактировать", "Удалить", "Сохранить" и "Отменить". Usercontrol 2: экран, на котором пользователь может вводить текст в текстовые поля и поля паролей
Но когда я хочу сохранить, я обычно делаю следующее, когда у меня есть только 1 пользовательский элемент управления, в котором есть кнопки и все, кроме разделенной меню и подробного экрана:
<Button Style="{DynamicResource SaveButton}" Command="{Binding Path=SaveCommand}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource pwConverter}">
<Binding ElementName="txtPassword" />
<Binding ElementName="txtRepeatPassword" />
</MultiBinding>
</Button.CommandParameter>
</Button>
Но теперь имя элемента "txtPassword" и "txtRepeatPassword" не существует в этой области. Это моя команда SaveCommand, когда я нажимаю кнопку сохранения. Он получает эти 2 параметра, поэтому я могу проверить, совпадают ли 2 пароля и все в таком духе.
private void SaveUserExecute(object passwords)
{
try
{
var passwordvalues = (object[])passwords;
PasswordBox passwordBox1 = (PasswordBox)passwordvalues[0];
PasswordBox passwordBox2 = (PasswordBox)passwordvalues[1];
...
Есть идеи, как решить эту проблему?
2 ответа
Это легко, если вы используете шаблон MVVM. Вы можете иметь одну ViewModel, которая может быть DataContext для каждого из ваших пользовательских элементов управления, и ваше главное окно. Затем просто свяжите со свойствами каждого из них.
Ниже приведен пример ViewModel, в котором есть поля, доступные через свойства, с которыми мы можем связать:
public class ViewModel : INotifyPropertyChanged
{
private readonly Command _command;
public Command Command
{
get { return _command; }
}
public ViewModel()
{
_command = new Command(this);
}
private string _textBoxOnUserControlOne;
private string _textBoxOnUserControlTwo;
public string TextBoxOnUserControlOne
{
get { return _textBoxOnUserControlOne; }
set
{
if (value == _textBoxOnUserControlOne) return;
_textBoxOnUserControlOne = value;
OnPropertyChanged("TextBoxOnUserControlOne");
}
}
public string TextBoxOnUserControlTwo
{
get { return _textBoxOnUserControlTwo; }
set
{
if (value == _textBoxOnUserControlTwo) return;
_textBoxOnUserControlTwo = value;
OnPropertyChanged("TextBoxOnUserControlTwo");
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Вот класс команд, где я собираюсь работать с обоими этими свойствами:
public class Command : ICommand
{
private readonly ViewModel _viewModel;
public Command(ViewModel viewModel)
{
_viewModel = viewModel;
}
public void Execute(object parameter)
{
var dataOnControlOne = _viewModel.TextBoxOnUserControlOne;
var dataOnControlTwo = _viewModel.TextBoxOnUserControlTwo;
//Use these values
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
Теперь, вот мой первый пользовательский элемент управления 1, который связан с одним из полей моей ViewModel, обратите внимание на DataContext:
<UserControl ... DataContext="{StaticResource ViewModel}">
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Text="{Binding TextBoxOnUserControlOne}" Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
</Grid>
</UserControl>
А вот второй UserControl с тем же DataContext, и текстовое поле привязано к другому свойству:
<UserControl ... DataContext="{StaticResource ViewModel}">
<Grid>
<TextBox Height="23" HorizontalAlignment="Left" Text="{Binding TextBoxOnUserControlTwo}" Margin="12,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
</Grid>
</UserControl>
Вот мое главное окно, которое содержит оба этих пользовательских элемента управления и кнопку, привязанную к моему классу команд:
<Window ... DataContext="{StaticResource ViewModel}">
<Grid>
<my:UserControl1 HorizontalAlignment="Left" Margin="160,69,0,0" x:Name="userControl11" VerticalAlignment="Top" Height="47" Width="155" />
<my:UserControl2 HorizontalAlignment="Left" Margin="160,132,0,0" x:Name="userControl12" VerticalAlignment="Top" Height="48" Width="158" />
<Button Content="Button" Command="{Binding Command}" Height="23" HorizontalAlignment="Left" Margin="199,198,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
</Grid>
</Window>
И наконец мой класс App.Xaml, чтобы склеить все вместе:
<Application ...>
<Application.Resources>
<wpfApplication4:ViewModel x:Key="ViewModel"/>
</Application.Resources>
</Application>
Здесь у нас есть отдельные пользовательские элементы управления, и поля привязаны к свойствам в модели одного представления. Эта модель представления передает себя в командный класс, который затем может получить доступ к свойствам, с которыми связаны текстовые поля в отдельных пользовательских элементах управления, и работать с ними при нажатии кнопки. Надеюсь, это поможет!
Поскольку мои 2 пользовательских элемента управления совместно использовали один и тот же DataContext, я создал 2 свойства, которые представляют мои пароли. Когда я инициализировал это представление, я сделал следующее:
public InputUserView()
{
InitializeComponent();
this.DataContext = InputUserViewModel.Instance;
InputUserViewModel.Instance.PasswordBox1 = txtPassword;
InputUserViewModel.Instance.PasswordBox2 = txtRepeatPassword;
}
Так что теперь моя viewmodel знает о тех 2 паролях. Я думаю, что это не очень хорошо, но это работает для меня, и я могу жить с этим