我在 StackOverFlow 中看到了很多问题,但他们没有在 Dispatcher 中出现此错误
我正在公司升级一个Wpf应用程序,他们给了我一个任务,让UI上的游戏列表变得更快。
应用程序设计模式是mvvm。
我开发了 2 个部分。
第 1 节:从数据库中获取游戏 第 2 部分:PC 上的常规搜索。
在此之前:仅常规搜索。
这是我的代码:
public async Task FindGameInBackground()
{
await App.Current.Dispatcher.BeginInvoke(HandleLaunchersAndGames); // Problem Here
await App.Current.Dispatcher.InvokeAsync(() => Games = new (Games.OrderBy(x => x.Name)));
GamesView = CollectionViewSource.GetDefaultView(Games);
...
}
HandleLaunchersAndGames 没问题,但它是在填充数据后调用 AddGame 方法
private Task AddGame(Game gameModel)
{
var lGameModel = gameModel;
if (!Games.Any(x => x.Name.Equals(lGameModel.Name)) ||
!Games.Any(x => x.AId.Equals(lGameModel.AId)) ||
Games.Where(x => x.Name.Equals(lGameModel.Name))
.All(x => x.LauncherName != lGameModel.LauncherName))
{
bool threadAccess = App.Current.Dispatcher.Thread == Thread.CurrentThread;
if (threadAccess)
{
Games.Add(lGameModel); // **I Get The Error Here.**
}
App.Current.Dispatcher.Invoke(() => Games.Add(lGameModel));
}
return Task.CompletedTask;
}
游戏类型:
public ObservableCollection<Game> Games
{
get => _games ??= new ObservableCollection<Game>();
set
{
_games = value;
OnPropertyChanged();
}
}
并且它在 UI 中绑定
我不知道为什么会收到此错误,我正在使用 Dispatcher 和 Invoke 在 AddGame 中,我正在检查线程访问,但添加对象后出现错误
您没有提供为您提供准确建议所需的所有详细信息。
因此,我将展示其中一种可能选项的一些抽象实现。
using Simplified;
using System.Collections;
using System.Collections.ObjectModel;
using System.Threading;
using System.Threading.Tasks;
namespace Core2023.SO.HosseinSanjabian.Question77697304
{
public record Game(string Name, int AId, string LauncherName)
{
public Game() : this(string.Empty, 0, string.Empty) { }
public override string ToString() => $"{AId}: {Name} ({LauncherName})";
}
public class GamesViewModel
{
public ReadOnlyObservableCollection<Game> Games { get; }
private readonly ObservableCollection<Game> privateGames = new();
private void AddGame(Game gameModel)
{
Thread.Sleep(5000); // Emulating some kind of delay in the execution method
lock (((ICollection)privateGames).SyncRoot)
privateGames.Add(gameModel);
}
private async Task AddGameAsync(Game gameModel)
{
await Task.Run(() => AddGame(gameModel));
}
public RelayCommand<Game> AddGameCommand { get; }
public GamesViewModel()
{
Games = new(privateGames);
AddGameCommand = new(async game => await AddGameAsync(game));
}
}
}
<Window x:Class="Core2023.SO.HosseinSanjabian.Question77697304.GamesWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Core2023.SO.HosseinSanjabian.Question77697304"
xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
mc:Ignorable="d"
Title="GamesWindow" Height="450" Width="800"
DataContext="{DynamicResource vm}">
<FrameworkElement.Resources>
<local:GamesViewModel x:Key="vm"/>
<CollectionViewSource x:Key="games" Source="{Binding Games}">
<CollectionViewSource.SortDescriptions>
<cm:SortDescription PropertyName="Name"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<local:Game x:Key="addidingGame"/>
</FrameworkElement.Resources>
<UniformGrid Rows="1">
<DataGrid ItemsSource="{Binding Source={StaticResource games}}"/>
<UniformGrid Columns="1">
<UniformGrid Columns="2" DataContext="{DynamicResource addidingGame}">
<TextBlock Text="AID:"/>
<TextBox Text="{Binding AId}"/>
<TextBlock Text="Name:"/>
<TextBox Text="{Binding Name}"/>
<TextBlock Text="LauncherName:"/>
<TextBox Text="{Binding LauncherName}"/>
</UniformGrid>
<Button Content="Add Game"
Command="{Binding AddGameCommand}"
CommandParameter="{DynamicResource addidingGame}"
Click="OnAddidingGame"/>
</UniformGrid>
</UniformGrid>
</Window>
using System.Collections;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
namespace Core2023.SO.HosseinSanjabian.Question77697304
{
public partial class GamesWindow : Window
{
public GamesWindow()
{
InitializeComponent();
GamesViewModel viewModel = (GamesViewModel) FindResource("vm");
ICollection games = viewModel.Games;
BindingOperations.EnableCollectionSynchronization(games, games.SyncRoot);
}
private async void OnAddidingGame(object sender, RoutedEventArgs e)
{
await Task.Delay(100);
Resources["addidingGame"] = new Game();
}
}
}