none
ASP.NET3.5 Windows7 IE8 テキストボックスでIMEキーが効かなくなる。 RRS feed

  • 質問

  • 毎度、お世話になります。

    テキストボックス上で[半角/全角漢字]キーを押してもIMEモードになりません。

    マウスで別の場所(パネル等)をクリックしてからだと有効になります。

    原因が分からず悩んでおります。

    プログラムで先にボタンなどにフォーカスした後にテキストボックスにフォーカスする事で回避できている

    部分もありますが、同じようにしても効かない場合があります。

    どなたか同じ様な現象で悩んだ方、ご教授御願いします。

    2010年10月18日 11:03

回答

  • SurferOnWww さんが使われていた RegisterHiddenField を使用すると、ID の問題は解決できました。
    それと、JavaScript 側でのグローバル変数で対処できたので、HiddenField 自体を不要にできました。

    そんなコードを作成した後、SurferOnWww さんのコードをじっくり見てると、
    focus().focus()
    という箇所、なぜか私には2つ目の focus の方が上にずれて見えるなと思うと同時に気づいたんですが、そもそも、もう一度フォーカスをセットするだけで対処できるんですね!
    (他の人に聞いたら見えないと言われたけど、本当に?と繰り返したらそう言われれば見えると言われました。)

    すると、以下のコードだけでも済むことになり、試してみると正常に機能しました。
    マリカさん、この返信に気づいてくれるといいですけど。

    protected void Page_Load(object sender, EventArgs e)
    {
        // UpdatePanel 上のコントロールに Focus() すると IME が機能しなくなるため、
        // JavaScript 側でフォーカスを再設定する。
        foreach (var c in new[] { Text2 })
        {
            c.Attributes["onFocus"] = "event.srcElement.focus()";
        }
    }

    追記
    その1:JavaScript ではイベントハンドラ内の this は event.srcElement を表すので、this.focus() でも良いようです。
    その2:1つ前の返信で「複数回実行されない場合は」って書いてますけど、Attributes.Add はキーが既存してもエラーにならずに更新してくれるんですね。
    その3:Attributes で設定する場合は大文字小文字は区別されませんが、JavaScript でのイベントは onfocus なので、Attributes でも "onfocus" にしたいと思いました。
    その4:foreach での new[] は、もし対象が複数の TextBox だった時に便利かなと思ったのでした。new[] { Text3,Text4 } みたいに。ちなみに new[] は new TextBox[] と同じで配列です。

    • 回答としてマーク マリカ 2010年10月21日 8:39
    • 編集済み TH01 2010年10月28日 8:19 追記
    2010年10月21日 8:04

