0

So i am build simple Clipboard manager. Every ListViewItem come from Clipboard.GetText and my application minimize to Tray and when double click on its Icon the application jump and i want to focus become on the first ListViewItem in order to be able to navigate with Up & Down arrows.

This is my ListView:

ListView myListView;

Model List:

public ObservableCollection<string> Clipboards

Window Loaded event:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        if (viewModel.Clipboards.Count != 0)
            myListView.ScrollIntoView(myListView.Items[0]);
        myListView.Focus();
     }

So currently when i open int the first time the application, the Focus is not on any ListViewItem and in the next time the focus is on the last selected/click ListViewItem and not on the first one.

user979033
  • 5,430
  • 7
  • 32
  • 50
  • Have you tried using [Focus Manager](https://stackoverflow.com/a/21891179/2029607) for this? Also if the ListView is bound to a ViewModel then you could control if there is anything selected without handling the code behind or relying on puny loaded events. – XAMlMAX Jan 02 '19 at 09:10
  • Can i have simple code example of what you talking ? – user979033 Jan 02 '19 at 11:35
  • Sure. ``. – XAMlMAX Jan 02 '19 at 12:49

2 Answers2

1

It looks like you have your ViewModel in the code behind. This is not good MVVM standard.

Maybe this could be helpful How can I set the focus to a ListBox properly on load if it uses databinding?

Bjorn
  • 181
  • 2
  • 11
-1

From what I see you are not focusing any ListViewItem but the ListView itself. I think this is your mistake. To focus the item you have to get it's container. The objects in the ItemsSource are actually the data itself and no the UIElement to render. To draw this data or add it to the visual tree for rendering, the ItemsControl will generate a container for the data e.g. a ListViewItem. Only the UIElement can receive focus, that's why the UIElement exposes the Focus() method. You have to use the ItemContainerGenarator to retrieve this container for your data:

  ListView myListView;
  (myListView.ItemsPanel as VirtualizingPanel)?.BringIndexIntoViewPublic(0);
  myListView.Dispatcher.Invoke(new Action(
    () => 
    {
      ListBoxItem dataContainer = myListView.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
      dataContainer?.Focus();
    }), DispatcherPriority.ContextIdle);

This example will move the focus to the first element in the ListView.

  • That wouldn't (or possibly wouldn't) work if you are using virtualization (which is the default) since containers get destroyed when scrolled out of view and you'll get a null exception. You'd have to scroll item 0 into view first, then wait for the container to be generated. Only then can you set focus to it. – SledgeHammer Jan 02 '19 at 18:56
  • This time you are right. When virtualization is used we have to take care that the requested item container is generated before we can access it. This time your comment has some value. This is how we do it. That's professional behavior. –  Jan 02 '19 at 21:00
  • Yeah, feels like you are stalking me. I am that guy that you are trying to tell to manage my controls from within the view model and that code-behind free files are mandatory to MVVM. But no problem. –  Jan 02 '19 at 21:10
  • oh.. I didn't pay attention to the name... and no, that's not what I said at all... you were too busy going on your rant to read I guess lol... but yes, I'll stick to my statement about the 2nd part... if you are using code behind you aren't packaging stuff correctly. It's simply not needed and its poor design to split the logic. I'll also stick to my other point about your approach being bad since you are tightly coupling a bunch of things. But hey... you work at BMW, so what do I know lol... – SledgeHammer Jan 02 '19 at 21:21
  • Btw, your fixed code still won't work since containers are generated asynchronously. All your code will do now is nothing since all the null checks will fail. – SledgeHammer Jan 02 '19 at 21:22