none
タップされたら、TextBox を入力可能し、タッチキーボードを表示したい RRS feed

  • 質問

  • お世話になります。
    DataTemplate で定義した Grid があり、そこには10数行の RowDefinition を定義しています。一部の行は、TextBox で デフォルトが IsReadOnly="True" の設定です。
    DataTemplate は、ObservableCollection 型のデータをバインドしています。

    やりたい事は、画面をタップされたら、IsReadOnly を False に設定し、フォーカスを当てて、タッチキーボードを表示 したいです。
    TextBox には Tapped イベントが入らないようなので、Grid のTappedイベントで処理しようとしています。
    DataTemplate の Grid 内の TextBox にアクセスするには、どのようにしたらよいのかよく分かりません。ご教示よろしくお願いいたします。


    <DataTemplate x:key="recordInfoItemTemplate">
          <Grid x:Name="gridRecord" Margin="0,0,0,20"  Width="130"
                   HorizontalAlignment="Left" VerticalAlignment="Top"
                   IsTapEnabled="True" Tapped="textBoxOrdering_Tapped">
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition/>
                   :
                   :
                        <RowDefinition/>
                  </Grid.RowDefinitions>
                  <Border Grid.Row="0" BorderBrush="DargGray" BorderThickness="1"
                             Background="Navy">
                        <TextBlock Text="{Binding Date}" Foreground="White"
                        Style={StaticResource InformationTextBlockStyle}"/>
                  </Border>
              :
              :
                  <Border Grid.Row="0" BorderBrush="DargGray" BorderThickness="1"
                              Background="Navy">
                        <TextBox x:Name="textBoxFirst" Text="{Binding First, mode=TwoWay}
                                       IsReadOnly="True" IsTapEnabled="True"
                       Tapped="textBoxFirst_Tapped"/>
                  </Border>
             :
    </DataTemplate>

       :
       :
       :
       <ItemsControl
                Grid.Column="1"
                          x:Name="itemsControlFutureRecordsArea"
                          ItemsSource="{Binding}"
                          ItemTemplate="{StaticResource recordInfoItemTemplate}">
            <ItemsControl.ItemsPanel>
                  <ItemsPanelTemplate>
                          <StackPanel Orientation="Horizontal"/>
                  </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
       </ItemsControl>


    • 編集済み JOSIE39 2013年11月14日 7:36
    2013年11月14日 7:34

