2017-01-25 1 views
3

はじめC#:アプリケーションのクラッシュレポートビューアーで数回

を更新]ボタンをクリックした後、これはレポートビューアーは、.NET Framework 4.6.1を目標としている私のWinformsのアプリケーションでどのように見えるかの部分です。リフレッシュボタン(丸でダブル緑色の矢印)は、それ自体でヌルパラメータでbtnOK_Clickイベントを呼び出すレポートビューアーイベントをコールしながら

enter image description here

OKボタンは、btnOk_Clickイベントを呼び出します。以下のコードは、レポートビューアーで数回を更新]ボタンをクリックした後、それ

コード

private void btnOk_Click(object sender, EventArgs e) 
    { 
     try 
     { 
      ... 
      //Code adding datasources to rpvCustomReport 
      ... 
      this.rpvCustomReport.RefreshReport(); //Causing the error. 
      //NOTE: this.rpvCustomReport is instantiated in .Design.cs as 
      //new Microsoft.Reporting.WinForms.ReportViewer(); 
      ... 
     } 
     catch (Exception ex) 
     { 
      HandleException(ex); //Custom function to handle exception 
     } 
    } 

private void rpvCustomReport_ReportRefresh(object sender, CancelEventArgs e) 
    { 
     this.btnOk_Click(null, null); //sender object and event variables are not used in this function, hence, it is set to null 
    } 

問題

私のアプリケーションのクラッシュを示しています。

enter image description here

これは私がイベントビューア> Windowsログ>アプリケーション

メッセージで見つけたものです:例外はAsyncLocal通知コールバックで処理されていませんでした。私はエラーのためにグーグルを試みたが、不足していた。

enter image description here

