我正在实现读取文件,并更新WPF中ListView
的项目源。但是我对UI线程有问题。让我看看显示问题的GIF。
如您所见,我在动画进度方面遇到问题。 (由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是结果。
如您所见,动画没有问题。我虽然做得很好。但是几分钟后,我变得很尴尬。因为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#源代码。首先,我创建本地集合bb
。 (不要怪我为XD命名变量)。要更新视图中的列表计数,我需要添加新属性OriginGamesCnt
,ExceptGamesCnt
。我尝试更新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;
}
}
}