10

Microsoft の問題をここに記録しました - Repro はダウンロード可能です: https://connect.microsoft.com/VisualStudio/feedback/details/741454/value-change-event-doesnt-fire-for-datetimepicker-controls-used -in-vsto-アドイン

DateTimePicker を Excel VSTO フローティング アドインに配置し、カレンダーがドロップダウンしたときにアドインの端の外側になるように配置する場合は、次を参照してください。

ここに画像の説明を入力

緑の丸で囲まれた日付を選択すると期待どおりに機能しますが、赤で丸で囲まれた日付をクリックすると、カレンダーのドロップダウンが閉じられ、日付が設定されません!

これを修正する方法を知っている人はいますか?

編集

この SO ユーザーは、WPF を使用して問題を経験しました: VSTO WPF ContextMenu.MenuItem TaskPane の外側をクリックして発生しません

ここに画像の説明を入力

その質問への回答は、問題がしばらく前に接続することが報告されたことを示していますが、VSTO 4.0 SP1 ではまだ解決策がありません: https://connect.microsoft.com/VisualStudio/feedback/details/432998/excel-2007-vsto-custom-タスク ペイン-with-wpf-context-menu-has-focus-problems

回避策の 1 つは、DispatcherFrame を使用してメッセージをポンプし、メニューの GotFocusEvent と LostFocusEvent をサブスクライブすることです。http://blogs.msdn.com/b/vsod/archive/2009/12/16/excel-2007-wpf-events-are-not-fired-for-items-that-overlap-excel-ui-for- wpf-context-menus.aspx ですが、これはメニューのすべての WPF コードであり、Winform DateTimePicker のソリューションではありません。

Microsoft Connect の再現:

新しいプロジェクト > Excel 2010 アドイン

using TaskPane;
using Microsoft.Office.Core;

namespace ExcelAddIn2
{
public partial class ThisAddIn
{
    TaskPaneView MyTaskView = null;
    Microsoft.Office.Tools.CustomTaskPane MyTaskPane = null;

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    //setup custom taskpane
    MyTaskView = new TaskPaneView();
    MyTaskView.currentInstance = Globals.ThisAddIn.Application;
    MyTaskPane = this.CustomTaskPanes.Add(MyTaskView, "MyTaskView");
    MyTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionFloating;
    MyTaskPane.DockPositionRestrict = MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
    MyTaskPane.Visible = true;
}
}

[ファイル] メニュー > [追加] > [新しいプロジェクト] > [クラス ライブラリ] > 名前付き TaskPane

次に、TaskPane プロジェクトで、TaskPaneView という名前のユーザー コントロールを作成します。

public partial class TaskPaneView : UserControl
{
    public TaskPaneView()
    {
        InitializeComponent();
    }

    public Microsoft.Office.Interop.Excel.Application currentInstance { get; set; }

    public TaskPaneCtrl getTaskPaneCtrl
    {
        get { return this.taskPaneCtrl1; }
    }  

}

次に、DateTimePicker を使用してユーザー コントロールを作成し、Calendar コントロールがユーザー コントロールの右下に配置されていることを確認します。

public partial class TaskPaneCtrl : UserControl
{
public TaskPaneCtrl()
{
    InitializeComponent();
}
}

TaskPane クラス ライブラリで、Excel Interop を参照します (例: c:\Program Files x86\Microsoft Visual Studio 14.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Excel.dll)。

ソリューションをビルドします。機能しない部分をコメントアウトします。ビルド ソリューション。

TaskPaneCtrl を TaskPaneView にドラッグ アンド ドロップし、コンパイルに失敗したもののコメントを外します。

ここに画像の説明を入力

F5 キーを押してカレンダー コントロールをクリックし、タスクペイン領域外の日付を選択してみてください。Value Change イベントは発生しません。カレンダーの外でクリックしたように動作します。

注: コントロールから落ちるドロップダウンリストを試しましたが、そのイベントは発火します!

4

2 に答える 2

7

ここで問題となるのは「フローティング」です。Excel のメッセージ ポンプを使用して Windows メッセージ (これらのコントロールを入力に応答させるメッセージ) をディスパッチすることは、決して問題ではありません (奇妙なことの原因となることがあります)。これは、Winforms と同様に WPF でもうまくいかず、ウィンドウに配信される前にメッセージをフィルタリングする独自のディスパッチ ループがあります。それぞれのディスパッチャが使用されていない場合に問題となる主な問題は、タブ移動やショートカット キーストロークなどです。

そして、この種の問題は、メッセージをディスパッチする前に Excel が独自のフィルタリングを行うことによって引き起こされます。マルウェア対策機能については、Microsoft はプログラムが Office アプリをいじることをずっと心配していると思います。

Winforms ソリューションは、WPF の回避策と同じものです。独自のメッセージ ループをポンピングする必要があります。これには多少の手術が必要です。DateTimePicker は、DropDown イベントのキャンセルを許可せず、カレンダーが既に表示されたに発生するため、協力しません。回避策はばかげていますが効果的です。DTP のドロップダウン矢印のように見えるボタンをフォームに追加し、矢印に重なるようにして、矢印の代わりにクリックされるようにします。

ボタンをドロップダウン矢印に重ねるためのコード例:

    public Form1() {
        InitializeComponent();
        var btn = new Button();
        btn.BackgroundImage = Properties.Resources.DropdownArrow;
        btn.FlatStyle = FlatStyle.Flat;
        btn.BackColor = Color.FromKnownColor(KnownColor.Window);
        btn.Parent = dateTimePicker1;
        btn.Dock = DockStyle.Right;
        btn.Click += showMonthCalendar;
        dateTimePicker1.Resize += delegate {
            btn.Width = btn.Height = dateTimePicker1.ClientSize.Height;
        };
    }

Click イベント ハンドラーは、MonthCalendar を含むダイアログを表示する必要があります。

    private void showMonthCalendar(object sender, EventArgs e) {
        dateTimePicker1.Focus();
        using (var dlg = new CalendarForm()) {
            dlg.DateSelected += new DateRangeEventHandler((s, ea) => dateTimePicker1.Value = ea.Start);
            dlg.Location = dateTimePicker1.PointToScreen(new Point(0, dateTimePicker1.Height));
            dlg.ShowDialog(this);
        }
    }

CalendarForm を使用すると、ボーダーレスで MonthCalendar のみを含むフォームを追加できます。

public partial class CalendarForm : Form {
    public event DateRangeEventHandler DateSelected;

    public CalendarForm() {
        InitializeComponent();
        this.StartPosition = FormStartPosition.Manual;
        monthCalendar1.Resize += delegate {
            this.ClientSize = monthCalendar1.Size;
        };
        monthCalendar1.DateSelected += monthCalendar1_DateSelected;
    }

    void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e) {
        if (DateSelected != null) DateSelected(this, e);
        this.DialogResult = DialogResult.OK;
    }
}
于 2012-05-12T13:34:21.190 に答える
2

憶測:
このバグは、クリック メッセージが送信されるまで datetimepicker のサーフェスがレンダリングされないために発生します。

回答するための次のステップ:
可能であれば、サード パーティの日時ピッカー コントロールでテストしてみてください。問題が解決するかどうかはまだわからないため、これは完全な答えではないことを認識しています。

その他の回答: コントロールに合わせてタスクペインのサイズを変更します。これでバグは解決されますが、ユーザーの観点からは少し奇妙に見えます。

于 2012-05-10T05:54:12.733 に答える