使用调度程序通过 wpf 中的异步方法从 class 更新 UI

using dispatcher to update UI from class with async methods in wpf

我有一个带有管理数据的 class,这个 class 有一个绑定在 UI 菜单中的 ObservableCollection。问题是可观察集合加载数据,但我的 UI 没有显示它。

我的class是这样的

public class DAL : INotifyPropertyChanged
{
    public DAL()
    {
        this.unity = new UnitOfWork(@"http://192.168.0.173/vocalcontactapi");
    }

    private UnitOfWork unity;

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private ObservableCollection<EstadosAgente> estadosPausa = new ObservableCollection<EstadosAgente>();
    public ObservableCollection<EstadosAgente> EstadosPausa
    {
        get { return this.estadosPausa; }
    }

    public async Task<bool> GetAgentStatesAsync()
    {
        await awaitGetAgentStatesTask();
        OnPropertyChanged("EstadosPausa");
        return true;
    }

    private Task awaitGetAgentStatesTask()
    {
        //UnitOfWork unity = new UnitOfWork(Properties.Settings.Default.restServer);
        NameValueCollection parms = new NameValueCollection();
        parms.Add("servicioId", "1");
        return Task.Run(() =>
        {
            try
            {
                var estados = unity.EstadosAgente.GetAll(parms).Where(q => q.habilitado == true).Select(p => p).ToList();
                if (estados == null)
                    return;

                estados.ForEach(x =>
                {
                    Application.Current.Dispatcher.Invoke(new Action(() =>
                    {
                        this.EstadosPausa.Add(x); //*** I think here is the problem***
                    }));
                });

            }
            catch (Exception ex)
            {
                string err = ex.Message;
            }
        });
    }

}

而 mainWindow 我有一个 属性 的 class DAL:

private DAL data = new DAL();
public DAL Data { get{ return this.data}}

在我的菜单中有下一个:

  <Menu Grid.Row="1">
            <MenuItem Header="uno" ItemsSource="{Binding DAL.EstadosPausa}" Click="DataBoundMenuItem_Click">
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="Header" Value="{Binding estado}"/>
                        <Setter Property="Tag" Value="{Binding}" />
                    </Style>
                </MenuItem.ItemContainerStyle>
            </MenuItem>
        </Menu>

显然,加载数据的所有属性都是正确的。有什么帮助吗?

这段代码中有一些东西让我 "itchy" 但无论如何......

您有 public DAL Data 属性 但您绑定到 DAL.EstadosPausa。您需要绑定到 Data.EstadosPausa 才能解决问题。您将在调试器中看到所有绑定错误 Output window.


在这里,考虑一下您的代码库的这个简化但 100% 工作的版本。现在你在玩 async/awaits,无缘无故地返回 Task<bool>Dispatching 工作到 UI 线程(从你的例子中很明显)。

XAML

<Menu Grid.Row="1">
    <MenuItem Header="Uno" ItemsSource="{Binding Data.EstadosPausa}">
        <MenuItem.ItemContainerStyle>
            <Style TargetType="MenuItem">
                <Setter Property="Header" Value="{Binding Estado}"/>
                <Setter Property="Tag" Value="{Binding}" />
            </Style>
        </MenuItem.ItemContainerStyle>
    </MenuItem>
</Menu>

代码隐藏

public partial class MainWindow : Window
{
    private readonly Dal _data = new Dal();

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        _data.GetAgentStatesAsync(); // Fire Task away, no time to wait!!1
    }

    public Dal Data { get { return _data; } }  
}

public class EstadosAgente
{
    public string Estado { get; set; }
}

public class Dal : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Task GetAgentStatesAsync()
    {
        return Task.Run(() =>
            {
                Thread.Sleep(1000); // I'm a long running operation...
                var estados = new List<EstadosAgente>
                    {
                        new EstadosAgente { Estado = "Estado 1" },
                        new EstadosAgente { Estado = "Estado 2" }
                    };
                EstadosPausa = new ObservableCollection<EstadosAgente>(estados);
                OnPropertyChanged("EstadosPausa");
            });
    }

    public ObservableCollection<EstadosAgente> EstadosPausa { get; private set; }

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged; // <- always assign to local variable!
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}