BackgroundWorker没有';似乎没有效果
本文关键字:有效果 没有 BackgroundWorker | 更新日期: 2023-09-27 18:11:21
解决方案
我自己找到了解决办法。感谢所有的回复,它帮助我走上了正确的道路。
实际上有一种非常简单的方法
我刚刚将我的命令更改为异步方法(public Async void"MethodName"(,如果我想在后面执行ExecuteAbortCommand,我只做了以下操作:
await Task.Run(() => {
ExecuteAbortSessionCommand();
});
它为我完成了任务。我希望它能帮助其他人
在wpf-中创建多线程任务时需要注意的几点
首先,除非你的后台进程与视图直接相关,否则你的视图中不应该有线程,把它留在它所属的视图模型中,这将消除你在更新时遇到的大多数问题,因为这些问题将在绑定中处理,对你的gui 没有影响
第二,如果你确实需要做一些与视图相关的事情,只使用Dispatcher。为尽可能小的事务调用,即Textbox.Dispatcher.Invoke(()=>Textbox.Text = "something")
。这是因为当它让调度器在控制的主GUI线程中执行代码时,调度器将锁定你的线程和调度器所连接的元素
正如你所说的,你的任务是与服务器相关的,那么它们不是它的视图元素,所以如果你把它保持在视图模型中,那么你的代码应该看起来像这个
public class LoaderViewModel
{
public LoaderViewModel()
{
loader.DataLoaded += Loader_DataLoaded;
}
public Dispatcher Dispatcher {get; set; }
public ObservableCollection<DataViewModel> Values { get; } = new ObservableCollection<DataViewModel>();
ModelLoader loader = new ModelLoader();
public void LoadData()
{
loader.LoadData();
}
private void Loader_DataLoaded(object sender, IEnumerable<DataModel> e)
{
Dispatcher.Invoke(() => Values.Clear());
foreach (var item in e)
{
Dispatcher.Invoke(()=>Values.Add(new DataViewModel( item)));
}
}
}
public class DataViewModel : INotifyPropertyChanged
{
public DataViewModel(DataModel model)
{
Model = model;
Model.ValueLoaded += Model_ValueLoaded;
}
private void Model_ValueLoaded(object sender, EventArgs e)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Text"));
}
public event PropertyChangedEventHandler PropertyChanged;
public DataModel Model { get;private set; }
public string Text
{
get { return Model.Value; }
}
}
public class DataModel
{
public DataModel(int id)
{
ID = id;
}
public int ID { get; set; }
private string _Value = "Loading...";
Task backgroundLoad;
public string Value
{
get {
if (backgroundLoad == null && _Value == "Loading...")//background Load on Demand
{
backgroundLoad = Task.Run(async () =>
{
Value = await Server.GetDataValues(ID);
});
}
return _Value;
}
set
{
if (_Value != value)
{
_Value = value;
ValueLoaded?.Invoke(this, EventArgs.Empty);
}
}
}
public event EventHandler ValueLoaded;
}
public class ModelLoader
{
public void LoadData()
{
loading = Task.Run(async()=>
{
var results = (await Server.GetDataIDs()).Select(i => new DataModel(i));
DataLoaded?.Invoke(this, results);
});
}
private Task loading;
public event EventHandler<IEnumerable<DataModel>> DataLoaded;
}
//simulates a slow responding server
public static class Server
{
private static Random rnd = new Random();
public static async Task<IEnumerable<int>> GetDataIDs()
{
await Task.Delay(5000);
return Enumerable.Range(1, 15);
}
public static async Task<string> GetDataValues(int id)
{
await Task.Delay(rnd.Next(100,6000));
return $"Values {id}";
}
}
我制作的快速演示的视图是
<Window x:Class="WpfApplication1.MainWindow"
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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:LoaderViewModel x:Name="viewModel" />
</Window.DataContext>
<DockPanel>
<Button Click="Clear_Click" DockPanel.Dock="Top" >Clear</Button>
<Button Click="Load_Click" DockPanel.Dock="Top">Load Data</Button>
<ListView ItemsSource="{Binding Values}" ScrollViewer.VerticalScrollBarVisibility="Visible" >
<ListView.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Text}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DockPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
viewModel.Dispatcher = Dispatcher;
}
private void Clear_Click(object sender, RoutedEventArgs e)
{
viewModel.Values.Clear();
}
private void Load_Click(object sender, RoutedEventArgs e)
{
viewModel.LoadData();
}
}
注意:该视图只是演示ViewModel 的一个快速而肮脏的示例
解决方案
我自己找到了解决办法。感谢所有的回复,它帮助我走上了正确的道路。
实际上有一种非常简单的方法
我刚刚将我的命令更改为异步方法(public Async void"MethodName"(,如果我想在后面执行ExecuteAbortCommand,我只做了以下操作:
await Task.Run(() => {
ExecuteAbortSessionCommand();
});
它为我完成了任务。我希望它能帮助其他人