简体   繁体   English

绑定到 ObsevableCollection 在 WINUI3 应用程序中不起作用

[英]Bind to ObsevableCollection not working in WINUI3 app

I am building a semi automatic administration platform to keep track of my daytrading.我正在构建一个半自动管理平台来跟踪我的日间交易。 With a python script I can get information out of the platform and through a pipe it gets to the app who passes it into a SQLite database.使用 python 脚本,我可以从平台获取信息,并通过管道将信息传递给应用程序,该应用程序将其传递到SQLite数据库。

Now I'm working on getting the data out of the database and into the GUI of the application.现在我正在将数据从数据库中取出并放入应用程序的 GUI 中。 Now, all 3 of the methods run on a Task thread as the pipe server is using a infinite while loop as well as the method that gets the data from the database.现在,所有 3 个方法都在Task线程上运行,因为管道服务器正在使用无限 while 循环以及从数据库获取数据的方法。 As the data is changing every 2 seconds it has to update the data in the GUI as well.由于数据每 2 秒更改一次,因此它也必须更新 GUI 中的数据。

Binding from the xaml to the model is not working as the method is running on a different thread.从 xaml 绑定到模型不起作用,因为该方法在不同的线程上运行。 This is where I'm stuck.这就是我卡住的地方。

The code is as follows,代码如下,

