从Task更新ViewModel属性,但是在WPF中确实很慢

问题描述 投票:0回答:1

我正在实现读取文件,并更新WPFListView的项目源。但是我对UI线程有问题。让我看看显示问题的GIF。

enter image description here

如您所见,我在动画进度方面遇到问题。 (由MaterialDesignTheme支持)最好不要显示列表视图的任何更新项目,也不要显示进度动画,但是动画的质量较低。以下源代码是视图模型的一部分。

private ObservableCollection<List<int>> originGames;
public ObservableCollection<List<int>> OriginGames
{
    get { return originGames; }
    set { SetProperty(ref originGames, value); }
}
private bool JobOnWork;
public bool BJobOnWork
{
    get { return JobOnWork; }
    set { SetProperty(ref JobOnWork, value); }
}
private async void OnFileOpenOriginGame()
{

    OpenFileDialog dlg = new OpenFileDialog();
    dlg.DefaultExt = ".txt";
    dlg.Filter = "텍스트 파일 (*.txt)|*txt";

    // when Open Dlg
    if (dlg.ShowDialog() == true)
    {
        BJobOnWork = true;
        OriginGames = new ObservableCollection<List<int>>();

        using (StreamReader sr = new StreamReader(dlg.FileName))
        {
            while (!sr.EndOfStream)
            {
                string oneline = await sr.ReadLineAsync();
                string[] values = oneline.Split(' ');

                List<int> temp = new List<int>();

                for (int i = 0; i < 6; i++)
                {
                    int valueint = -1;
                    bool safe = int.TryParse(values[i], out valueint);
                    temp.Add(valueint);
                }

                OriginGames.Add(temp);
            }
        }
        BJobOnWork = false;
    }
}

您可能想知道什么是BJobOnWork属性。它只是动画的绑定属性。以下xaml源代码显示了BJobOnWork属性的工作方式。

<Button
    Width="100"
    Margin="0,30,0,0"
    HorizontalAlignment="Center"
    VerticalAlignment="Top"
    materialDesign:ButtonProgressAssist.IsIndeterminate="True"
    materialDesign:ButtonProgressAssist.IsIndicatorVisible="{Binding BJobOnWork}"
    materialDesign:ButtonProgressAssist.Value="-1"
    Command="{Binding CFileOpenOriginGame}"
    Foreground="White"
    Style="{StaticResource MaterialDesignRaisedLightButton}"
    ToolTip="원본 입력">
    _원본 입력
</Button>

为了获得流畅的动画,我以为我可以移动操作(读取数据和更新属性),所以我用C#Task做到了。因此,我实现了它,下面的gif是结果。

enter image description here

如您所见,动画没有问题。我虽然做得很好。但是几分钟后,我变得很尴尬。因为1-2分钟后作业没有结束。大约需要3到5分钟。我不知道如何解决这种情况。在我看来,这是折衷的事情。

以下是我的C#源代码。

await Task.Run(async () =>
{
    using (StreamReader sr = new StreamReader(dlg.FileName))
    {
        while (!sr.EndOfStream)
        {
            string oneLine = await sr.ReadLineAsync();
            string[] values = oneLine.Split(' ');

            List<int> temp = new List<int>();

            for (int i = 0; i < 6; i++)
            {
                int valueInt = -1;
                bool safe = int.TryParse(values[i], out valueInt);
                temp.Add(valueInt);
            }

            App.Current.Dispatcher.BeginInvoke((Action)(() =>
            {
                OriginGames.Add(temp);
            }), DispatcherPriority.Normal);
        }
    }
});

我希望对此有更好的解决方案,但是如果我别无选择,那么我将选择第一个解决方案。有没有什么方法可以快速实现良好的UI线程和良好的后台工作?谢谢阅读。

c# wpf
1个回答
0
投票

从疯狂那里得到答案后,我就用这种方式实施。

  1. 不更新每个循环中绑定的属性。
  2. 如果要更新绑定的某些属性,请创建计时器并通过它来实现它。

以下gif显示了我的成就。enter image description here

以下源代码是c#源代码。首先,我创建本地集合bb。 (不要怪我为XD命名变量)。要更新视图中的列表计数,我需要添加新属性OriginGamesCntExceptGamesCnt。我尝试更新OriginGames中的ObservableCollection DispatcherTimer,但它也会产生延迟,并且需要lock关键字才能使用bb Collection进行线程安全。

所以下面的源代码是我最终的解决方案源代码。

private async void OnFileOpenOriginGame(string param)
{

    OpenFileDialog dlg = new OpenFileDialog();
    dlg.DefaultExt = ".txt";
    dlg.Filter = "텍스트 파일 (*.txt)|*txt";

    ObservableCollection<List<int>> bb = new ObservableCollection<List<int>>();
    // when Open Dlg
    if (dlg.ShowDialog() == true)
    {
        if (param.Equals("Origin"))
        {
            BJobOnWorkOriginBtn = true;
            OriginGames = new ObservableCollection<List<int>>();
        }
        else if ( param.Equals("Erase"))
        {
            BJobOnWorkExceptBtn = true;
            ExceptGames = new ObservableCollection<List<int>>();
        }

        DispatcherTimer dt= new DispatcherTimer();
        dt.Interval = new TimeSpan(0, 0, 0, 0, 500);
        dt.Tick += (s, e) =>
        {
            App.Current.Dispatcher.BeginInvoke((Action)(() =>
            {
                if (param.Equals("Origin")) OriginGamesCnt = bb.Count;
                else ExceptGamesCnt = bb.Count;
            }), DispatcherPriority.Background);

        };

        dt.Start();

        await Task.Run(async () =>
        {
            using (StreamReader sr = new StreamReader(dlg.FileName))
            {
                while (!sr.EndOfStream)
                {
                    string oneLine = await sr.ReadLineAsync();
                    string[] values = oneLine.Split(' ');

                    List<int> temp = new List<int>();

                    for (int i = 0; i < 6; i++)
                    {
                        int valueInt = -1;
                        bool safe = int.TryParse(values[i], out valueInt);
                        temp.Add(valueInt);
                    }

                    bb.Add(temp);
                }
            }
        });
        dt.Stop();

        if (param.Equals("Origin")) BJobOnWorkOriginBtn = false;
        else BJobOnWorkExceptBtn = false;

        if (param.Equals("Origin"))
        {
            OriginGames = bb;
            OriginGamesCnt = bb.Count;
        }
        else
        {
            ExceptGames = bb;
            ExceptGamesCnt = bb.Count;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.