Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 通过大量数据的可观察收集批量更新UI组件WinRT_C#_User Interface_Event Handling_Windows Runtime_Dispatcher - Fatal编程技术网

C# 通过大量数据的可观察收集批量更新UI组件WinRT

C# 通过大量数据的可观察收集批量更新UI组件WinRT,c#,user-interface,event-handling,windows-runtime,dispatcher,C#,User Interface,Event Handling,Windows Runtime,Dispatcher,我有一个WinRT应用程序,每次从设备接收数据时都会发出通知。我还有一个UI控件,它与我希望添加新数据的可观察集合进行数据绑定 虽然我已经使它能够更新可观察的集合,但它会导致UI变得非常滞后,因为生成的数据量很快。因此,最好是批量更新,可能每几百毫秒更新一次 下面显示了代码片段。首先,我创建周期计时器 TimerElapsedHandler f = new TimerElapsedHandler(batchUpdate); CreatePeriodicTimer(f, new

我有一个WinRT应用程序,每次从设备接收数据时都会发出通知。我还有一个UI控件,它与我希望添加新数据的可观察集合进行数据绑定

虽然我已经使它能够更新可观察的集合,但它会导致UI变得非常滞后,因为生成的数据量很快。因此,最好是批量更新,可能每几百毫秒更新一次

下面显示了代码片段。首先,我创建周期计时器

 TimerElapsedHandler f = new TimerElapsedHandler(batchUpdate);
        CreatePeriodicTimer(f, new TimeSpan(0, 0, 3));
下面是我的事件处理程序,用于处理新数据的输入,以及存储信息的临时列表

List<FinancialStuff> lst = new List<FinancialStuff>();
    async void myData_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
    {
        var data = new byte[args.CharacteristicValue.Length];
        DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);
        lst.Add(new FinancialStuff() { Time = "DateTime.UtcNow.ToString("mm:ss.ffffff")", Amount = data[0] });

    }
List lst=new List();
异步无效myData_值已更改(GattCharacteristic发送方,GattValueChangedEventArgs args)
{
变量数据=新字节[args.CharacteristicValue.Length];
DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(数据);
lst.Add(newfinancialstuff(){Time=“DateTime.UtcNow.ToString”(“mm:ss.ffffff”)”,Amount=data[0]});
}
然后我的批处理更新,称为perioidly

    private void batchUpdate(ThreadPoolTimer source)
    {

            AddItem<FinancialStuff>(financialStuffList, lst);                        

    }
private void批处理更新(ThreadPoolTimer源)
{
AddItem(财务列表,lst);
}
最后,为了进行测试,我想清除可观察的集合和项目

    public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
    {

        lock (items)
        {

            if (Dispatcher.HasThreadAccess)
            {
                foreach (T item in items)
                    oc.Add(item);

            }
            else
            {
                Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
                {

                    oc.Clear();
                    for (int i = 0; i < items.Count; i++)
                    {
                        items.Count());
                        oc.Add(items[i]);
                    }
                    lst.Clear();

                });
            }
        }

    }
public async void AddItem(observeCollection oc,列表项)
{
锁(项目)
{
if(Dispatcher.HasThreadAccess)
{
foreach(项目中的T项目)
oc.添加(项目);
}
其他的
{
Dispatcher.RunAsync(CoreDispatcherPriority.Low,()=>
{
oc.Clear();
对于(int i=0;i
虽然这似乎是可行的,但在几次更新之后,UI会锁定,并且更新非常缓慢/如果没有的话。对于测试,在计时器启动时,它只会在列表中获得几百项

有人能告诉我为什么会发生这种情况吗?我想我的设计很差


谢谢

您没有在事件处理程序中锁定列表

// "lst" is never locked in your event handler
List<FinancialStuff> lst = new List<FinancialStuff>();
lst.Add(new FinancialStuff() { Time = "DateTime.UtcNow.ToString("mm:ss.ffffff")", Amount = data[0] });
EDIT2:
由于AddItem方法已经在后台线程上,我认为您不需要运行Dispatcher.RunAsync。相反,我认为最好是阻止它,这样就不会导致对该部分代码的多次调用。尝试使用Dispatcher。改为运行。我已经更新了上面的代码示例以显示更改。你不应该再需要oc上的锁了,因为物品上的锁已经足够好了。此外,请验证Dispatcher.Run的语法是否正确。

TTat的答案听起来似乎有道理。我只会建议使用即时模式渲染(如Direct2D)来进行高频数据可视化。你能提供更多关于这方面的信息吗?如果你可以使用C++ VisualStudio,它可以为DirectX、Direct2D和混合DirectX提供XAML的项目模板。描述如何在XAML应用程序中使用DirectX。如果你真的不想使用C++,你通常会使用在DirectX上面的一个管理包装器SARPDX。我加了锁,但没什么区别。用户界面很快就开始锁定,这肯定是图表导致了锁定。如果我删除绑定到observableCollection的图表,UI不会锁定idea。我认为您的意思是oc.Add(itemsToRender[I]),但无论哪种方式,对于大于20的值,它似乎都会很快锁定(它会锁定很长时间/不确定地锁定在30大小)。我不明白为什么这么慢!还有什么想法吗?老实说,我不太确定这里的语法是什么。如果我们想同步执行运行,那么我们可以在“await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,()=>”之前使用wait,但是在移除锁之后,它仍然非常慢。这就是您想要的吗?ThanksIt需要同步。对于同步和“BeginInvoke”,它应该是“Invoke”对于异步,但我认为您使用的是4.5版?只需键入Dispatcher.Run和intellisense就可以为您提供语法。
AddItem<FinancialStuff>(financialStuffList, lst);    
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
    // "lst" reference is locked here, but it wasn't locked in the event handler 
    lock (items)
    {
        if (Dispatcher.HasThreadAccess)
        {
            foreach (T item in items)
                oc.Add(item);
        }
        else
        {
            Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
            {
                oc.Clear();

                // This may never exit the for loop
                for (int i = 0; i < items.Count; i++)
                {
                    items.Count());
                    oc.Add(items[i]);
                }
                lst.Clear();
            });
        }
    }
}
public async void AddItem<T>(ObservableCollection<T> oc, List<T> items)
{
    // "lst" reference is locked here, but it wasn't locked in the event handler 
    lock (items)
    {
        // Change this to what you want
        const int maxSize = 100;

        // Make sure it doesn't index out of bounds
        int startIndex = Math.Max(0, items.Count - maxSize);
        int length = items.Count - startIndex;

        List<T> itemsToRender = items.GetRange(startIndex, length);

        // You can clear it here in your background thread.  The references to the objects
        // are now in the itemsToRender list.
        lst.Clear();

        // Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
        // Please verify this is the correct syntax
        Dispatcher.Run(() =>
        {
            // At second look, this might need to be locked too
            // EDIT: This probably will just add overhead now that it's not running async.
            // You can probably remove this lock
            lock(oc)
            {
                oc.Clear();

                for (int i = 0; i < itemsToRender.Count; i++)
                {
                    // I didn't notice it before, but why are you checking the count again?
                    // items.Count());
                    oc.Add(itemsToRender[i]);
                }
             }
        });
    }
}