C# Событие происходит много раз - PullRequest
1 голос
/ 10 января 2020

У меня проблема. Я использую CollectionView, который получает данные в пользовательском ViewModel с моей веб-страницы, если он возвращает JSON с данными. Как только Offset в вызове> = num_of_rows, веб-страница печатает "Nothing". Если это произойдет, я установлю логическое значение HitBottomOfList = true;. Теперь каждый раз, когда он хочет сделать веб-звонок, он проверяет, если HitBottomOfList == false.

Полный код

ViewModel:

public class TemplateListViewModel
{
    public double WidthHeight { get; set; }

    public ICommand LoadTemplates => new Command(LoadTemplateList);
    public int CurrentTemplateCountReceived;
    public bool HitBottomOfList = false;
    public ObservableCollection<TemplateSource> sourceList { get; set; }


    public TemplateListViewModel()
    {
        CurrentTemplateCountReceived = 0;
        sourceList = new ObservableCollection<TemplateSource>();

        var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
        var width = mainDisplayInfo.Width;
        var density = mainDisplayInfo.Density;
        var ScaledWidth = width / density;

        WidthHeight = (ScaledWidth / 2);

        loadingTemplates += onLoadingTemplates;
        LoadTemplateList();
    }

    private event EventHandler loadingTemplates = delegate { };

    private void LoadTemplateList()
    {
        loadingTemplates(this, EventArgs.Empty);
    }

    private async void onLoadingTemplates(object sender, EventArgs args)
    {
        if (HitBottomOfList == false)
        {
            List<Template> templateList = await App.RestService.GetTemplates(App.User, CurrentTemplateCountReceived);

            if (templateList != null)
            {
                foreach (var template in templateList)
                {
                    ImageSource source = ImageSource.FromUri(new Uri("mysite.org/myapp/" + template.FileName));
                    TemplateSource templateSource = new TemplateSource { Id = template.Id, Source = source, WidthHeight = WidthHeight, FileName = template.FileName };
                    sourceList.Add(templateSource);
                }

                CurrentTemplateCountReceived = sourceList.Count;
            }
            else
            {
                HitBottomOfList = true;
            }
        }
    }
}

XAML:

<CollectionView ItemsSource="{Binding sourceList}" RemainingItemsThreshold="6"
RemainingItemsThresholdReachedCommand="{Binding LoadTemplates}">
    <CollectionView.ItemsLayout>
        <GridItemsLayout Orientation="Vertical"
    Span="2" />
    </CollectionView.ItemsLayout>
    <CollectionView.ItemTemplate>
        <DataTemplate>

            <ff:CachedImage
    Source="{Binding Source}"
    VerticalOptions="Center"
    HorizontalOptions="Center"
    WidthRequest="{Binding WidthHeight}"
    HeightRequest="{Binding WidthHeight}">
                <ff:CachedImage.GestureRecognizers>
                    <TapGestureRecognizer Tapped="imgTemplate_Clicked" />
                </ff:CachedImage.GestureRecognizers>
            </ff:CachedImage>

        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

И, наконец, WebCall, который я делаю:

public async Task<List<Template>> GetTemplates(User user, int offset)
{
    var postData = new List<KeyValuePair<string, string>>();
    postData.Add(new KeyValuePair<string, string>("un", user.Username));
    postData.Add(new KeyValuePair<string, string>("pw", user.Password));
    postData.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
    var content = new FormUrlEncodedContent(postData);
    var weburl = "mysite.org/myapp/get_templates.php";
    List<Template> response = await PostResponseTemplates(weburl, content);

    return response;
}

public async Task<List<Template>> PostResponseTemplates(string weburl, FormUrlEncodedContent content)
{
    var response = await client.PostAsync(weburl, content);
    var json = await response.Content.ReadAsStringAsync();

    if (json != "Nothing")
    {
        var jObject = JObject.Parse(json);
        var templatePropery = jObject["Templates"] as JArray;
        List<Template> templateList = new List<Template>();

        foreach (var property in templatePropery)
        {
            List<Template> propertyList = new List<Template>();
            propertyList = JsonConvert.DeserializeObject<List<Template>>(property.ToString());
            templateList.AddRange(propertyList);
        }

        var sourcePropery = (JObject)jObject["Source"];
        foreach (var property in sourcePropery)
        {
            string tempplateSource = property.Value.Value<string>();
            App.TemplateSource = tempplateSource;
        }

        return templateList;
    }
    else
    {
        ErrorMessage = json;
        return default(List<Template>);
    }
}

Теперь проблема в том, что когда он запускает RemainingItemsThresholdReachedCommand="{Binding LoadTemplates}", он выполняет команду много раз друг за другом, думая, что ему нужно больше данные, при этом уже есть команда для получения новых данных. Это приводит к тому, что приложение получает новые данные с одним и тем же offset несколько раз, поэтому приложение будет многократно повторять одни и те же данные в CollectionView.

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

Обновление

Используя @Jason его код, происходит следующее: Когда код проходит через MyHandler, он запускает LoadTemplateList();, но переходит на handling = false; до его завершения, поэтому разрешается запуск следующей команды без завершения другой. Есть идеи как дождаться окончания метода до sh?

1 Ответ

0 голосов
/ 10 января 2020

используйте bool для отслеживания, если вы уже обрабатываете событие, и игнорируйте все новые

bool handling = false;

public void MyHandler()
{
  // already handling an event, ignore the new one
  if (handling) return;

  handling = true;

  // process event here

  handling = false;
}
...