Ich habe Probleme, das Ergebnis der asynchronen Methode an die UI zu übermitteln.Asynchrone PointCollection-Änderung in UI propagieren
XAML
<Window x:Class="COVMin.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:COVMin"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid Margin="0,0,0,0">
<Border BorderThickness="1" BorderBrush="Black" Background="White" Margin="4" VerticalAlignment="Top" Height="170">
<Polygon Points="{Binding Points}" Stretch="Fill" Fill="Black" Opacity="0.8" />
</Border>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Height="24" Marin="0,0,0,10" VerticalAlignment="Bottom" Width="75" Command="{Binding DrawPointsCommand}"/>
</Grid>
Ansichtsmodell
class MainViewModel : ViewModelBase
{
private PointCollection points { get; set; }
public PointCollection Points
{
get { return this.points; }
set
{
this.points = value;
OnPropertyChanged("Points");
}
}
public ICommand DrawPointsCommand { get; private set; }
/// <summary>
/// Simplified, in real it´s long time operation causing UI to freeze.
/// </summary>
private Task<PointCollection> ConvertToPointCollection()
{
return Task.Run<PointCollection>(() =>
{
PointCollection points = new PointCollection();
points.Add(new System.Windows.Point(0, 6236832));
points.Add(new System.Windows.Point(255, 6236832));
return points;
});
}
/// <summary>
///
/// </summary>
private async Task<PointCollection> Process()
{
this.Points = await ConvertToPointCollection();
return this.Points;
}
/// <summary>
/// Method calling long-time operation bound to button as a Command.
/// </summary>
private async void GetValues()
{
this.Points = await Process();
}
/// <summary>
/// Constructor.
/// </summary>
public MainViewModel()
{
this.DrawPointsCommand = new DelegateCommand(GetValues);
}
}
ViewModelBase
/// <summary>
/// Base class for PropertyChanged event handling.
/// </summary>
class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
DelegateCommand Klasse
public class DelegateCommand : ICommand
{
private readonly Action _action;
public DelegateCommand(Action action)
{
_action = action;
}
public void Execute(object parameter)
{
_action();
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
}
Das Problem ist mit OnPropertyChange, die verursacht System.ArgumentException sagt mir, dass ich DependencySource für den gleichen Thread wie DependencyObject erstellen muss. Ich habe einige Stunden damit verbracht, mit den Dispatchern zu versuchen und was nicht, aber immer noch nicht gut.
_ "Erzähl mir, dass ich DependencySource auf dem gleichen Thread wie DependencyObject erstellen muss" _ - was Sie tun. Technisch gesehen macht dies Ihre Frage zu einem Duplikat der kanonischen Antwort "Dispatcher verwenden". Das heißt, Ihre Frage ist zu vage, um sicher zu sein, dass dies alles ist, was Sie brauchen. Mit der "Task" -basierten Methode sollten Sie in der Lage sein, das Ergebnis zu "erwarten" und eine explizite Interaktion mit dem Objekt "Dispatcher" zu vermeiden. Aber Ihr Codebeispiel oben zeigt nicht einmal, wie 'Process()' aufgerufen wird. Bitte stellen Sie eine gute [mcve] zur Verfügung, die das Problem zuverlässig reproduziert. –
Vielen Dank für Ihre Antwort. Ich habe das obige Beispiel aktualisiert, aber ich bin mir nicht sicher, was ich sonst noch hinzufügen sollte. – Tomas
Der Artikel unter dem Link, den ich im vorherigen Kommentar angegeben habe, enthält alle Informationen, die Sie wissen müssen, "was Sie sonst noch dort hinstellen sollten". –