Я только начал программировать на C# и хотел что-то сделать с самого начала. Итак, я узнал о шаблоне MVVM и попытался с ним работать. Для этого я использовал делегата от ICommand с лямбда-функциями.делегат Async ICommand для шаблона MVVM с возвращаемым значением
Это прекрасно работает, но поскольку моя программа использует запросы HTML, мне нужно было найти способ сделать вызовы для асинхронных команд.
Так я нашел хорошую реализацию которой я пытался понять, но мне не удалось в какой-то момент ... Вот идет Реализация:
public interface IRaiseCanExecuteChanged
{
void RaiseCanExecuteChanged();
}
// And an extension method to make it easy to raise changed events
public static class CommandExtensions
{
public static void RaiseCanExecuteChanged(this ICommand command)
{
var canExecuteChanged = command as IRaiseCanExecuteChanged;
if (canExecuteChanged != null)
canExecuteChanged.RaiseCanExecuteChanged();
}
}
public class DelegateCommand : DelegateCommand<object>
{
public DelegateCommand(Action executeMethod)
: base(o => executeMethod())
{
}
public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
: base(o => executeMethod(), o => canExecuteMethod())
{
}
}
/// <summary>
/// A command that calls the specified delegate when the command is executed.
/// </summary>
/// <typeparam name="T"></typeparam>
public class DelegateCommand<T> : ICommand, IRaiseCanExecuteChanged
{
private readonly Func<T, bool> _canExecuteMethod;
private readonly Action<T> _executeMethod;
private bool _isExecuting;
public DelegateCommand(Action<T> executeMethod)
: this(executeMethod, null)
{
}
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
{
if ((executeMethod == null) && (canExecuteMethod == null))
{
throw new ArgumentNullException("executeMethod", @"Execute Method cannot be null");
}
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
bool ICommand.CanExecute(object parameter)
{
return !_isExecuting && CanExecute((T)parameter);
}
void ICommand.Execute(object parameter)
{
_isExecuting = true;
try
{
RaiseCanExecuteChanged();
Execute((T)parameter);
}
finally
{
_isExecuting = false;
RaiseCanExecuteChanged();
}
}
public bool CanExecute(T parameter)
{
if (_canExecuteMethod == null)
return true;
return _canExecuteMethod(parameter);
}
public void Execute(T parameter)
{
_executeMethod(parameter);
}
}
public interface IAsyncCommand : IAsyncCommand<object>
{
}
public interface IAsyncCommand<in T> : IRaiseCanExecuteChanged
{
Task ExecuteAsync(T obj);
bool CanExecute(object obj);
ICommand Command { get; }
}
public class AwaitableDelegateCommand : AwaitableDelegateCommand<object>, IAsyncCommand
{
public AwaitableDelegateCommand(Func<Task> executeMethod)
: base(o => executeMethod())
{
}
public AwaitableDelegateCommand(Func<Task> executeMethod, Func<bool> canExecuteMethod)
: base(o => executeMethod(), o => canExecuteMethod())
{
}
}
public class AwaitableDelegateCommand<T> : IAsyncCommand<T>, ICommand
{
private readonly Func<T, Task> _executeMethod;
private readonly DelegateCommand<T> _underlyingCommand;
private bool _isExecuting;
public AwaitableDelegateCommand(Func<T, Task> executeMethod)
: this(executeMethod, _ => true)
{
}
public AwaitableDelegateCommand(Func<T, Task> executeMethod, Func<T, bool> canExecuteMethod)
{
_executeMethod = executeMethod;
_underlyingCommand = new DelegateCommand<T>(x => { }, canExecuteMethod);
}
public async Task ExecuteAsync(T obj)
{
try
{
_isExecuting = true;
RaiseCanExecuteChanged();
await _executeMethod(obj);
}
finally
{
_isExecuting = false;
RaiseCanExecuteChanged();
}
}
public ICommand Command { get { return this; } }
public bool CanExecute(object parameter)
{
return !_isExecuting && _underlyingCommand.CanExecute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add { _underlyingCommand.CanExecuteChanged += value; }
remove { _underlyingCommand.CanExecuteChanged -= value; }
}
public async void Execute(object parameter)
{
await ExecuteAsync((T)parameter);
}
public void RaiseCanExecuteChanged()
{
_underlyingCommand.RaiseCanExecuteChanged();
}
}
Теперь у меня есть два вопроса. 1. Хорошо ли это реализовать, как они это сделали? Как я вижу, объект T просто используется как параметр функции, который я могу передать своей лямбда-функции.
Что я могу сделать с этим кодом является следующее:
private ObservableList<string, string> dict;
private IAsyncCommand searchCommand;
public async Task myFunction() {
//changes global variable dict bound to view
public IAsyncCommand MyCommand
{
get
{
if (myCommand == null)
{
myCommand = new AwaitableDelegateCommand(
() =>
{
return myFunction(myParameter);
});
}
return searchCommand;
}
}
где туРипсЫоп редактирует глобальную переменную Dict, который связан с точки зрения с помощью функции MyFunction с добытчиками и сеттеров. Надеюсь, это обычная практика, потому что я просто так ее нашел. Мы возвращаем задачу здесь, и AwaitableDelegateCommand внутренне ждет ее, поэтому нам не нужно заботиться. Но мы не можем получить доступ к задаче или ее результату, правильно?
Итак, как я мог достичь этого, если myFunction не возвращает void, а переменную. Тогда мне нужно было бы получить результат задания (после ожидания async) и назначить его списку.
код будет выглядеть следующим образом:
public async Task<ObservableDictionary<string, string>> myFunction() {
var dict = new ObservableDictionary<string, string>();
//do work....
return dict;
}
public IAsyncCommand MyCommand
{
get
{
if (myCommand == null)
{
//what to do here to assign dict the result of the Task?
}
return searchCommand;
}
}
Это сделает мой код более многократного использования, и я хочу, чтобы это было хорошо :) Надежда кто-то может мне помочь.
EDIT: Поскольку моя проблема не очень ясна, я пытаюсь объяснить ее еще раз.
Мой метод возвращает значение, и я хочу, чтобы мой метод для запуска асинхронной с AwaitableDelegateCommand
Теперь проблема ... А метод, который возвращает значение, как правило, ничего не делать с остальной частью кода, но со значением который возвращается ... В моем случае он заполняет словарь из запроса HTML и возвращает его. Если я теперь запускаю метод async в лямбда, он ничего не делает .... потому что я не могу получить результат задачи в фоновом режиме. Итак, я решил это сейчас, переписав функцию. Вместо того, чтобы заполнять локальную переменную словаря, она заполняет глобальную. Это единственный способ узнать, как получить доступ к данным функции. Я просто хочу знать, есть ли другой способ сделать это, или если это единственный/лучший способ.
Надеюсь, что это лучше.
Извините, нажал ввод и не смог отредактировать во времени -.- « Я не использовал функцию OnPropertyChanged до сих пор. Это действительно полезно, если в моем словаре появились новые данные;) Но мой вопрос состоял в том, возвращаемое значение, работающее с командами (т. е. заставить его вести себя как задача?) Я имею в виду, что реализация полностью перегружена: возможно, я могу изменить какой-то код, чтобы это работало? Или это невозможно? Я просто не хочу моя функция для редактирования глобальной переменной, чтобы сделать ее повторно используемой для других программ. – syc
Почему вы не можете использовать функции с возвращаемыми значениями в команде? Просто отбросьте возвращаемое значение ... 'new Command (() => ThisMethodReturnsSomething()) ' – Haukinger
Но мне нужно возвращаемое значение, чтобы назначить его моей глобальной переменной , Я просто хочу сделать его многоразовым.Если я использую функцию без возврата, она ничего не делает, потому что то, что я возвращаю, также является тем, что я создал/отредактировал. Я не хочу, чтобы мой метод был изменен только для использования его в качестве команды. – syc