wpf 如果ViewModel构造函数有参数,如何连接View和ViewModel?

5t7ly7z5  于 2023-08-07  发布在  其他
关注(0)|答案(2)|浏览(262)

我的视图模型:

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分配给Code Behind中的DataContext,但发生错误,因为我的视图模型具有带参数的构造函数。如果ViewModel中的构造函数带参数,如何正确连接视图模型和视图本身?

igsr9ssn

igsr9ssn1#

最干净的方法是通过DependencyInjection-Framework将ViewModel注入到每个View中。
您可以使用库Wpf.Extensions.Hosting在Generic Host上运行WPF应用程序。
要注入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找到一个完整的例子

ctehm74n

ctehm74n2#

将ViewModel分配给View的最简洁的方法是使用ViewModelLocator模式。
首先定义locator类,它处理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>


现在可以使用ViewModelLocator资源作为源来分配View的DataContext。

<Window
    x:Class="MainView"
    ...
    DataContext="{Binding Source={StaticResource ViewModelLocator}, Path=MainViewModel}"
>


这个构造还允许在设计时将实时数据提供给View-更多细节请参见我的blog post

相关问题