简体   繁体   中英

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

I've got a class with manage data, and this class has a ObservableCollection which is bind in UI menu. The problem is that the observable collection loads data, but my UI does not show it.

My class is like this

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

}

And mainWindow I have a Property of class DAL:

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

In my menu I've got next:

  <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>

Obviously, all properties of the loaded data are correct. Any help please?

There's few things in this code which makes me "itchy" but anyway...

You have public DAL Data property but you are binding to DAL.EstadosPausa . You need to bind to Data.EstadosPausa and that'll solve it. You'll see all binding errors in your debuggers Output window.


Here, consider this simplified yet 100% working version of your code base. Now you are fooling around with async/await s, returning Task<bool> and Dispatching work to UI thread for no good reason (that is obvious from your example).

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>

CodeBehind

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM