1
votes

I'm trying to send a Control as a ComandParamter so that I can set focus on it. These controls are in a GridViewColumn HeaderTemplate and tabbing cannot go across headers as far as I can tell. My research has led me to utilize x:reference because ElementName fails due to naming scope. The command is properly bound, it does run when I don't bind a CommandParameter.

With the binding shown in xaml below, I receive this error:

Attempt to reference named object(s) 'resourcetypeSrch' which have not yet been defined. Forward references, or references to objects that contain forward references, are not supported on directives other than Key.

How can I bind the ComboBox with x:Name resourcetypeSrch to the TextBox KeyBinding CommandParameter?

<GridViewColumn DisplayMemberBinding="{Binding Name }">
    <GridViewColumn.HeaderTemplate>
        <DataTemplate>
            <DockPanel>
                <TextBlock Text="{StaticResource Name}" />
                <TextBox Text="{Binding DataContext.Foo, RelativeSource={RelativeSource AncestorType=Page}}"                                             
                         Style="{StaticResource SearchBox }" Width="200">
                    <TextBox.InputBindings>
                        <KeyBinding Key="Tab" 
                                    Command="{Binding DataContext.SearchNavigationCmd, RelativeSource={RelativeSource AncestorType=Page}}"
                                    CommandParameter="{Binding {x:Reference resourcetypeSrch}}"/>
                    </TextBox.InputBindings>

                </TextBox>
            </DockPanel>
        </DataTemplate>
    </GridViewColumn.HeaderTemplate>
</GridViewColumn>

<GridViewColumn Width="350" DisplayMemberBinding="{Binding ResourceTypeLookup.TypeName }">
    <GridViewColumn.HeaderTemplate>
        <DataTemplate>
            <DockPanel>
                <TextBlock Text="{StaticResource ResourceType}" />
                <ComboBox x:Name="resourcetypeSrch" Width="300" HorizontalAlignment="Left" IsSynchronizedWithCurrentItem="True"
                      ItemsSource="{Binding DataContext.SrchResourceTypeLookups, RelativeSource={RelativeSource AncestorType=Page}, Mode=OneTime}" 
                      DisplayMemberPath="TypeName"
                      SelectedValuePath="Bar"
                      SelectedValue="{Binding DataContext.Fizz, RelativeSource={RelativeSource AncestorType=Page}}" >
                </ComboBox>
            </DockPanel>
        </DataTemplate>
    </GridViewColumn.HeaderTemplate>
</GridViewColumn>
3
<KeyBinding Key="Tab" Command="{Binding DataContext.SearchNavigationCmd, RelativeSource={RelativeSource AncestorType=Page}}" CommandParameter="Binding DataContext.SrchResourceTypeLookups, RelativeSource={RelativeSource AncestorType=Page}, Mode=OneTime}"/>? - StepUp

3 Answers

0
votes

I believe you want to be able to tab navigate through controls in headers of the grid. What you can do to achieve this is create a property in your dataSource for each column (i.e. Column1IsFocused, Column2IsFocused).

Then you can create an extension to focus your control (for example here is one) from viewmodel. You will bind the property IsFocused of your extension to each of properties from dataSource and then in the Command handler you just set one or the other property to true. I believe this might work.

0
votes

I just thought about another posibility. You can just traverse the visual tree in the command handler method and find your control by name. Here is a nice implementation of a method that goes through VisualTree of an object and looks for a control with specified method:

public static T FindChild<T>(DependencyObject parent, string childName)
   where T : DependencyObject
{    
  // Confirm parent and childName are valid. 
  if (parent == null) return null;

  T foundChild = null;

  int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
  for (int i = 0; i < childrenCount; i++)
  {
    var child = VisualTreeHelper.GetChild(parent, i);
    // If the child is not of the request child type child
    T childType = child as T;
    if (childType == null)
    {
      // recursively drill down the tree
      foundChild = FindChild<T>(child, childName);

      // If the child is found, break so we do not overwrite the found child. 
      if (foundChild != null) break;
    }
    else if (!string.IsNullOrEmpty(childName))
    {
      var frameworkElement = child as FrameworkElement;
      // If the child's name is set for search
      if (frameworkElement != null && frameworkElement.Name == childName)
      {
        // if the child's name is of the request name
        foundChild = (T)child;
        break;
      }
    }
    else
    {
      // child element found.
      foundChild = (T)child;
      break;
    }
  }

  return foundChild;
}

So in your command you just need to do:

FindChild<ComboBox>(ListView, "resourcetypeSrch")

Substitute "ListView" with name of any control that is parent to the data you are looking.

0
votes

You need to use RelativeSource binding for your CommandParameter in KeyBinding:

<KeyBinding Key="Tab" 
        Command="{Binding DataContext.SearchNavigationCmd, RelativeSource={RelativeSource AncestorType=Page}}"
        CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"/>

This code will look up the controls tree until it finds the control of type ComboBox. In your particular case the first ComboBox it's going to find is going to be the one you need.