Запустить действие, начинающееся после X миллисекунд

Я разрабатываю мобильное приложение Xamarin Forms, на котором есть страница, содержащая элементы управления SearchBar, ListView и Map. В представлении списка содержится список адресов, которые отображаются в виде контактов на карте.

Когда пользователь вводит в SearchBar, ListView автоматически обновляется (посредством привязки ViewModel). Метод ViewModel, который фильтрует источник данных для списка, выглядит примерно так:

void FilterList()
{
    listDataSource = new ObservableCollection<location>(
        locationData.Where(l => l.Address.Contains(searchBar.Text))
    );

    // ***** Now, update the map pins using the data in listDataSource
}

Я хочу обновить карту, поскольку ListView фильтруется, но не на КАЖДОМ нажатии, поскольку это может происходить несколько раз в секунду. По сути, я хочу, чтобы "календарная пауза" в каждом событии FilterList до обновления Карты. В псевдокоде...

    // ***** Now, update the map pins using the data in listDataSource
    if (a previously-requested map update is pending)
    {
        // Cancel the pending map update request
    }

    // Request a new map update in 1000ms using [listDataSource]

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

Может ли кто-нибудь предложить "умнее" совместимый с PCL способ сделать это?

Ответ 1

вы можете попробовать:

await Task.Delay(2000);

Ответ 2

Так же, как вы сказали, это можно сделать очень простым способом, используя Tasks и асинхронное программирование.

Вы хотите прочитать об этом: http://msdn.microsoft.com/en-us/library/hh191443.aspx

Вот пример:

public async Task DelayActionAsync(int delay, Action action) 
{
    await Task.Delay(delay);

    action();
}

Ответ 3

Вот что я сделал, и он работает в моих приложениях Xamarin Form.

    public string Search
    {
        get { return _search; }
        set
        {
            if (_search == value)
                return;

            _search = value;
            triggerSearch = false;
            Task.Run(async () =>
            {
                string searchText = _search;
                await Task.Delay(2000);
                if (_search == searchText)
                {
                    await ActionToFilter();
                }
            });
        }
    }

У меня есть свойство "Поиск", привязанное к полю ввода. Всякий раз, когда пользователь что-то фильтрует, код ждет 1 секунду, а затем сравнивает новое текстовое поле с полем, которое было раньше 1 секунды. Если предположить, что строка равна, это означает, что пользователь перестает вводить текст, и теперь код может быть запущен для фильтрации.

Ответ 4

Проблема с простыми задержками состоит в том, что вы можете получить кучу событий в очереди, когда истечет время задержки. Вы можете добавить логику, чтобы отбрасывать события, которые возникли во время задержки. Если вы хотите объявить логику на более высоком уровне, вы можете использовать Reactive Extensions.

Ответ 5

Работа в последней версии xamarin.

Еще один отличный способ при нажатии кнопки,

    public async void OnButtonClickHandler(Object sender, EventArgs e)
{
    try
    {
        //ShowProgresBar("Loading...");

        await Task.Run(() =>
        {
            Task.Delay(2000); //wait for two milli seconds

            //TODO Your Business logic goes here
            //HideProgressBar();

        });

        await DisplayAlert("Title", "Delayed for two seconds", "Okay");

    }
    catch (Exception ex)
    {

    }
}

async и await ключи важны, предположим, что вы работаете в многопоточной среде.

Ответ 6

Есть еще один способ:

new Handler().PostDelayed(() =>
{
    // hey, I'll run after 1000 ms
}, 1000);

Конечно, вы также можете использовать следующую версию:

var handler = new Handler();
var action = () => 
{
    // hey, I'll run after 1000 ms
};

handler.PostDelayed(action, 1000);