回答

  • > DataTemplate の Grid 内の TextBox にアクセスするには、どのようにしたらよいのかよく分かりません

    ここ↑が一番悩んでおられるところでしょうね。
    VisualTreeHelperを使えば、Grid コントロール内に配置されているコントロールを探し出すことができます。

    > Grid のTappedイベントで処理しようとしています

    そのイベント ハンドラーでは Grid コントロールを取得できますね(第1引数)。
    あとは、VisualTreeHelperを使って、Grid コントロールの子ども (クラスの継承関係ではなくて、ビジュアル ツリーの親子関係) の中から目的のコントロールを探しだしてやります。
    たとえば、子どもの中から特定のコントロールで最初に見つかったものを取得するなら、次のようなメソッドが使えます。今回の場合ですと、T には TextBox を、引数 parent には Grid コントロールを指定してやります。

        // 指定されたコントロールの子から、特定の型で最初に見つかったものを返す 
        private T FindFirstControlByType<T>(DependencyObject parent) 
          where T : DependencyObject 
        { 
          int childrenCount = VisualTreeHelper.GetChildrenCount(parent); 
          if (childrenCount == 0) 
            return null; 
     
          for (int i = 0; i < childrenCount; i++) 
          { 
            DependencyObject child = VisualTreeHelper.GetChild(parent, i); 
            if (child is T) //←検索条件を変えるにはココを修正する
              return child as T; 
     
            var grandchild = FindFirstControlByType<T>(child); 
            if (grandchild != null) 
              return grandchild; 
          } 
     
          return null; 
        } 
    
    ※ このソースから引用 > http://code.msdn.microsoft.com/windowsapps/Windows5-836fb3e1/sourcecode?fileId=100561&pathId=88034978



    biac [ http://bluewatersoft.cocolog-nifty.com/ ]

    • 回答の候補に設定 星 睦美 2013年11月15日 6:52
    • 回答としてマーク JOSIE39 2013年11月18日 2:24
    2013年11月14日 8:19
  • しかしながら…。
    ・ある TextBox をタップ → その TextBox の IsReadOnly を False に
    ということならば、タップすれば編集できるのですから、IsReadOnly を True にしておく意味が分かりません。

    ひょっとして、本当にやりたいことは、「フォーカスがあるテキストボックスの背景色を変えたい」のではありませんか?

    それならば、システムが持っている TextBox のスタイル定義をコピーして、変更してしまえばよいです。
    以下 VS 2012 で説明します。

    TextBox を配置しているテンプレートを編集状態にします。
    メニュー [表示]-[その他のウィンドウ]-[ドキュメント アウトライン] で、ドキュメント アウトラインを開きます。
    ドキュメント アウトラインで TextBox を右クリックし、[テンプレートの編集]-[コピーして編集...]を選びます(次の画像)。

    出てきたダイアログで、適当に設定します。プロジェクト全体で使えるようにするには、定義先を [アプリケーション] にします。

    コピーされたスタイル定義を次のように修正すれば、TextBox の背景色が、フォーカスの無い時は暗い赤、フォーカスがあるときは明るい緑になります。

        <Style x:Key="TextBoxStyle1" TargetType="TextBox">
          ……省略……
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="TextBox">
                <Grid>
                  ……省略……
                  <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                      ……省略……
                      <VisualState x:Name="Normal">
                        <Storyboard>
                          <DoubleAnimation Duration="0" To="{StaticResource TextControlBackgroundThemeOpacity}"
                                           Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundElement"/>
                          <DoubleAnimation Duration="0" To="{StaticResource TextControlBorderThemeOpacity}" 
                                           Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BorderElement"/>
    
                          <!-- ↓追加 -->
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" 
                                                         Storyboard.TargetName="BackgroundElement">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="#884444"/>
                          </ObjectAnimationUsingKeyFrames>
    
                        </Storyboard>
                      </VisualState>
                      ……省略……
    
                      <!--<VisualState x:Name="Focused"/>-->
                      <!-- ↓変更 -->
                      <VisualState x:Name="Focused">
                        <Storyboard>
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" 
                                                         Storyboard.TargetName="BackgroundElement">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="#bbffcc"/>
                          </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                      </VisualState>
                    </VisualStateGroup>
    
                    ……省略……
                  </VisualStateManager.VisualStateGroups>
                  ……省略……
                </Grid>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
    

    biac [ http://bluewatersoft.cocolog-nifty.com/ ]

    • 回答としてマーク JOSIE39 2014年2月28日 6:22
    2013年12月1日 11:10

すべての返信

  • > DataTemplate の Grid 内の TextBox にアクセスするには、どのようにしたらよいのかよく分かりません

    ここ↑が一番悩んでおられるところでしょうね。
    VisualTreeHelperを使えば、Grid コントロール内に配置されているコントロールを探し出すことができます。

    > Grid のTappedイベントで処理しようとしています

    そのイベント ハンドラーでは Grid コントロールを取得できますね(第1引数)。
    あとは、VisualTreeHelperを使って、Grid コントロールの子ども (クラスの継承関係ではなくて、ビジュアル ツリーの親子関係) の中から目的のコントロールを探しだしてやります。
    たとえば、子どもの中から特定のコントロールで最初に見つかったものを取得するなら、次のようなメソッドが使えます。今回の場合ですと、T には TextBox を、引数 parent には Grid コントロールを指定してやります。

        // 指定されたコントロールの子から、特定の型で最初に見つかったものを返す 
        private T FindFirstControlByType<T>(DependencyObject parent) 
          where T : DependencyObject 
        { 
          int childrenCount = VisualTreeHelper.GetChildrenCount(parent); 
          if (childrenCount == 0) 
            return null; 
     
          for (int i = 0; i < childrenCount; i++) 
          { 
            DependencyObject child = VisualTreeHelper.GetChild(parent, i); 
            if (child is T) //←検索条件を変えるにはココを修正する
              return child as T; 
     
            var grandchild = FindFirstControlByType<T>(child); 
            if (grandchild != null) 
              return grandchild; 
          } 
     
          return null; 
        } 
    
    ※ このソースから引用 > http://code.msdn.microsoft.com/windowsapps/Windows5-836fb3e1/sourcecode?fileId=100561&pathId=88034978



    biac [ http://bluewatersoft.cocolog-nifty.com/ ]

    • 回答の候補に設定 星 睦美 2013年11月15日 6:52
    • 回答としてマーク JOSIE39 2013年11月18日 2:24
    2013年11月14日 8:19
  • 速攻、アドバイスをありがとうこ゛ざいます。正にご指摘の事で困っておりました。大変、大変助かりました。ありがとうございます。

    理屈がまだよく分かってないので試行錯誤の最中につき、このようにサクサク、アドバイスを頂けた時の有り難い気持ちは言葉で表せません。ありがとうございました。

    ところで、もう1点教えて頂けないでしょうか。
    DataTamplate の中には、TextBlock と TextBox が混在していて、TextBox は複数、存在し、デフォルトは読み取り専用です。
    ユーザー操作の点から考えると、ユーザーは入力したい箇所(=TextBox) をタップすると思います。
    しかし、コード上、TextBoxのTappedイベントは補足できません。代わりに親の Grid の Tappedイベントが補足されます。
      (そのため、Grid の中からTextBox を探し出そうと悩んでおりました)

    ご教示頂いた方法で、TextBox を探し出す事は可能になりました。
    が、じつは、もう1つ、「どのTextBoxをタップされたか」を知りたいのです。Grid の情報から、それを知る方法はあるのでしょうか。
    Tapped イベントの TappedRoutedEventArgs e から、 GetPosition を取得できます。これと何かを組み合わせれば、「どの TextBox をタップされたか」知る事ができそうな気もするのですが、何か他に上手い方法をご存知ではありませんか?

    もし、ご存知でしたら、厚かましいお願いですが、教えて頂けないでしょぅか。どうかよろしくお願いいたします。

    • 回答としてマーク JOSIE39 2013年11月18日 2:24
    • 回答としてマークされていない JOSIE39 2013年11月18日 2:24
    2013年11月14日 8:53
  • JOSIE39 さん、こんにちは
    フォーラム オペレーターの星 睦美です。

    biac さんからの回答が参考になったようですね。役立つ回答には、MSDN フォーラムがより活発なユーザー同士の情報交換の場になるように投稿者からの[回答としてマーク]をお願いします。

    追加の質問がありますが、最初の質問が解決されている場合には新しい質問として投稿いただくほうが回答者の目にとまりやすくなりますのでおすすめします。

    それでは今後ともMSDN フォーラムをお役立てください。


    フォーラム オペレーター 星 睦美 - MSDN Community Support


    • 編集済み 星 睦美 2013年11月15日 7:18 改行
    2013年11月15日 7:18
  • 星 様

    すみません、了解いたしました。

    2013年11月18日 2:23
  • 気付くのが遅れて、すみません。

    すみません、私が勘違いしてしまったのですが、
    ・画面のどこかをタップ → 特定の TextBox の IsReadOnly を False に
    ではなくて、
    ・ある TextBox をタップ → その TextBox の IsReadOnly を False に
    なのですね。

    それならば、テンプレートの中であっても、GotFocus イベントが利用できると思います。

    private void textBox_GotFocus(object sender, RoutedEventArgs e)
    {
      var textBox = sender as TextBox;
      if (textBox != null)
        textBox.IsReadOnly = false;
    }
    
    private void textBox_LostFocus(object sender, RoutedEventArgs e)
    {
      var textBox = sender as TextBox;
      if (textBox != null)
        textBox.IsReadOnly = true;
    }
    


    biac [ http://bluewatersoft.cocolog-nifty.com/ ]

    2013年12月1日 9:45
  • しかしながら…。
    ・ある TextBox をタップ → その TextBox の IsReadOnly を False に
    ということならば、タップすれば編集できるのですから、IsReadOnly を True にしておく意味が分かりません。

    ひょっとして、本当にやりたいことは、「フォーカスがあるテキストボックスの背景色を変えたい」のではありませんか?

    それならば、システムが持っている TextBox のスタイル定義をコピーして、変更してしまえばよいです。
    以下 VS 2012 で説明します。

    TextBox を配置しているテンプレートを編集状態にします。
    メニュー [表示]-[その他のウィンドウ]-[ドキュメント アウトライン] で、ドキュメント アウトラインを開きます。
    ドキュメント アウトラインで TextBox を右クリックし、[テンプレートの編集]-[コピーして編集...]を選びます(次の画像)。

    出てきたダイアログで、適当に設定します。プロジェクト全体で使えるようにするには、定義先を [アプリケーション] にします。

    コピーされたスタイル定義を次のように修正すれば、TextBox の背景色が、フォーカスの無い時は暗い赤、フォーカスがあるときは明るい緑になります。

        <Style x:Key="TextBoxStyle1" TargetType="TextBox">
          ……省略……
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="TextBox">
                <Grid>
                  ……省略……
                  <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                      ……省略……
                      <VisualState x:Name="Normal">
                        <Storyboard>
                          <DoubleAnimation Duration="0" To="{StaticResource TextControlBackgroundThemeOpacity}"
                                           Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundElement"/>
                          <DoubleAnimation Duration="0" To="{StaticResource TextControlBorderThemeOpacity}" 
                                           Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BorderElement"/>
    
                          <!-- ↓追加 -->
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" 
                                                         Storyboard.TargetName="BackgroundElement">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="#884444"/>
                          </ObjectAnimationUsingKeyFrames>
    
                        </Storyboard>
                      </VisualState>
                      ……省略……
    
                      <!--<VisualState x:Name="Focused"/>-->
                      <!-- ↓変更 -->
                      <VisualState x:Name="Focused">
                        <Storyboard>
                          <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" 
                                                         Storyboard.TargetName="BackgroundElement">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="#bbffcc"/>
                          </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                      </VisualState>
                    </VisualStateGroup>
    
                    ……省略……
                  </VisualStateManager.VisualStateGroups>
                  ……省略……
                </Grid>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
    

    biac [ http://bluewatersoft.cocolog-nifty.com/ ]

    • 回答としてマーク JOSIE39 2014年2月28日 6:22
    2013年12月1日 11:10
  • ブルーウオーターソフト 様

    せっかくご回答くださったのに、無視した状態にしてしまい、申し訳ありません。

    正に、私がやりたかったことの直球回答です。
    このような丁寧な解決策を教えて頂きながら、3ヶ月も音沙汰なしの状況にしてしまい、大変、本当に申し訳ありませんでした。

    解決したのかしてないのか、何の返信もせずに3ヶ月。。。Windowsストアアプリ開発に戻ってきたので、また教えてくださいとは無視の良い話となりますね。どのような結果であれ、質問がクローズするまで、きちんとアクセスして確認していきます。

    申し訳ありませんでした。丁寧なアドバイスをありがとうございました。このまま参考にさせて頂きます。

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

    2014年2月28日 6:22