Передача параметров в ViewModel с помощью пользовательской реализации INavigationService? - PullRequest
0 голосов
/ 19 апреля 2019

Я создал небольшое приложение с использованием MVVM Light, и я достиг точки, в которой мне нужно передавать параметры между несколькими различными моделями представления в моем приложении. Я изучил несколько разных вариантов, но я не большой их фанат. Самое многообещающее, с чем я сталкивался до сих пор, - это просто передача сообщений между ViewModels, но это несколько ограничивает, так как у приложения есть потенциал для одновременного открытия нескольких одинаковых View, и мне нужно изолировать параметры в единственном экземпляре. View / ViewModel.

В настоящее время я не использую встроенный INavigationService, предоставляемый MVVM Light, но я сделал один невероятно похожий (и если я смогу решить внедрение параметров, я, скорее всего, переключусь).

Вот урезанная версия моей навигационной службы:

public class NavigationService : INavigationService
{
    /* this implementation will not allow us to have the same window open
       more than once. However, for this application, that should be sufficient.
    */
    public NavigationService()
    {
        _openPages = new Dictionary<string, Window>();
    }

    private readonly Dictionary<string, Window> _openPages;
    public void ClosePage(string pageKey)
    {
        if (!_openPages.ContainsKey(pageKey)) return;

        var window = _openPages[pageKey];

        window.Close();
        _openPages.Remove(pageKey);
    }

    public IEnumerable<string> OpenPages => _openPages.Keys;

    public void NavigateTo(string pageKey)
    {
        if (!AllPages.ContainsKey(pageKey))
            throw new InvalidPageException(pageKey);

        // Don't re-open a window that's already open
        if (_openPages.ContainsKey(pageKey))
        {
            _openPages[pageKey].Activate();
            return;
        }

        var page = (Window) Activator.CreateInstance(AllPages[pageKey]);
        page.Show();
        page.Closed += OnWindowClosedHandler;
        _openPages.Add(pageKey, page);
    }

    // Probably a better way to remove this.
    private void OnWindowClosedHandler(object sender, EventArgs args)
    {
        foreach (var item in _openPages.Where(kvp => kvp.Value == sender).ToList())
        {
            _openPages.Remove(item.Key);
        }
    }

    // Reflection might work for this.
    // Might also consider making this more dynamic so it isn't hard-coded into my service
    private readonly Dictionary<string, Type> AllPages = new Dictionary<string, Type>
    {
        ["AddPatientView"] = typeof(AddPatientView),
        ["CheckInView"] = typeof(CheckInView),
        ["MainView"] = typeof(MainWindow),
        ["PatientLookupView"] = typeof(PatientLookupView),
        ["PatientDetailsView"] = typeof(PatientDetailsView)
    };
}

Большинство моих моделей ViewModel используют внедрение зависимостей для подключения других внедряемых сервисов, например:

public class CheckInViewModel : ViewModelBase
{
    public CheckInViewModel(ILicenseValidationService licenseValidationService,
        IPatientFetchService patientFetchService,
        IPatientCheckInService patientCheckInService)
    {
        if (IsInDesignMode)
        {
            Title = "Find Member (Design)";
        }
        else
        {
            Title = "Find Member";

            CanFetch = true;
            FindMemberCommand = new RelayCommand(async () => await FindMemberHandler(), () => CanFetch);
            CheckInPatientCommand = new RelayCommand<Window>(async (window) => await CheckInPatientHandler(window),
                (window) => Patient?.PatientId != null);

            _licenseValidationService = licenseValidationService;
            _patientFetchService = patientFetchService;
            _patientCheckInService = patientCheckInService;
        }
    }
}

Я хотел бы реализовать какой-то метод ввода других параметров наряду с моими внедренными службами. Было ли что-то подобное сделано относительно простым способом?

1 Ответ

0 голосов
/ 19 апреля 2019

Способ внедрения зависимостей работает почти во всех случаях, когда вы разрешаете или получаете экземпляр типа, который затем использует конструктор с наибольшим количеством параметров для предоставления вам объекта.

Если вы регистрируете конкретный объект дляИнтерфейс (или просто тип) затем разрешает / получает класс, который использует одну из этих вещей в своем ctor, а затем DI предоставляет зарегистрированный экземпляр.

С MVVMLight у вас есть SimpleIoc, а SimpleIoc.Default эквивалентентот статический сервис, о котором ты думаешь.Это очень просто.

С simpleioc, как только вы получаете экземпляр модели данного типа, это одиночный объект.Вы можете форсировать другой экземпляр, передавая уникальный ключ, но все они кэшируются.Вы можете получить экземпляр с параметрами и, возможно, заменить текущий объект.Я не уверен, случайно.Может потребоваться более сложный контейнер DI.

Кроме этого.

Поскольку вы используете разные окна, это создает некоторую сложность в том, что вы хотите создать экземпляр окна, и это будету вас должен быть текстовый текст, который нужно как-то предоставить с вашими параметрами.

Сначала вы можете использовать viewmodel.Вы получаете inavigationservice из DI или ресурсов или статического.

У вас есть метод DoWindow (Object vm).

Когда вы хотите перемещаться, вы, вероятно, знаете параметры для vm.Добавьте в вашу модель представления параметры.Новое окно, которое вы используете для всех видов.Установите его содержание для вашей viewmodel.Это связано с тем, что у вас есть как окна сейчас.За исключением того, что вы делаете их usercontrols.Используйте Datatype = "vmtype", чтобы связать представление как шаблон с viewmodel.Свяжите заголовок вашего окна с Content.Title и, конечно, добавьте свойство Title к базовой модели представления.

В качестве альтернативы, в приложении с одним окном вы можете управлять контентом, заполняющим область, в которой будут отображаться виды. Bindсодержимое этого свойства currentviewmodel, и вы можете использовать первую навигацию viewmodel в этом окне.

...