Windows CE 5.0 で実行している .NET CF 2.0 アプリケーションで奇妙な動作が発生しました。
コントロールを定期的に更新するタイマーがあります。そのコントロールは、(マウスダウンハンドラーで) ユーザーからタップアンドホールドジェスチャを受け取ることもできます。私が見つけたのは、TAH が開始すると (終了する前に) タイマー イベントが処理を開始し、実行の途中でマウス ダウン ハンドラーをプリエンプトする可能性があることです。
私の調査によると、これは通常の動作ではなく、単にタイマー/イベントを誤解しているだけですか? SHRecognizeGesture が Application.DoEvents と同等のものを呼び出しているだけでしょうか?
いずれにせよ、アプリがTAHをチェックしているときにタイマーデリゲートが「カチカチ」しないように、この例を修正する「良い」方法を誰かが持っていますか?
この問題を説明するサンプル プログラムについては、以下を参照してください (リスト ボックスの下の空きスペースをタップ アンド ホールドすると、ログ メッセージが生成されます)。
前もって感謝します。
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace DeviceApplication1
{
public class BugExample : Control
{
[Flags]
internal enum SHRGFLags
{
SHRG_RETURNCMD = 0x00000001,
SHRG_NOTIFYPARENT = 0x00000002,
SHRG_LONGDELAY = 0x00000008,
SHRG_NOANIMATION = 0x00000010,
}
[DllImport("aygshell.dll")]
private extern static int SHRecognizeGesture(ref SHRGINFO shrg);
private struct SHRGINFO
{
public int cbSize;
public IntPtr hwndClient;
public int ptDownx;
public int ptDowny;
public int dwFlags;
}
public bool TapAndHold(int x, int y)
{
SHRGINFO shrgi;
shrgi.cbSize = 20;
shrgi.hwndClient = this.Handle;
shrgi.dwFlags = (int)(SHRGFLags.SHRG_RETURNCMD );
shrgi.ptDownx = x;
shrgi.ptDowny = y;
return (SHRecognizeGesture(ref shrgi) > 0);
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
BugExampleForm parent = (BugExampleForm)this.Parent;
//The problem is that the parent tick event will fire whilst TapAndHold is running
//Does TapAndHold perform an equivelant to Application.DoEvents?
parent.AddLog("Tap Hold - Enter");
parent.AddLog(String.Format("Tap Hold - Exit - {0}", TapAndHold(e.X, e.Y)));
}
}
public class BugExampleForm : Form
{
Timer _timer;
BugExample _example;
ListBox _logBox;
public BugExampleForm()
{
_example = new BugExample();
_example.Dock = DockStyle.Fill;
_logBox = new ListBox();
_logBox.Dock = DockStyle.Top;
_timer = new Timer();
_timer.Interval = 1000;
_timer.Enabled = true;
_timer.Tick += new EventHandler(_timer_Tick);
this.SuspendLayout();
this.Text = "Example";
this.Size = new System.Drawing.Size(200, 300);
this.Controls.Add(_example);
this.Controls.Add(_logBox);
this.ResumeLayout();
}
void _timer_Tick(object sender, EventArgs e)
{
AddLog("Tick");
}
public void AddLog(string s)
{
_logBox.Items.Add(s);
_logBox.SelectedIndex = _logBox.Items.Count - 1;
}
}
}
画像をインラインでリンクできないため、動作を示すスクリーンショットへのリンクを次に示します。
編集:私の実際のアプリケーションでは、タイマーの目盛りがコントロールを更新しています。そのため、私は 1 つのスレッド内での作業に制限されています。(イベントハンドラーでも必要なことを実際に達成することはできません)。