wpf 从单独的类文件调用命令

snz8szmq  于 2023-01-10  发布在  其他
关注(0)|答案(1)|浏览(149)

因此,我已经在它几天,并为我的生活找不到任何文件,完全符合我的情况在这里。
我基本上已经设置了一个自定义导航服务,并希望直接从用户控件调用ViewModel类中的命令。
我想我在这里的边缘,但我缺乏经验的C#是开枪打我的脚。
下面是我的Login.xaml.cs中的一段代码:

private LoginViewModel _loginViewModel;
        public Login(LoginViewModel loginViewModel)
        {
            _loginViewModel = loginViewModel;
        }
        private void GrantAccess()
        {
            int userAccess = Int16.Parse(User.Access);
            if (userAccess == 1)
            {
                MessageBox.Show("The bottom man");
            }
            if (userAccess == 2)
            {
                MessageBox.Show("The little boss");
            }
            if (userAccess == 3)
            {
                MessageBox.Show("The little big boss");
            }
            if (userAccess == 4)
            {
                {
                    _loginViewModel.NavigateMM1Command.Execute(null);
                }
            }

        }

下面是我试图从ViewModel引用的命令:

public class LoginViewModel : BaseViewModel
    {
        public ICommand NavigateMM1Command { get; }
        public LoginViewModel(NavigationStore navigationStore)
        {
            NavigateMM1Command = new NavigateCommand<MM1ViewModel>(new NavigationService<MM1ViewModel>(navigationStore, () => new MM1ViewModel(navigationStore)));
        }
    }

基本上,我一直在通过一个又一个教程,试图将他们教的东西应用到我需要的东西上,而且大部分都很有效,但是现在_loginViewModel抛出了一个空引用异常,我不知道为什么。
我试过:

LoginViewModel loginViewModel = new loginViewModel();

但是它要求我通过它传递一个navigationstore参数,这感觉不对。这里的任何帮助都会治愈我暂时的精神错乱XD

jfgube3f

jfgube3f1#

您将收到空对象引用,因为在构造LoginViewModelnavigationStorenull
也就是说,在构造LoginViewModel时,您尚未配置示例化类型navigationStore的方法。
依赖注入(DI)或控件调用(IoC)是本答案中要涵盖的更全面的主题。
话虽如此,我还是要在这里提供一些代码来回顾一下,它代表了一种使用类型Map集合来配置服务提供者的方法。
在这个完整的ConsoleApp示例中,我们将显式示例化ServiceCollection,添加服务类型(指定Map到哪里的应用程序),并构建ServiceProvider;有了这个提供程序,我们将使用GetService解析和示例化Login类型--示例化所有类型;
类型本质上是您指定的类型的模型,但我修改了一些方面(一个虚构的概念,就像您的Execute方法和NavigationStore的用法一样)。

演示导航类型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleDemo.NavLoginDemo
{
    public interface ICommand 
    {
        void Execute(string? userName);
    }

    public interface INavigationStore {
        public bool this[string index] { get;set; }
    }

    public interface INavigationService {
        void GrantAccessToUser(string userName);
    }
    public interface INavigationViewModel { }

    internal class NavigationStore : INavigationStore
    {
        private Dictionary<string, bool> userAccessDict;

        public NavigationStore() { 
            userAccessDict = new Dictionary<string, bool>();
        }

        public bool this[string index] { 
            get => userAccessDict.TryGetValue(index, out var val) && val; 
            set => userAccessDict[index] = value; 
        }
    }

    internal class NavigationService : INavigationService
    {
        private readonly INavigationStore _navigationStore;

        public NavigationService(INavigationStore navigationStore) 
        {
            _navigationStore = navigationStore;
        }

        public void GrantAccessToUser(string? userName)
        {
            if (string.IsNullOrWhiteSpace(userName))
                throw new ArgumentException(nameof(userName));

            _navigationStore[userName!] = true;
        }
    }

    internal class NavigationCommand : ICommand
    {
        private readonly INavigationService _navigationService;
        public NavigationCommand(INavigationService navigationService) 
        {
            _navigationService = navigationService;
        }

        public void Execute(string? userName)
        {
            if (userName != null)
            {
                _navigationService.GrantAccessToUser(userName);
            }
        }
    }

    internal class User
    {
        public string? Name { get; set; }
        public string Access { get; set; } = "1";
    }

    public abstract class BaseViewModel
    {
        internal User User { get; set; } = new User();

        protected BaseViewModel() { }
    }

    internal class LoginViewModel : BaseViewModel, INavigationViewModel
    {
        private readonly ICommand _command;

        public LoginViewModel(ICommand command) : base()
        {
            _command = command;
        }

        internal ICommand NavigateMM1Command => _command;
    }

    internal class Login
    {

        private User User => _loginViewModel.User;

        private readonly LoginViewModel _loginViewModel;
        public Login(LoginViewModel loginViewModel) 
        { 
            _loginViewModel = loginViewModel;   
        }

        internal void SetAccess(int access)
        {
            SetAccess($"{access}");
        }
        internal void SetAccess(string access)
        {
            User.Access = access; 
        }

        internal void SetUserName(string userName) { User.Name = userName; }

        internal async Task GrantAccessAsync()
        {
            await Task.Yield();

            int userAccess = Int16.Parse(User.Access);
            switch (userAccess)
            {
                case 1:
                    Console.WriteLine("The bottom man");
                    break;
                case 2:
                    Console.WriteLine("The little boss");
                    break;
                case 3:
                    Console.WriteLine("The little big boss");
                    break;
                case 4:
                    _loginViewModel.NavigateMM1Command.Execute(User.Name);
                    break;
                default:
                    throw new NotImplementedException();
            }
        }

    }
}

Program.cs(使用Microsoft.扩展.依赖注入)

using Microsoft.Extensions.DependencyInjection;
using System.Collections.Immutable;
using System.ComponentModel.Design;
using System.Linq;
using ConsoleDemo.NavLoginDemo;

internal class Program
{

    private static async Task Main(string[] args)
    {
        var services = new ServiceCollection();
        var provder = ConfigureServices(services);

        var login = provder.GetService<Login>();

        if (login != null)
        {
            await login.GrantAccessAsync();
            login.SetAccess(2);
            await login.GrantAccessAsync();
            login.SetAccess(3);
            await login.GrantAccessAsync();
            login.SetUserName("James Bond");
            login.SetAccess(4);
            await login.GrantAccessAsync();
        }

    }

    private static IServiceProvider ConfigureServices(IServiceCollection services)
    {
        return services
            .AddScoped<INavigationStore, NavigationStore>()
            .AddScoped<INavigationService, NavigationService>()
            .AddScoped<ICommand, NavigationCommand>()
            .AddScoped<LoginViewModel>()
            .AddScoped<Login>()
            .BuildServiceProvider();
    }
}

备注

  • -但是,在您的应用程序中,您的Program.cs或Startup.cs文件中可能已经有一个ServiceCollection示例。并且ServiceProvider(或HostProvider)将由应用程序管理;因此,您可能不需要显式解析(或GetService<T>)--只需在ServiceCollection中添加Service Type(Map)。这些参数类型将被示例化并"注入"到自身正在示例化的Type的构造函数中。

相关问题