The first methods of the page are the ObservableCollection and the initialization which starts the Task methods with Task.Run();页面的第一个方法是ObservableCollection和使用Task.Run();启动Task方法的初始化; as well as the PropertyChanged method.以及PropertyChanged方法。

        private ObservableCollection<OpenTradesModel> _trades = new ObservableCollection<OpenTradesModel>();
        public ObservableCollection<OpenTradesModel> Trades
        {
            get { return _trades; }
            set { _trades = value; OnPropertyChanged(nameof(Trades)); Debug.Print("Property Changed!"); }
        }
        
        public OpenTradesView()
        {
            InitializeComponent();
            List<Task> tasks = new()
            {
                Task.Run(() => { startServerAndUseData(); }),
                Task.Run(() => { runScript(); }),
                Task.Run(() => { DataBaseQueryToGUI(); }),
            };
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

The following method gets the data from the SQLite database and puts it into _trades .以下方法从SQLite数据库中获取数据并将其放入_trades中。

public Task DataBaseQueryToGUI()
        {
            while (true)
            {
                try
                {
                    using var db = new DatabaseContext();
                    var rowData = db.OpenTrades.OrderBy(x => x.Id).ToList();

                    foreach (var row in rowData)
                    {
                        var query = new OpenTradesModel()
                        {
                            Ticket = row.Ticket,
                            Time = row.Time,
                            Type = row.Type,
                            Magic = row.Magic,
                            Identifier = row.Identifier,
                            Reason = row.Reason,
                            Volume = row.Volume,
                            PriceOpen = row.PriceOpen,
                            StopLoss = row.StopLoss,
                            TakeProfit = row.TakeProfit,
                            CurrentPrice = row.CurrentPrice,
                            Swap = row.Swap,
                            Profit = row.Profit,
                            Symbol = row.Symbol,
                        };
                        _trades.Add(query); //This is where the exception is thrown.
                        Debug.Print("Added to Model!");
                    }
                }
                catch (Exception e)
                {
                    Debug.Print(e.ToString());
                    break;
                }
               Thread.Sleep(2000);
            }
            return Task.CompletedTask;
        }

The xaml is as follows. xaml如下。

<ListView x:Name="ListData" MaxWidth="1496" Width="1496" Height="457" MaxHeight="457"
                          ItemsSource="{x:Bind Trades, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

                    <ListViewHeaderItem Margin="-11,0,0,0">
                        ...
                    </ListViewHeaderItem>

                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <Expander>
                                <Expander.Header>
                                    <Grid>
                                        <Grid.ColumnDefinitions>
                                            ...
                                        </Grid.ColumnDefinitions>

                                        <TextBlock Grid.Column="0"  Text="{Binding Trades}"/>
                                        <TextBlock Grid.Column="1"  Text="{Binding Time}" Margin="-17,0,0,0"/>
                                        <TextBlock Grid.Column="2"  Text="{Binding Type}"/>
                                        <TextBlock Grid.Column="3"  Text="{Binding Magic}"/>
                                        <TextBlock Grid.Column="4"  Text="{Binding Identifier}"/>
                                        <TextBlock Grid.Column="5"  Text="{Binding Reason}"/>
                                        <TextBlock Grid.Column="6"  Text="{Binding Volume}"/>
                                        <TextBlock Grid.Column="7"  Text="{Binding PriceOpen}"/>
                                        <TextBlock Grid.Column="8"  Text="{Binding StopLoss}"/>
                                        <TextBlock Grid.Column="9"  Text="{Binding TakeProfit}"/>
                                        <TextBlock Grid.Column="10" Text="{Binding CurrentPrice}"/>
                                        <TextBlock Grid.Column="11" Text="{Binding Swap}" Margin="-15,0,0,0"/>
                                        <TextBlock Grid.Column="12" Text="{Binding Profit}" Margin="15,0,0,0"/>
                                        <TextBlock Grid.Column="13" Text="{Binding Symbol}"/>
                                    </Grid>
                                </Expander.Header>

The binding seems to work but does not show the data that is put into _trades .绑定似乎有效,但没有显示放入_trades的数据。 As the following exception shows it has to do with threading, I just have no idea how to get the data to the UI thread.正如以下异常表明它与线程有关,我只是不知道如何将数据获取到 UI 线程。 Every answer I've found here didn't work for me.我在这里找到的每个答案都不适合我。

System.Runtime.InteropServices.COMException (0x8001010E): The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))
   at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|20_0(Int32 hr)
   at WinRT.ExceptionHelpers.ThrowExceptionForHR(Int32 hr)
   at ABI.Microsoft.UI.Xaml.Interop.WinRTNotifyCollectionChangedEventArgsRuntimeClassFactory.CreateInstanceWithAllParameters(NotifyCollectionChangedAction action, IList newItems, IList oldItems, Int32 newIndex, Int32 oldIndex)
   at ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs.CreateMarshaler2(NotifyCollectionChangedEventArgs value)
   at ABI.System.Collections.Specialized.NotifyCollectionChangedEventHandler.NativeDelegateWrapper.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.InsertItem(Int32 index, T item)
   at System.Collections.ObjectModel.Collection`1.Add(T item)
   at TradeAdministration.Views.OpenTradesView.DataBaseQueryToGUI() in C:\Users\Nick\source\repos\TradeAdministration\TradeAdministration\Views\OpenTradesView.xaml.cs:line 96

Hopefully one of you can get me on the right track of thought.希望你们中的一个能让我走上正确的思路。 Thanks in advance!提前致谢!

I fixed it by changing the DataBaseQueryToGUI() function as follows:我通过更改DataBaseQueryToGUI()函数来修复它,如下所示:

private async void DataBaseQueryToGUI() // Made it an async method.
        {
            await Task.Run(() => // Added
            { 
                while (true)
                {
                    try
                    {
                        using var db = new DatabaseContext();
                        var rowData = db.OpenTrades.OrderBy(x => x.Id).ToList();

                        foreach (var row in rowData)
                        {
                            var query = new OpenTradesModel()
                            {
                                Ticket = row.Ticket,
                                Time = row.Time,
                                Type = row.Type,
                                Magic = row.Magic,
                                Identifier = row.Identifier,
                                Reason = row.Reason,
                                Volume = row.Volume,
                                PriceOpen = row.PriceOpen,
                                StopLoss = row.StopLoss,
                                TakeProfit = row.TakeProfit,
                                CurrentPrice = row.CurrentPrice,
                                Swap = row.Swap,
                                Profit = row.Profit,
                                Symbol = row.Symbol,
                            };
                            this.DispatcherQueue.TryEnqueue(() => // Pushed these to the Dispatcher.
                            {
                                _trades.Add(query);
                                Debug.Print("Added to Model!");
                            });
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.Print(e.ToString());
                        break;
                    }
                    Thread.Sleep(2000);
                }
            });
        }

This works for now.这暂时有效。 Although I am missing some data but that's fixable.虽然我遗漏了一些数据,但这是可以修复的。 Now I need to figure out a way to update the data instead of adding the new data.现在我需要想办法更新数据而不是添加新数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM