非同期メソッドの結果をUIに伝播するのに問題があります。async PointCollectionをUIに変更する
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>
ビューモデル
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クラス
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;
}
問題は、DependencyObjectと同じスレッドでDependencySourceを作成する必要があることを示すSystem.ArgumentExceptionを引き起こすOnPropertyChangeにあります。私はDispatchersで何時間も過ごしましたが、それでもなお良いことはありません。
_ "DependencyObjectと同じスレッドでDependencySourceを作成する必要があることを私に伝える" _ - これはあなたが行うことです。技術的には、それはあなたの質問を標準的な "ディスパッチャの使用"答えの複製にします。あなたの質問はあまりにも漠然としているので、それがあなたが必要とするすべての助けだと確かめることはできません。 'Task'ベースのメソッドでは、結果を'待つ 'ことができ、 'Dispatcher'オブジェクトとの明示的なやりとりを避けることができます。しかし、上のコード例では、 'Process()'がどのように呼び出されているかを示していません。問題を確実に再現する良い[mcve]を提供してください。 –
ありがとうございます。上記の例を更新しましたが、他に何を置くべきかはわかりません。 – Tomas
私が前のコメントで提供したリンクの記事は、あなたが知っておくべき情報のすべてを提供しています。 –