C# 异步获取数据时WPF Datagrid选择问题
我有一个简单的数据网格C# 异步获取数据时WPF Datagrid选择问题,c#,wpf,datagrid,wpfdatagrid,C#,Wpf,Datagrid,Wpfdatagrid,我有一个简单的数据网格 <DataGrid x:Name="dgSample" ItemsSource="{Binding Items, IsAsync=True}" AutoGenerateColumns="False" SelectionMode="Single" CanUserAddRows="False" CanUserDeleteRows="False" SelectionUnit="FullRow"> <DataGrid.Co
<DataGrid x:Name="dgSample" ItemsSource="{Binding Items, IsAsync=True}" AutoGenerateColumns="False" SelectionMode="Single" CanUserAddRows="False" CanUserDeleteRows="False" SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" IsReadOnly="True"/>
<DataGridTextColumn Header="Date" Binding="{Binding Date}" IsReadOnly="True"/>
<DataGridTemplateColumn Header="Sent" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Sent}" IsEnabled="False" HorizontalAlignment="Center"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
我从Items对象填充此datagrid
代码隐藏:
public List<Item> Items { get; set;}
private async void GetData()
{
await Task.Run(() =>
{
GetItems();
});
}
private void GetItems()
{
Items = facade.GetItems();
}
公共列表项{get;set;}
私有异步void GetData()
{
等待任务。运行(()=>
{
GetItems();
});
}
私有void GetItems()
{
Items=facade.GetItems();
}
一切正常,我获取数据并异步填充datagrid。问题是当我想选择一行时,我不能。我点击一个单元格,选择就会自动消失
当我填充datagrid sync时,您需要使用的问题消失了,否则可能会死锁UI线程
这对我很有用(我用的是Prism):
使用Prism.Commands;
使用制度;
使用System.Collections.Generic;
使用Prism.Mvvm;
使用System.Collections.ObjectModel;
使用模型;
使用System.Threading.Tasks;
公共类ItemsViewModel:BindableBase
{
私人门面;
public ItemsViewModel()
{
facade=newmyfacade();
Items=新的ObservableCollection();
}
公共可观测集合项{get;private set;}
公共DelegateCommand GetDataCommand=>new DelegateCommand(GetData);
私有异步void GetData()
{
//包装异步void并使用异步任务是最佳实践
等待GetItems();
}
私有异步任务GetItems()
{
//不是真正异步的
var result=await facade.GetItems();
Items.Clear();
Items.AddRange(结果);
}
类MyFacade
{
公共异步任务GetItems()
{
//不是真正异步的
var items=新列表();
添加(新项{Name=“Joe”,Date=DateTime.Now});
添加(新项{Name=“Bob”,Date=DateTime.Now});
添加(新项{Name=“Sam”,Date=DateTime.Now});
退货项目;
}
}
}
视图:
您需要使用,否则可能会死锁UI线程
这对我很有用(我用的是Prism):
使用Prism.Commands;
使用制度;
使用System.Collections.Generic;
使用Prism.Mvvm;
使用System.Collections.ObjectModel;
使用模型;
使用System.Threading.Tasks;
公共类ItemsViewModel:BindableBase
{
私人门面;
public ItemsViewModel()
{
facade=newmyfacade();
Items=新的ObservableCollection();
}
公共可观测集合项{get;private set;}
公共DelegateCommand GetDataCommand=>new DelegateCommand(GetData);
私有异步void GetData()
{
//包装异步void并使用异步任务是最佳实践
等待GetItems();
}
私有异步任务GetItems()
{
//不是真正异步的
var result=await facade.GetItems();
Items.Clear();
Items.AddRange(结果);
}
类MyFacade
{
公共异步任务GetItems()
{
//不是真正异步的
var items=新列表();
添加(新项{Name=“Joe”,Date=DateTime.Now});
添加(新项{Name=“Bob”,Date=DateTime.Now});
添加(新项{Name=“Sam”,Date=DateTime.Now});
退货项目;
}
}
}
视图:
我不会使用列表
,通常您希望将可观察集合
绑定到项目资源
。您多久填充一次项
?您是按需还是定期?我按需填充项目。即使我使用ObservableCollection,问题仍然存在。另外,我实现了INotifyPropertyChanged,因此列表应该没有任何问题。我猜您可能会有另一个代码清除选择,因为您显示的代码看起来不错。您是否正在使用任何MVVM框架?当您说“当我填充datagrid sync时”,您的意思是加载异步项,还是从xaml中的绑定中删除IsAsync?出于测试目的,我创建了wpf窗口,所有绑定都是代码绑定(没有MVVM)。通过“填充datagrid sync”,我的意思是更改GetData()方法:private void GetData()不带async/wait,我不会使用列表
,通常您希望将可观察集合
绑定到项资源
。您多久填充一次项
?您是按需还是定期?我按需填充项目。即使我使用ObservableCollection,问题仍然存在。另外,我实现了INotifyPropertyChanged,因此列表应该没有任何问题。我猜您可能会有另一个代码清除选择,因为您显示的代码看起来不错。您是否正在使用任何MVVM框架?当您说“当我填充datagrid sync时”,您的意思是加载异步项,还是从xaml中的绑定中删除IsAsync?出于测试目的,我创建了wpf窗口,所有绑定都是代码绑定(没有MVVM)。通过“填充datagrid sync”,我的意思是更改GetData()方法:private void GetData(),而不使用async/await
using Prism.Commands;
using System;
using System.Collections.Generic;
using Prism.Mvvm;
using System.Collections.ObjectModel;
using Models;
using System.Threading.Tasks;
public class ItemsViewModel : BindableBase
{
private MyFacade facade;
public ItemsViewModel()
{
facade = new MyFacade();
Items = new ObservableCollection<Item>();
}
public ObservableCollection<Item> Items { get; private set; }
public DelegateCommand GetDataCommand => new DelegateCommand(GetData);
private async void GetData()
{
// it's the best practice to wrap an async void and use an async Task
await GetItems();
}
private async Task GetItems()
{
// not really async
var result = await facade.GetItems();
Items.Clear();
Items.AddRange(result);
}
class MyFacade
{
public async Task<List<Item>> GetItems()
{
// not really async
var items = new List<Item>();
items.Add(new Item { Name = "Joe", Date = DateTime.Now });
items.Add(new Item { Name = "Bob", Date = DateTime.Now });
items.Add(new Item { Name = "Sam", Date = DateTime.Now });
return items;
}
}
}
<UserControl x:Class="DataGridPopulatedAsync.Views.ItemsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<StackPanel>
<Button Command="{Binding GetDataCommand}" Content="Get Data" />
<DataGrid ItemsSource="{Binding Items}" />
</StackPanel>
</UserControl>