0

リストから 1 つを選択すると、パワーポイントを WPF 要素に変換する WPF アプリケーションを構築しています。ViewModel をビューにバインドし、ViewModel 間の通信を追加するために、MVVM ライトを使用しています。

OpenLocalView と PresentationView の 2 つのビューがあります。OpenLocalView でパワーポイントを選択すると、MVVM ライトによって、PresentationView の ViewModel とそのパワーポイントへのパスを含む MainViewModel にメッセージが送信されます。MainViewModel はビューを PresentationView に切り替え、PresentationViewModel はこのコードを実行してパワーポイントを変換します。変換が完了したら、現在のスライドを設定して、PresentationView に表示されるようにします。

  public void StartPresentation(string location)
  {
        var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
        Loading = true;
        Task.Factory.StartNew(() =>
            {
                var converterFactory = new ConverterFactory();
                var converter = converterFactory.CreatePowerPointConverter();
                _slides = converter.Convert(location).Slides;
            }, 
            CancellationToken.None, 
            TaskCreationOptions.LongRunning, 
            scheduler).ContinueWith(x =>
                {
                    Loading = false;
                    CurrentSlide = _slides.First();
                }, 
                CancellationToken.None, 
                TaskContinuationOptions.OnlyOnRanToCompletion, 
                scheduler);
   }

Loading プロパティが設定されている場合、ビューは「読み込み中」メッセージで更新され、UI の応答性が向上します。

    public Boolean Loading
    {
        get { return _loading; }
        set
        {
            _loading = value;
            RaisePropertyChanged("Loading");
        }
    }

問題は、これが最初にパワーポイントを読み込んだときに正しく実行されることです。ビューがPresentationViewに切り替わり、「読み込み中」メッセージが表示され、変換が完了すると、メッセージが消えてスライドが表示されます。しかし、OpenLocalView に戻って別のパワーポイントを選択すると、OpenLocalView がハングし、コンバーターの終了後に PresentationView に切り替わり、「読み込み中」メッセージがまったく表示されません。

参考までに、関連するコードをいくつか追加します。

これは、OpenLocalViewModel でパワーポイントが選択されたときに実行されます。

    private void PerformOpenPresentation(string location)
    {
        Messenger.Default.Send<OpenPowerPointMessage>(new OpenPowerPointMessage {Location = location});
    }

MainViewModel はメッセンジャーにサブスクライブされ、ビューを切り替えます。

Messenger.Default.Register<OpenPowerPointMessage>(this,
            delegate
            {
                if (_presentation == null) _presentation = new PresentationView();
                CurrentView = _presentation;
            });

PresentationViewModel もメッセンジャーにサブスクライブされ、上記のメソッドを実行します。

Messenger.Default.Register<OpenPowerPointMessage>(this, message => StartPresentation(message.Location));

それで、私は何を間違っていますか?繰り返しますが、同じコードが実行されますが、一度は問題なく実行され、その後は実行されません。

4

4 に答える 4

1

変換を開始したときに、UIがまだ更新されていない可能性があります。Loadingをtrueに設定してからコンバータスレッドが開始するまで数ミリ秒待ってみてください:)

于 2012-05-31T08:05:05.740 に答える
1

ここを見て:

 var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
 Loading = true;

Task.Factory.StartNew(() =>
        {
            var converterFactory = new ConverterFactory();
            var converter = converterFactory.CreatePowerPointConverter();
            _slides = converter.Convert(location).Slides;
        }, 
        CancellationToken.None, 
        TaskCreationOptions.LongRunning, 
here  ----> scheduler).ContinueWith(x =>
            {
                Loading = false;
                CurrentSlide = _slides.First();
            }, 
            CancellationToken.None, 
            TaskContinuationOptions.OnlyOnRanToCompletion, 
            scheduler);

同期コンテキスト、つまり UI スレッドで「長時間実行」タスクを開始しています。実行時間の長いタスクでスケジューラを取り除き、継続して残します。:)

于 2012-05-30T13:19:39.900 に答える
0

「Loading = true」をタスク開始ブロックに移動することをお勧めしますが、「Loading」値を設定する際は必ずディスパッチャーを使用してください。問題の実際の理由は言えないかもしれませんが、試してみる価値はあります...

このような何かが役立つかもしれません..

Task.Factory.StartNew(() =>
            {
               System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)delegate()
                 {
                     Loading = true;
                  });
                var converterFactory = new ConverterFactory();
                var converter = converterFactory.CreatePowerPointConverter();
                _slides = converter.Convert(location).Slides;
            }
于 2012-05-30T13:46:55.930 に答える
0

わかりました、私はWindowsフォームでそれをしましたが、同じだと思います

Task スレッドで Label を作成し、フォームの Invoke を呼び出します

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    public void AddControl(Control control)
    {
        if (InvokeRequired)
        {
            this.Invoke(new Action<Control>(AddControl), new object[] { control });
            return;
        }
        this.Controls.Add(control);
    }

    private void Form1_Load(object sender, EventArgs e)
    {

        Task.Factory.StartNew(() =>
            {
                var label = new Label
                {
                    Location = new Point(0, 0),
                    Text = "hola",
                    ForeColor = Color.Black
                };
                this.Invoke(new Action<Control>(AddControl), new object[] { label });
            });
    }
}

編集

Dispather.Invokeを使用するのはどうですか.これがUIをブロックするかどうかはわかりません....

  public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public void AddControl()
    {
        var l = new Label
        {
            Content = "Label",
            Height = 28,
            HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
            Margin = new Thickness(209, 118, 0, 0),
            Name = "label1",
            VerticalAlignment = System.Windows.VerticalAlignment.Top
        };

        Grid.Children.Add(l);
    }


    private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            Dispatcher.Invoke(new Action(AddControl), null);
        });
    }
}
于 2012-05-30T14:24:15.150 に答える