Как связать элемент управления с ViewModel?
В Xamarin.Forms, чтобы связать элемент управления (UI-элемент) с ViewModel, используется механизм привязки данных (Data Binding). Основная идея заключается в том, чтобы UI (View) «слушал» свойства и команды, определённые во ViewModel. При изменении значений в ViewModel пользовательский интерфейс обновляется автоматически, и наоборот — при двусторонней привязке.
Процесс связывания элементов управления с ViewModel включает:
-
Создание ViewModel с нужными свойствами и командами.
-
Назначение ViewModel как BindingContext страницы или элемента.
-
Настройку привязки в XAML или C# с использованием синтаксиса {Binding ...}.
1. Подготовка ViewModel
ViewModel — это обычный C#-класс, реализующий интерфейс INotifyPropertyChanged, который сообщает интерфейсу об изменениях в данных.
Пример ViewModel:
public class MainViewModel : INotifyPropertyChanged
{
private string userName;
public string UserName
{
get => userName;
set
{
if (userName != value)
{
userName = value;
OnPropertyChanged(nameof(UserName));
}
}
}
public ICommand SubmitCommand { get; }
public MainViewModel()
{
SubmitCommand = new Command(OnSubmit);
}
private void OnSubmit()
{
// Логика обработки
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
2. Установка BindingContext
BindingContext — это объект, свойства которого будут использоваться в выражениях привязки. Обычно это экземпляр ViewModel.
Установка в C#:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainViewModel();
}
}
Установка в XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:local="clr-namespace:MyApp.ViewModels"
x:Class="MyApp.MainPage">
<ContentPage.BindingContext>
<local:MainViewModel />
</ContentPage.BindingContext>
3. Привязка свойств UI-элемента к ViewModel
Теперь можно привязать конкретные свойства элементов управления к свойствам ViewModel, используя синтаксис {Binding PropertyName}.
Пример: Entry (ввод текста) и Label (отображение)
ViewModel:
public string UserName { get; set; }
XAML:
<Entry Text="{Binding UserName, Mode=TwoWay}" Placeholder="Введите имя" />
<Label Text="{Binding UserName}" />
- Mode=TwoWay позволяет как получать значение, так и отправлять его обратно из UI в ViewModel.
4. Привязка команд (ICommand)
Чтобы обработать действия пользователя, например нажатие кнопки, можно привязать кнопку к команде из ViewModel.
ViewModel:
public ICommand SubmitCommand { get; }
public MainViewModel()
{
SubmitCommand = new Command(OnSubmit);
}
XAML:
<Button Text="Отправить" Command="{Binding SubmitCommand}" />
5. Привязка коллекции к списковому элементу (ListView, CollectionView)
Для отображения списков объектов из ViewModel используется ObservableCollection.
ViewModel:
public ObservableCollection<string> Items { get; }
public MainViewModel()
{
Items = new ObservableCollection<string>
{
"Элемент 1",
"Элемент 2",
"Элемент 3"
};
}
XAML:
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding .}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
{Binding .} — означает привязку к самому элементу коллекции, если он простого типа, например string.
6. Использование BindingContext на уровне компонентов
BindingContext можно задавать не только на уровне страницы, но и у отдельных элементов или layout-контейнеров.
Пример:
<StackLayout BindingContext="{Binding CurrentUser}">
<Label Text="{Binding Name}" />
<Label Text="{Binding Email}" />
</StackLayout>
В этом случае Name и Email должны быть свойствами объекта CurrentUser, который, в свою очередь, является свойством ViewModel.
7. Привязка к ресурсам и конвертерам
Если нужно изменить отображаемое значение (например, логическое значение → цвет), можно использовать IValueConverter.
Пример конвертера:
public class BoolToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Color.Green : Color.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
Ресурс в XAML:
<ContentPage.Resources>
<ResourceDictionary>
<local:BoolToColorConverter x:Key="BoolToColorConverter" />
</ResourceDictionary>
</ContentPage.Resources>
Использование:
<Label Text="Статус"
TextColor="{Binding IsActive, Converter={StaticResource BoolToColorConverter}}" />
8. Проверка правильности привязки
Иногда элемент не отображает данные, даже если привязка указана. Чтобы устранить ошибки:
-
Убедитесь, что свойство BindingContext установлено правильно.
-
Проверьте, что имена свойств указаны корректно (учитывается регистр).
-
Убедитесь, что свойства ViewModel реализуют уведомления (INotifyPropertyChanged).
-
Для ListView и CollectionView используйте ObservableCollection.
-
Включите отладку привязки в Output (Visual Studio → Output → Xamarin Output).
9. Пример полной привязки элемента к ViewModel
ViewModel:
public class LoginViewModel : INotifyPropertyChanged
{
private string username;
public string Username
{
get => username;
set
{
username = value;
OnPropertyChanged(nameof(Username));
}
}
private string password;
public string Password
{
get => password;
set
{
password = value;
OnPropertyChanged(nameof(Password));
}
}
public ICommand LoginCommand { get; }
public LoginViewModel()
{
LoginCommand = new Command(OnLogin);
}
private void OnLogin()
{
// Авторизация
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:local="clr-namespace:MyApp.ViewModels"
x:Class="MyApp.LoginPage">
<ContentPage.BindingContext>
<local:LoginViewModel />
</ContentPage.BindingContext>
<StackLayout Padding="20">
<Entry Placeholder="Логин" Text="{Binding Username}" />
<Entry Placeholder="Пароль" Text="{Binding Password}" IsPassword="True" />
<Button Text="Войти" Command="{Binding LoginCommand}" />
</StackLayout>
</ContentPage>
10. Привязка в C# (без XAML)
Иногда вся страница создаётся на C#, без XAML. В этом случае привязка тоже возможна.
Пример:
var entry = new Entry();
entry.SetBinding(Entry.TextProperty, "Username");
var button = new Button { Text = "Войти" };
button.SetBinding(Button.CommandProperty, "LoginCommand");
Content = new StackLayout
{
Children = { entry, button }
};
BindingContext = new LoginViewModel();
Связывание элементов управления с ViewModel в Xamarin.Forms — ключевой механизм построения реактивного, масштабируемого интерфейса. Он минимизирует необходимость писать код вручную, обеспечивая чистую архитектуру и лёгкую поддержку при росте функциональности приложения.