我目前对我的C#WPF GUI体验感到绝望。 我是WPF和Data-Binding的新手,也是我没有C#专家...
我尝试了基本MVVM WPF模式的演示模板: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx
...并添加〜2000客户检查巨大数据列表上的gui行为,因为我必须处理个人项目中的大量复杂数据。
由于Customer-List的显示发生在WPF-Data-Binding-Magic中,我不确定如何控制GUI加载时间(使用+2000数据最多12秒)。
CustomerRepository:
readonly List<Customer> _customers;
/// <summary>
/// Returns a shallow-copied list of all customers in the repository.
/// </summary>
public List<Customer> GetCustomers()
{
return new List<Customer>(_customers);
}
AllCustomerView.xaml / Listview,其中包含客户列表:
<ListView
AlternationCount="2"
DataContext="{StaticResource CustomerGroups}"
ItemContainerStyle="{StaticResource CustomerItemStyle}"
ItemsSource="{Binding}"
>
<ListView.GroupStyle>
<StaticResourceExtension
ResourceKey="CustomerGroupStyle"
/>
</ListView.GroupStyle>
<ListView.View>
<GridView>
<GridViewColumn
Header="Name"
DisplayMemberBinding="{Binding Path=DisplayName}"
/>
<GridViewColumn
Header="E-mail"
DisplayMemberBinding="{Binding Path=Email}"
/>
<GridViewColumn Header="Total Sales">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentPresenter
Content="{Binding Path=TotalSales}"
ContentStringFormat="c"
HorizontalAlignment="Right"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<UserControl.Resources>
<CollectionViewSource
x:Key="CustomerGroups"
Source="{Binding Path=AllCustomers}"
>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="IsCompany" />
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<!--
Sort descending by IsCompany so that the 'True' values appear first,
which means that companies will always be listed before people.
-->
<scm:SortDescription PropertyName="IsCompany" Direction="Descending" />
<scm:SortDescription PropertyName="DisplayName" Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
我的问题是:
有没有办法可以同步。在列表视图加载时加载数据而不冻结gui?
有没有什么方法可以跟踪进度,甚至可以获得已显示数据的进度,直到所有项目都正确加载?
另外:我正在使用GetCustomers()方法和XAML-Bindings之间的数据绑定。这两方之间的“真正联系”在哪里?
答案 0 :(得分:0)
以下简化示例使用异步LoadCustomers
方法将ListView绑定到视图模型。
Customer
实例在单独的线程中创建(通过Task.Run()
),并通过Dispatcher
调用添加到ObservableCollection中(因为只能在UI线程中修改集合)。
LoadCustomers在Window的Loaded
事件处理程序中执行,因为它必须是await
ed,这在MainWindow构造函数中无法完成。
<ListView ItemsSource="{Binding Customers}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}"/>
</GridView>
</ListView.View>
</ListView>
代码背后:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var viewModel = new ViewModel();
DataContext = viewModel;
Loaded += async (s, e) => await viewModel.LoadCustomers();
}
}
public class Customer
{
public string Name { get; set; }
}
public class ViewModel
{
public ObservableCollection<Customer> Customers { get; private set; }
= new ObservableCollection<Customer>();
public async Task LoadCustomers()
{
await Task.Run(() =>
{
for (int i = 0; i < 2000; i++)
{
var customer = new Customer
{
Name = string.Format("Customer {0}", i + 1)
};
Application.Current.Dispatcher.Invoke(() => Customers.Add(customer));
}
});
}
}
答案 1 :(得分:0)
我会这样做
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
...
LoadCostumersAsync(); //code after this line executes before LoadCostumersAsync() is finished, so your UI remains responsive
...
}
private ObservableCollection<Customer> _customers;
public ObservableCollection<Customer> Customers { get { return _customers; } }
private async void LoadStopsAsync()
{
IsLoading= true; // you can use this property to show a busyindicator on the UI
_customers = await LoadCostumers;
IsLoading = false;
}
public System.Threading.Tasks.Task<ObservableCollection<Customer>> LoadCostumers()
{
return System.Threading.Tasks.Task.Factory.StartNew(() =>
{
return YourMethodThatGetsCostumers();
});
}
}