手がかり

  1. この問題は、私は急速に[OK]ボタンをクリックすると、この問題は発生しませんデバッグモード(Visual Studioの2015)
  2. では発生しません。 I冗長/テストコード(例えば、MessageBox.Show()this.rpvCustomReport.RefreshReport();ラインbtnOk_Clickにイベントを追加すると
  3. 、この問題は発生しません。しかし、の前にの行を追加すると、問題が発生します。これは、私がthis.rpvCustomReport.RefreshReport();が問題を引き起こしていると結論付けた方法でした。

質問

  1. なぜその問題が発生したのか?
  2. 今後この種の問題をデバッグするために実行する必要がある手順は何ですか?

回避策

この問題を解決するために、私はbtnOk_Clickを呼び出す前に、イベントをキャンセルしなければなりません。

private void rpvCustomReport_ReportRefresh(object sender, CancelEventArgs e) 
{ 
    e.Cancel = true; //Cancel the default event. 
    this.btnOk_Click(null, null); //sender object and event variables are not used in this function, hence, it is set to null 
} 

なぜ私はデフォルトの動作をキャンセルする必要があるのか​​まだ分かりません。それは良い修正のようには見えません。

+0

16:18:59の.NETランタイムエラーは何ですか? –

+0

@ScottChamberlain私は16:18:59に最初のクラッシュを経験しました。その後、アプリケーションを再起動し、もう一度[更新]ボタンをクリックすると、16時19分20秒にクラッシュする可能性があります。したがって、16:18:59の.NETランタイムエラーは、16:19:20の.NETランタイムエラーとまったく同じです。 – Mark

答えて

2

私はMSDNでもあなたの質問にこの応答を掲載しました。

これは、現在の操作の途中でキャンセルして再び開始すると、ReportViewerの内部非同期レンダリングと関係があります。レポートを読み込んだ後、すぐに表示モードを印刷レイアウトに設定することで、私はそれに遭遇しました。これを繰り返し実行すると、次のコードを含むフォームにボタンを追加し、繰り返しクリックすることで、繰り返し可能なエラーを減らすことができます(注意したように、デバッガで実行中に問題は発生しません)。

form.ReportViewer.SetDisplayMode(DisplayMode.PrintLayout); 
form.ReportViewer.SetDisplayMode(DisplayMode.Normal); 

ReportViewerの[更新]ボタンをクリックすると、レポートの内部更新ルーチンが起動します。あなたがあれば、ReportRefreshイベントが発生していることを

private void OnRefresh(object sender, EventArgs e) 
{ 
    try 
    { 
    CancelEventArgs e1 = new CancelEventArgs(); 
    if (this.ReportRefresh != null) 
     this.ReportRefresh((object) this, e1); 
    if (e1.Cancel) 
     return; 
    int targetPage = 1; 
    PostRenderArgs postRenderArgs = (PostRenderArgs) null; 
    if (sender == this.m_autoRefreshTimer) 
    { 
     targetPage = this.CurrentPage; 
     postRenderArgs = new PostRenderArgs(true, false, this.winRSviewer.ReportPanelAutoScrollPosition); 
    } 
    this.RefreshReport(targetPage, postRenderArgs); 
    } 
    catch (Exception ex) 
    { 
    this.UpdateUIState(ex); 
    } 
} 

お知らせをして:(Microsoftは今、これをオープンソース有しているが、あなたがMSコード参照サイト上で見つけることができますので、JetBrainsのdotPeekを使用して抽出)このコードは次のようになりますこのイベントをキャンセルしないと、ReportViewerは引き続きレポートを処理して再レンダリングします。イベントハンドラ内にあるコードは、ReportViewerにリフレッシュを指示します。リフレッシュは、基本的に、自分のコードと同じようにReportViewerをホイップするという同じ問題を設定します。

私はもともと、MS Connectの公式のバグレポートを提出するというアイデアでこれをさらに分離することを意図していましたが、私が気を付けるほどウサギの穴まで遠くまで行ってきました。私たちは、コールスタックから知っていることは、スレッドが実行コンテキストを切り替えていることである:火災をOnAsyncLocalContextChangedとき

Description: The application requested process termination through System.Environment.FailFast(string message). 
Message: An exception was not handled in an AsyncLocal<T> notification callback. 
Stack: 
    at System.Environment.FailFast(System.String, System.Exception) 
    at System.Threading.ExecutionContext.OnAsyncLocalContextChanged(System.Threading.ExecutionContext, System.Threading.ExecutionContext) 
    at System.Threading.ExecutionContext.SetExecutionContext(System.Threading.ExecutionContext, Boolean) 
    at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
    at System.Threading.ThreadHelper.ThreadStart(System.Object) 

、それは変更通知のためのコールバックを処理しようとします。これらのコールバックの

[SecurityCritical] 
[HandleProcessCorruptedStateExceptions] 
internal static void OnAsyncLocalContextChanged(ExecutionContext previous, ExecutionContext current) 
{ 
    List<IAsyncLocal> previousLocalChangeNotifications = (previous == null) ? null : previous._localChangeNotifications; 
    if (previousLocalChangeNotifications != null) 
    { 
     foreach (IAsyncLocal local in previousLocalChangeNotifications) 
     { 
      object previousValue = null; 
      if (previous != null && previous._localValues != null) 
       previous._localValues.TryGetValue(local, out previousValue); 

      object currentValue = null; 
      if (current != null && current._localValues != null) 
       current._localValues.TryGetValue(local, out currentValue); 

      if (previousValue != currentValue) 
       local.OnValueChanged(previousValue, currentValue, true); 
     } 
    } 

    List<IAsyncLocal> currentLocalChangeNotifications = (current == null) ? null : current._localChangeNotifications; 
    if (currentLocalChangeNotifications != null && currentLocalChangeNotifications != previousLocalChangeNotifications) 
    { 
     try 
     { 
      foreach (IAsyncLocal local in currentLocalChangeNotifications) 
      { 
       // If the local has a value in the previous context, we already fired the event for that local 
       // in the code above. 
       object previousValue = null; 
       if (previous == null || 
        previous._localValues == null || 
        !previous._localValues.TryGetValue(local, out previousValue)) 
       { 
        object currentValue = null; 
        if (current != null && current._localValues != null) 
         current._localValues.TryGetValue(local, out currentValue); 

        if (previousValue != currentValue) 
         local.OnValueChanged(previousValue, currentValue, true); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      Environment.FailFast(
       Environment.GetResourceString("ExecutionContext_ExceptionInAsyncLocalNotification"), 
       ex); 
     } 
    } 
} 

ひとつ投げていますOnAsyncLocalContextChangedがイベントログにエントリを書き込んですぐにアプリケーションを終了させるtry/catchでEnvironment.FailFastを呼び出す例外が発生しました。

ReportViewerが爆発する前にボタンをランダムにクリックすることができるため、この問題には競合状態のすべての特徴があります。今のところ、私たちはそれを避ける方法を知っています。私の場合は、レポートを更新する前に表示モードを設定する必要があります。あなたにとって、ReportRefreshイベントをキャンセルすると、重複した処理が回避され、その理由がわからなくても問題が解決されます。たぶんそこにいる誰かがそれをさらに気にすることがあります。

0

あなたは

this.btnOk_Click(sender, e); 

にコード

this.btnOk_Click(null, null); 

を置き換えることができ、私はそれが問題

+0

いいえ、問題は解決しません。 – Mark

0

を解決していない場合は、

btnOk.PerformClick(); 
を使用することができるはずです知ってみましょう

また、いいですねo try - catchブロックを使用し、実行時に発生するエラーを記録すると、アプリケーションのソースコードをデバッグすることができない場合があります。

+0

ありがとう、ありがとうございます。これはアプリケーションクラッシュエラーを解決しません。また、あなたが見ることができるように、私のコードで 'try-catch'ブロックを使用しましたが、それをキャッチしませんでした。アプリケーションはただ終了します。 – Mark

+0

私が見ているように、問題が発生した場所では 'try-catch'ブロックはありません。 'rpvCustomReport_ReportRefresh'メソッドの内容を' try-catch'にラップします。 – DDan

+0

はい私はそれを持っています。コードセクションでは、問題のどこに問題が発生したのかを、 'btnOk_Click()'メソッドの '/ /エラーを発生させる'のところで強調しています – Mark

0

パラメータなしでボタンクリック機能を呼び出すことができます。

btnOk.Click();またはbtnOk.PerformClick();

次のようにコードを変更して試してみてください。

private void doSomeThing() { 
try 
    { 
     ... 
     //Code adding datasources to rpvCustomReport 
     ... 
     this.rpvCustomReport.RefreshReport(); //Causing the error. 
     //NOTE: this.rpvCustomReport is instantiated in .Design.cs as 
     //new Microsoft.Reporting.WinForms.ReportViewer(); 
     ... 
    } 
    catch (Exception ex) 
    { 
     HandleException(ex); //Custom function to handle exception 
    } 
} 

private void btnOk_Click(object sender, EventArgs e) 
{ 
    this.doSomeThing(); 
} 

private void rpvCustomReport_ReportRefresh(object sender, CancelEventArgs e) 
{ 
    this.doSomeThing(); 
} 
+0

ありがとう、ありがとうございます。これはアプリケーションクラッシュエラーを解決しません。 – Mark

関連する問題