简体   繁体   中英

Initial focus on the ItemsControl - DataTemplate

I have a WPF window where I am displaying some locations info. The locations are coming from a BindingList ( AvailableLocations ) and are displayed using DataTemplate inside a ScrollViewer . Below is my xaml code.

<Border Margin="0" Background="White">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="Title" FontSize="14" FontWeight="Bold" Margin="10"/>
            <Button Content="X" HorizontalAlignment="Right" MinWidth="0" Grid.Column="1" Command="{Binding CancelCommand}" Margin="2.5" />
        </Grid>
        <Border Margin="10,0,10,10" BorderBrush="Black" BorderThickness="0.5" Grid.Row="1"  Background="GhostWhite">
            <ScrollViewer VerticalScrollBarVisibility="Auto" Margin="0,2.5,2.5,2.5"  IsTabStop="False" Focusable="False">
                <ItemsControl ItemsSource="{Binding AvailableLocations}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Button Content="{Binding Description}" Margin="0, 10" MinWidth="200">
                                <Button.Template>
                                    <ControlTemplate TargetType="Button">
                                        <Border x:Name="Border" Width="{TemplateBinding Width}"
                                        Height="{TemplateBinding Height}"
                                        Background="{TemplateBinding Background}"
                                        BorderBrush="Gray"
                                        BorderThickness="1">
                                            <Label x:Name="Content"  Content="{TemplateBinding Content}"
                                           FontWeight="{TemplateBinding FontWeight}"
                                           FontSize="{TemplateBinding FontSize}"/>
                                        </Border>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="IsMouseOver" Value="True">
                                                <Setter Property="Background" Value="LightGreen" TargetName="Border"/>
                                                <Setter Property="Cursor" Value="Hand"/>
                                            </Trigger>
                                            <Trigger Property="IsPressed" Value="True">
                                                <Setter Property="Background" Value="LightGreen" TargetName="Border"/>
                                                <Setter Property="BorderThickness" Value="2" TargetName="Border"/>
                                                <Setter Property="BorderBrush" Value="DarkGreen" TargetName="Border"/>
                                                <Setter Property="FontWeight" Value="SemiBold" TargetName="Content"/>
                                                <Setter Property="Cursor" Value="Hand"/>
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Button.Template>
                            </Button>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </ScrollViewer>
        </Border>
        <Button Name="btnCancel" Content="_Cancel" Command="{Binding CancelCommand}" IsCancel="True" Grid.Row="2"  Margin="10" HorizontalAlignment="right"  MinWidth="70"/>
    </Grid>

</Border>

And my ViewModel and and Model are as follows

class Window2ViewModel
{
    public BindingList<Location> AvailableLocations { get; private set; }
    public Window2ViewModel()
    {
        IList<Location> locations = new List<Location>()
        {
            new Location(){Description ="Desc 1"},
            new Location(){Description ="Desc 2"},
            new Location(){Description ="Desc 3"},
            new Location(){Description ="Desc 4"},
            new Location(){Description ="Desc 5"},
        };

        AvailableLocations = new BindingList<Location>(locations);
    }
}
public class Location
{
    public string Description { get; set; }
    public double LocationCD { get; set; }
    public string LocationType { get; set; }
    public double LocationTypeCd { get; set; }
    public string LocationTypeMean { get; set; }
    public double OrganizationID { get; set; }

} 

I am facing 2 issues here.

  1. When I do tabbing the focus goes to the container of the available locations items and I want to restrict that. I want the location fields and the button to be tababble, not to the container controls. I tried setting the IsTabStop="False" Focusable="False" to the ScrollViewer but that does not work.
  2. I want the initial focus of the window to be on the first location field (Desc 1 in this case). I know that for a window level control this can be done by FocusManager ( FocusManager.FocusedElement="{Binding ElementName=controlName} . But I don't know how can it be done for items inside DataTemplate .

Hope you folks understand the problems I am facing and any help on this will be highly appreciated.

Thanks in advance

After doing a lots of trial and error I realized that the focus is going to neither the Border nor the ScrollViewer elements. The focus actually goes to the ItemsControl element. So setting the IsTabStop = False to the ItemsControl resolved my first issue.

For initial focus to the DataTemplate item, I could not find any direct fixes. But using the following code I was able to bring the focus on the first element inside my DataTemplate.

Loaded += (s, e) =>
              {
                  foreach (var item in itemCtrl.Items)
                  {
                      UIElement uiElement =
                          (UIElement)itemCtrl.ItemContainerGenerator.ContainerFromItem(item);
                      if (uiElement != null)
                      {
                          if (uiElement is ContentPresenter)
                          {
                              ContentPresenter c = (uiElement as ContentPresenter);
                              Button b = c.ContentTemplate.FindName("btn", c) as Button;

                              Dispatcher.BeginInvoke(new Action(() =>
                              {
                                  b.Focus();
                              }), DispatcherPriority.Normal);

                              return;
                          }
                      }
                  }
              };

I am not so sure whether the above can be done directly inside xaml. Hope somebody will find a more appropriate solution. For the time being, the above fix is working for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM