BackgroundWorker没有';似乎没有效果

本文关键字:有效果 没有 BackgroundWorker | 更新日期: 2023-09-27 18:11:21

解决方案

我自己找到了解决办法。感谢所有的回复,它帮助我走上了正确的道路。

实际上有一种非常简单的方法

我刚刚将我的命令更改为异步方法(public Async void"MethodName"(,如果我想在后面执行ExecuteAbortCommand,我只做了以下操作:

    await Task.Run(() => {
    ExecuteAbortSessionCommand();
    });

它为我完成了任务。我希望它能帮助其他人

BackgroundWorker没有';似乎没有效果

在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();
    });

它为我完成了任务。我希望它能帮助其他人