C# 加载了UI元素的WPF异步
我需要隐藏加载的路由事件上的某些控件,以及启动异步任务时的控件。为了避免为同一件事编写两个方法,我创建了async Loaded事件并为此仅调用async任务,但我还需要更改两个UI StatusBarItem的内容,这不能在我的async方法中隐藏控件 我以前曾多次偶然发现过类似的示例,并且认为async/await允许您直接更新UI,只要您使用相同的方法调用await 这样做的时候我总是有疑问,所以我需要澄清一下自己,这是在async/await中合法的做法还是一种非常糟糕的做法? 以下是我的示例,说明我的意思:C# 加载了UI元素的WPF异步,c#,wpf,asynchronous,async-await,C#,Wpf,Asynchronous,Async Await,我需要隐藏加载的路由事件上的某些控件,以及启动异步任务时的控件。为了避免为同一件事编写两个方法,我创建了async Loaded事件并为此仅调用async任务,但我还需要更改两个UI StatusBarItem的内容,这不能在我的async方法中隐藏控件 我以前曾多次偶然发现过类似的示例,并且认为async/await允许您直接更新UI,只要您使用相同的方法调用await 这样做的时候我总是有疑问,所以我需要澄清一下自己,这是在async/await中合法的做法还是一种非常糟糕的做法? 以下是我
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
//Controls on UI thread - I change their content
StatusBarItem1.Content = "Some Text";
StatusBarItem2.Content = "Test Text";
await HideControls(); //Asynchronous task
}
private async Task HideControls()
{
await Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//Hide controls in UI Thread
var All_labels = My_Grid.Children.OfType<Label>();
foreach (var item in All_Labels)
{
item.Visibility = Visibility.Hidden;
}
TextBox1.Visibility = Visibility.Hidden;
}));
}
感谢您提前回复 我觉得你的方法真的有点奇怪 假设您了解mvvm,那么您可能知道绑定将比通过控件循环简单得多 无论您是否使用mvvm,我仍然认为实现这一点的简单方法是使用样式设置绑定来绑定所有标签的可见性 您可以将其放在my_网格的资源中,以在其中的所有标签上设置绑定。 还要绑定一个复选框 您可以使用控件的标记,该控件可以是依赖属性,也可以是实现inpc的某个对象中的常规属性 这将是更少的代码 然后,只需在一件事上设置一个属性 有时候,最好是等待任务。延迟(20),这样它肯定有时间做它的事情 然后等待你的任务 上面的内容只设置了可见性,但实际情况可能是获取数据或其他信息 将任务的结果返回到ui线程。在伪代码中:
var someResults = await yourTask;
因此,你的任务就是一项任务
然后你回到UI线程上,可以做任何你需要做的事情,并得到一些结果。
通常您根本不需要不同的线程,因为延迟的原因是从服务器读取数据时99.9%的网络和数据库延迟。在这种情况下,客户机上的任何单独任务几乎都没有“工作”要做,只有等待数据返回
也许作为旁白
Inotifypropertychanged更改通知被封送到ui线程。这意味着它在后台线程中工作
因此,您可以在任务内的vm上潜在地设置绑定属性,这将起作用
我真的不喜欢这种方法,因为如果任务只返回数据,您更关心ui线程和更好的封装
下面是一些快速而肮脏的标记+代码,可以为您提供更具体的内容
Title="MainWindow" Height="450" Width="800" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Click="Button_Click">Do Something</Button>
<StackPanel Tag="Visibility.Visible"
Grid.Column="1"
Name="sp">
<StackPanel.Resources>
<Style TargetType="Label">
<Setter Property="Visibility" Value="{Binding Tag, RelativeSource={RelativeSource AncestorType=StackPanel}}"/>
</Style>
</StackPanel.Resources>
<Label>Apple</Label>
<Label>Banana</Label>
<TextBox Name="TextBox1"
Text="This is the TextBox"
Visibility="{Binding Tag, RelativeSource={RelativeSource AncestorType=StackPanel}}"
/>
</StackPanel>
</Grid>
Title=“MainWindow”Height=“450”Width=“800”>
做点什么
苹果
香蕉
标记是一个依赖属性,所以不需要inpc,但这当然是非常脏的
代码隐藏
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
sp.Tag = Visibility.Collapsed;
var obj = await getSomeObjectAsync();
// obj would be some dto or something in a real app and you'd do something with it
sp.Tag = Visibility.Visible;
}
private static async Task<object> getSomeObjectAsync()
{
// You would do something like database access here rather than just delay.
await Task.Delay(2000);
return new object();
}
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
专用异步无效按钮\u单击(对象发送方,路由目标)
{
sp.Tag=可见性。折叠;
var obj=await getSomeObjectAsync();
//obj可能是dto或真实应用程序中的某个东西,你可以用它做点什么
sp.Tag=可见性。可见;
}
私有静态异步任务getSomeObjectAsync()
{
//您可以在这里执行类似于数据库访问的操作,而不仅仅是延迟。
等待任务。延迟(2000);
返回新对象();
}
}
我不认为你的问题有明确的是或否答案,这在很大程度上取决于上下文。可以肯定的是,在进行UI修改时,您需要小心地处于UI线程中。您的示例可能不是一个很好的示例,因为您在执行任务后没有做任何事情。延迟,因此很难看出异步方法有什么用处。你有没有一个更具体的例子,你想在等待之后改变UI内容?@Gimly,是的,我知道这是一个简单的例子,但这是一个真实的例子。这个发布的示例只是我在加载事件时调用async方法的一部分。另一部分是我通过async Button_click执行4个不同的异步任务,为了能够运行这个按钮,我需要在所有异步任务之前隐藏这些控件,为了将所有控件重置为与加载窗口时相同的点。但让您的方法等待1s再返回有什么好处?由于修改UI的代码需要在UI线程中,因此在执行工作时,它将阻止UI,因此异步没有任何用处。使用MVVM不是“正确”的方法吗?无论如何,对于快速/小型程序,我会像您一样进行脏处理。在您提供的代码中,我看不出有任何理由使hideControl
方法是异步的。在异步方法中包含一些同步代码是绝对正常的(如按钮\u单击
)。不要求每行代码都以wait
开头。谢谢你,我希望得到一个像你这样深刻的答案。我通常在做一些简单的事情时会这样做,到今天为止,没有用户在应用程序中出现任何错误。然而,为了证实你所说的一切,你能发布一个简单的例子吗?迭代控件不会给你任何错误。考虑到wpf的功能,这不是一个非常优雅的解决方案。这也不是很灵活。回答很好。非常感谢,我终于确认了我的错误。在WPF中要学习的另一件事:)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
sp.Tag = Visibility.Collapsed;
var obj = await getSomeObjectAsync();
// obj would be some dto or something in a real app and you'd do something with it
sp.Tag = Visibility.Visible;
}
private static async Task<object> getSomeObjectAsync()
{
// You would do something like database access here rather than just delay.
await Task.Delay(2000);
return new object();
}
}