すべての返信

  • その問題は ASP.NET と関係ないのでは?

    ASP.NET といっても、それはサーバー側だけの話で、ブラウザに返されるのは
    ただの html + CSS + script です。TextBox なら以下のようになります。

    <input name="TextBox1" type="text" id="TextBox1" />

    そこで IME が動く動かないは単純にクライアント側の問題のはずです。

    たまたま特定の PC で、ファイルが壊れているなどの問題とは違いますか?

    2010年10月18日 12:47
  • >その問題は ASP.NET と関係ないのでは?

    >そこで IME が動く動かないは単純にクライアント側の問題のはずです。

    仰る通りでした。不具合はFireFoxでは発生しませんでした。

    しかしながら、開発中のソフトはIEでの動作検証なのです。

    <asp:Button ID="Touroku" runat="server" Text="登録" />
    <asp:UpdatePanel ID="UP2" runat="server">
    <ContentTemplate>
       <asp:Panel ID="TopPanel" runat="server" Visible="false">
          <asp:TextBox ID="Text1" runat="server"/>
          <asp:Button ID="Tuika" runat="server" Text="追加" />
          <asp:PlaceHolder ID="PlaceHolder1" runat="server" Visible="false">
             <asp:TextBox ID="Text2" runat="server" />
             <asp:Button ID="NewEnd" runat="server" Text="決定" />
             <asp:Button ID="NewCansel" runat="server" Text="キャンセル" />
          </asp:PlaceHolder>
       </asp:Panel> 
    </ContentTemplate>
    </asp:UpdatePanel>

    動きとしては、先頭行の[登録]ボタンを押すとTopPanelのVisibleをtrueにして表示、

    その中の[追加]ボタンを押すと、PlaceHolder1のVisibleをtrueにして表示し、

    テキストボックスText2を入力可能にするという流れです。

    ボタンを押すとPostBackは返ります。

    TopPanel直下のText1ではIMEキーは効きます。PlaceHolder1のText2では無効です。

    UpdatePanelに配置してるためか、ブラウザのソース表示では、Text2や下のボタンの

    <input>タグは展開されていません。

    Visibleを制御するため、UpdatePanelは外せません。

    何が悪いのでしょうか?

     

    2010年10月19日 4:28
  • # すみません。本筋でないところに反応します。

    UpdatePanelに配置してるためか、ブラウザのソース表示では、Text2や下のボタンの

    <input>タグは展開されていません。


    ソース表示だとページをロードした時のソースしか見えませんが、開発者ツール (F12 キー) を使うと、今ブラウザーで表示しているコンテンツのソースが見えます。
    2010年10月19日 5:28
  • 同じコードで(ボタンのイベントハンドラを追加しましたが)試しましたが
    Text1, Text2 ともに、問題なく IME を有効にできましたけど? 

    環境は以下の通りです。

    Vista SP2, IIS7, IE8(標準/互換モード両方), .NET 3.5 SP1

    PlaceHolder を使っているのは何故ですか? アップされたコードには書い
    てないけですが、ひょっとして動的にコンロトールを追加しているのですか?

     
    参考に検証に使ったコードをアップしておきます。

    <%@ Page Language="C#" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <script runat="server">

        protected void Touroku_Click(object sender, EventArgs e)
        {
            TopPanel.Visible = true;
        }

        protected void Tuika_Click(object sender, EventArgs e)
        {
            PlaceHolder1.Visible = true;
        }

        protected void NewCansel_Click(object sender, EventArgs e)
        {
            PlaceHolder1.Visible = false;
        }

        protected void NewEnd_Click(object sender, EventArgs e)
        {
            PlaceHolder1.Visible = false;
        }
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            <asp:Button ID="Touroku" runat="server"
                Text="登録" OnClick="Touroku_Click" />
            <asp:UpdatePanel ID="UP2" runat="server">
                <ContentTemplate>
                    <asp:Panel ID="TopPanel" runat="server" Visible="false">
                        <asp:TextBox ID="Text1" runat="server"/>
                        <asp:Button ID="Tuika" runat="server"
                            Text="追加" OnClick="Tuika_Click" />
                        <asp:PlaceHolder ID="PlaceHolder1"
                            runat="server" Visible="false">
                            <asp:TextBox ID="Text2" runat="server" />
                            <asp:Button ID="NewEnd" runat="server"
                                Text="決定" OnClick="NewEnd_Click" />
                            <asp:Button ID="NewCansel" runat="server"
                                Text="キャンセル" OnClick="NewCansel_Click" />
                        </asp:PlaceHolder>
                    </asp:Panel>
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
        </form>
    </body>
    </html>

    2010年10月19日 12:35
  • わざわざコードを書いてまで検証して頂きましてありがとうございます。

    >PlaceHolder を使っているのは何故ですか? アップされたコードには書い
    >てないですが、ひょっとして動的にコンロトールを追加しているのですか?

    単純に、一つ一つVisbleを切り替えるのが面倒なのでテキストボックスとボタンを

    まとめるためです。動的な追加は行なっていません。

    さて、私のコードでは、PlaceHolder1のVisibleをtrueにした後、Text2.Focus()を

    行なっています。

    検証して頂いたコードでは、Text2が表示された時にテキストボックスにカーソルが

    無いと思います。入力するには、マウスクリックなどでカーソルを移動しますよね?

    最初に書いた様に、別の場所からカーソルが移った場合はIMEキーは効きます。

    他のPCで検証しても同じです。

     

    2010年10月20日 0:27
  • UpdatePanel 上では、以下のようなボタンと入力欄があるだけの単純なページでも問題が再現しますね。
    (Button1_Click では Text2.Focus() をしています。)
    (環境は、Vista、IE8、.NET3.5、OfficeIME2007 です。)

    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:Button ID="Button1" runat="server" Text="Button"
                onclick="Button1_Click" />
            <asp:TextBox ID="Text2" runat="server"></asp:TextBox>
        </ContentTemplate>
    </asp:UpdatePanel>

    ATOK にしても同じでしたので、IE に問題があるんじゃないかと思いました。

    対策として、フォーカスを再設定することで回避するコードを考えてみました。
    JavaScript はほとんど書いたことがなく、とても試行錯誤したのでおかしなところがあるかもしれませんが、一応、IME が働くようにできました。
    HiddenField で再帰を判断したり Element を特定しているのは、技術不足からの苦肉の策です。

    protected void Page_Load(object sender, EventArgs e)
    {
        var hidden = new HiddenField();
        hidden.ID = "hiddenForFocusFix";
        form1.Controls.Add(hidden);

        if (!IsPostBack)
        {
            // JavaScript の設定。
            Text2.Attributes["onFocus"] = @"
    // onfocus が再帰しないようにする。
    var hidden = document.getElementById('hiddenForFocusFix');
    if (hidden.value != '') {
        hidden.value = '';
        return;
    }
    hidden.value = event.srcElement.id;

    // onfocus イベント中は、blur の後に focus できないようなので、
    // setTimeout で処理する。
    setTimeout(
        function(){
            var srcElement =
                document.getElementById(
                    document.getElementById('hiddenForFocusFix').value);
            if (srcElement == null) return;

            srcElement.blur();
            srcElement.focus();
        }, 1);
    ";
        }
    }

    • 回答としてマーク マリカ 2010年10月21日 1:29
    • 回答としてマークされていない マリカ 2010年10月21日 8:39
    2010年10月20日 3:46
  • TH01様、返信ありがとうございます。

    コードを参考にAttributesを設定してみましたが、変な場所で実行時エラーに

    なってしまい原因が判らず挫折しました。

    2010年10月20日 7:03
  • 1つ確認をお願いしたいのですが、新規作成したプロジェクトにて、私の返信に書きました単純なページに上記対策コードを入れた場合でも、エラーが発生しますでしょうか?
    それと参考までに、エラー時のメッセージを教えていただければと思います。
    2010年10月20日 8:02
  • > 単純に、一つ一つVisbleを切り替えるのが面倒なのでテキストボックスとボタンを
    > まとめるためです。動的な追加は行なっていません。

    それなら Panel でもいいはずです。PlaceHolder は MSDN ライブラリによると "Web
    ページ上で動的に追加されたサーバー コントロールを格納します。" ということです。

    > さて、私のコードでは、PlaceHolder1のVisibleをtrueにした後、Text2.Focus()を
    > 行なっています。

    それを何故一番最初に書いておかないのですか? 前にもお願いしましたが、どのよ
    うに説明したら問題が理解されるかをよく考えた上で質問していただければと思いま
    す。お互い時間の節約になりますし。

    以下のようにすれば、IME は働くことは確認しました。ただし、他にもいろいろとコ
    ードがありそうなので、これでもダメかもしれませんが。

    面倒なので jQuery を使いましたが、使わなくてもできると思います(未検証です)。

    <%@ Page Language="C#" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <script runat="server">

        protected void Touroku_Click(object sender, EventArgs e)
        {
            TopPanel.Visible = true;
            ScriptManager.RegisterHiddenField(Page, "hiddenActionName", "Focus1");
        }

        protected void Tuika_Click(object sender, EventArgs e)
        {
            PlaceHolder1.Visible = true;
            ScriptManager.RegisterHiddenField(Page, "hiddenActionName", "Focus2");
        }

        protected void NewCansel_Click(object sender, EventArgs e)
        {
            PlaceHolder1.Visible = false;
            ScriptManager.RegisterHiddenField(Page, "hiddenActionName", "Focus1");
        }

        protected void NewEnd_Click(object sender, EventArgs e)
        {
            PlaceHolder1.Visible = false;
            ScriptManager.RegisterHiddenField(Page, "hiddenActionName", "Focus1");
        }
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
        <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    </head>
    <body>
        <form id="form1" runat="server">
        <h1>Focus TextBox in AJAX</h1>
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server">
            </asp:ScriptManager>
            <script type="text/javascript">
                <!--
                    Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(pageLoaded);

                    function pageLoaded(sender, args) {
                        var actionName = $('#hiddenActionName').val();
                        if (actionName == 'Focus1') {
                            $('#Text1').focus().focus();
                        }
                        else if (actionName == 'Focus2') {
                            $('#Text2').focus().focus();
                        }
                    }
                //-->
            </script>

            <asp:Button ID="Touroku" runat="server"
                Text="登録" OnClick="Touroku_Click" />
            <asp:UpdatePanel ID="UP2" runat="server">
                <ContentTemplate>
                    <asp:Panel ID="TopPanel" runat="server" Visible="false">
                        <asp:TextBox ID="Text1" runat="server"/>
                        <asp:Button ID="Tuika" runat="server"
                            Text="追加" OnClick="Tuika_Click" />
                        <asp:PlaceHolder ID="PlaceHolder1"
                            runat="server" Visible="false">
                            <asp:TextBox ID="Text2" runat="server" />
                            <asp:Button ID="Button1" runat="server"
                                Text="決定" OnClick="NewEnd_Click" />
                            <asp:Button ID="Button2" runat="server"
                                Text="キャンセル" OnClick="NewCansel_Click" />
                        </asp:PlaceHolder>
                    </asp:Panel>
                </ContentTemplate>
            </asp:UpdatePanel>
        </div>
        </form>
    </body>
    </html>

    2010年10月20日 14:38
  • TH01様、御世話になります。

    挫折しておりましたが、返信を書くために再度、挑戦しましたところ成功しました。

    実行エラーは「オブジェクトが見つからない」でした。

    なので、HiddenFieldの動的追加をやめてaspx内に追加して、Text2.Attributes["onFocus"]は、

    Text2.Attributes.Add("onFocus"... にして、ID名のhiddenForFocusFixを

    ctl00_body_hiddenForFocusFix に変更したら動作しました。

    助かりました。ありがとうございました。

     

    2010年10月21日 1:27
  • いつも、説明不足で申し訳ありません。御世話になりました。

    2010年10月21日 1:29
  • > HiddenFieldの動的追加をやめて
    > ID名のhiddenForFocusFixを
    > ctl00_body_hiddenForFocusFix に変更したら動作しました。

    あ、そういうことですか!
    そういえば ID は勝手に変更される場合がありましたね。
    そのあたり調べてみて、もしよりよい方法がわかった場合は私の返信のコードを修正しようと思います(しない可能性が高いです)。

    > Text2.Attributes["onFocus"]は、
    > Text2.Attributes.Add("onFocus"... にして

    複数回実行されない場合はどちらでも同じですが、Add の方が見た目は良いかもしれませんね。

    今回の話は IE の問題かなと思うので、修正されるまでのつなぎ対策のつもりです。
    IE9 で直っていればいいですけど、今回のコードが IE9 や別ブラウザーで問題になるといけませんので、機会があったら動作確認いただければと思います。

    と思いながら、XP, IE6, VS2010 という環境で試してみたところ、ちゃんとフォーカスされました。
    (訂正:違いました! 確認点を間違ってました。↑の環境でも IME は機能しませんでした。)
    IE8, VS2010 で確認したいところですが、環境がありません。。

    SurferOnWww さんのは(私にとって)勉強になりそうです。

    • 編集済み TH01 2010年10月21日 3:59 訂正
    2010年10月21日 3:47
  • SurferOnWww さんが使われていた RegisterHiddenField を使用すると、ID の問題は解決できました。
    それと、JavaScript 側でのグローバル変数で対処できたので、HiddenField 自体を不要にできました。

    そんなコードを作成した後、SurferOnWww さんのコードをじっくり見てると、
    focus().focus()
    という箇所、なぜか私には2つ目の focus の方が上にずれて見えるなと思うと同時に気づいたんですが、そもそも、もう一度フォーカスをセットするだけで対処できるんですね!
    (他の人に聞いたら見えないと言われたけど、本当に?と繰り返したらそう言われれば見えると言われました。)

    すると、以下のコードだけでも済むことになり、試してみると正常に機能しました。
    マリカさん、この返信に気づいてくれるといいですけど。

    protected void Page_Load(object sender, EventArgs e)
    {
        // UpdatePanel 上のコントロールに Focus() すると IME が機能しなくなるため、
        // JavaScript 側でフォーカスを再設定する。
        foreach (var c in new[] { Text2 })
        {
            c.Attributes["onFocus"] = "event.srcElement.focus()";
        }
    }

    追記
    その1:JavaScript ではイベントハンドラ内の this は event.srcElement を表すので、this.focus() でも良いようです。
    その2:1つ前の返信で「複数回実行されない場合は」って書いてますけど、Attributes.Add はキーが既存してもエラーにならずに更新してくれるんですね。
    その3:Attributes で設定する場合は大文字小文字は区別されませんが、JavaScript でのイベントは onfocus なので、Attributes でも "onfocus" にしたいと思いました。
    その4:foreach での new[] は、もし対象が複数の TextBox だった時に便利かなと思ったのでした。new[] { Text3,Text4 } みたいに。ちなみに new[] は new TextBox[] と同じで配列です。

    • 回答としてマーク マリカ 2010年10月21日 8:39
    • 編集済み TH01 2010年10月28日 8:19 追記
    2010年10月21日 8:04
  • 気付いてますよ(^o^)/

    何度も検証して頂き有難うございます。

    早速、試してみましたら動作しました。

    TH01様のコードのforeachでのnewの意味が判らなかったので、単純に

    Text2.Attributes.Add("onFocus", "event.srcElement.focus()");

    としただけでもOKでした。

    コードがスッキリして良かったです。

    これからも、よろしく御願いします。

    2010年10月21日 8:39