Моя модель просмотра:
public class MainViewModel : INotifyPropertyChanged
{
private User selectedUser;
private IUserRepository _userRepository;
public List<User> Users { get; set; }
public User SelectedUser
{
get { return selectedUser; }
set
{
selectedUser = value;
OnPropertyChanged("SelectedUser");
}
}
public MainViewModel(IUserRepository userRepository)
{
_userRepository = userRepository;
Users = GetAllUsers();
}
public List<User> GetAllUsers()
{
var users = _userRepository.GetAllUsers();
return users;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
Мой взгляд:
<Window x:Class = "AppDesc.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable = "d"
xmlns:vm = "clr-namespace:AppDesc.ViewModels"
Title = "MainWindow" Height = "350" Width = "525">
<Window.Resources>
<Style TargetType = "TextBlock">
<Setter Property = "FontSize" Value = "14" />
</Style>
<Style TargetType = "TextBox">
<Setter Property = "FontSize" Value = "14" />
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "*" />
<ColumnDefinition Width = "0.8*" />
</Grid.ColumnDefinitions>
<ListBox Grid.Column = "0" ItemsSource = "{Binding Users}"
SelectedItem = "{Binding SelectedUser}" Background = "#FFA68F8F">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin = "5">
<TextBlock FontSize = "18" Text = "{Binding Path=Name}" />
<TextBlock Text = "{Binding Path=Login}" />
<TextBlock Text = "{Binding Path=Password}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Grid.Column = "1" DataContext = "{Binding SelectedUser}" Background = "{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" HorizontalAlignment = "Stretch" VerticalAlignment = "Stretch">
<TextBlock Text = "Выбранный элемент" />
<TextBlock Text = "ФИО" />
<TextBox Text = "{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text = "Логин" />
<TextBox Text = "{Binding Login, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text = "Телефон" />
<TextBox Text = "{Binding TelephoneNumber, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Grid>
</Window>
Код позади моего представления:
Я попытался назначить свою ViewModel для DataContext в программном коде, но возникает ошибка, потому что моя модель представления имеет конструктор с параметрами. Как правильно связать модель представления и само представление, если конструктор во ViewModel принимает параметры?





Самый простой способ присвоить ViewModel представлению — использовать шаблон ViewModelLocator.
Сначала определите класс локатора, который обрабатывает создание экземпляров ViewModel.
public class ViewModelLocator
{
// substitute your choice of DNS container here
[DNS_Container].Register<IUSerRepository, UserRepository>()
[DNS_Container].Register<MainViewModel>()
public MainViewModel MainViewModel => [DNS_Container].GetInstance<MainViewModel>();
...
}
Теперь создайте экземпляр этого класса локатора в App.Xaml, что сделает его доступным в качестве ресурса для всего приложения.
<Application ...>
<Application.Resources>
<local:ViewModelLocator x:Key = "ViewModelLocator" />
...
</Application.Resources>
</Application>
Теперь вы можете назначить DataContext представления, используя ресурс ViewModelLocator в качестве источника.
<Window
x:Class = "MainView"
...
DataContext = "{Binding Source = {StaticResource ViewModelLocator}, Path=MainViewModel}"
>
Эта конструкция также позволяет передавать живые данные в представление во время разработки — подробнее в моем сообщении в блоге.
Самый чистый способ — внедрить ViewModel в каждый View с помощью DependencyInjection-Framework.
Вы можете использовать библиотеку Wpf.Extensions.Hosting для запуска приложений WPF на Generic Host.
Чтобы внедрить ViewModel, просто измените код программной части View на
public class MainWindow : Window
{
public MainWindow( MainViewModel viewModel )
{
InitializeComponent();
DataContext = viewModel;
}
}
и основной код для
// Create a builder by specifying the application and main window.
var builder = WpfApplication<App, MainWindow>.CreateBuilder(args);
// Configure dependency injection.
// Injecting MainWindowViewModel into MainWindow.
builder.Services
.AddTransient<MainWindowViewModel>()
.AddTransient<IUserRepository,UserRepositoryImplementingClass>();
var app = builder.Build();
await app.RunAsync();
Вот и все.
Вы можете найти полный пример на github.com
См. Как обрабатывать внедрение зависимостей в приложении WPF/MVVM