How can I set the keyboard focus to the content of a ContentPresenter when it changes? - wpf

I have a ContentControl in my view which is databound to the CurrentItem property of my viewmodel. The objects that are exposed via CurrentItem each has its own DataTemplate.
When the CurrentItem property changes, the appropriate DataTemplate for that item is displayed, as it should be. However, I cannot find out a way to set the keyboard focus to the content of the DataTemplate.
Even if I manually set the keyboard focus to the DataTemplate, if the CurrentItem property changes (and a new Template is instantiated) the focus is lost (FocusManager.GetFocussedElement returns null).
How can I set the keyboard focus to the content of the ContentPresenter when it changes?

I believe you can use the LayoutUpdated event on either your ContentControl or the ContentPresenter. This should fire anytime the Content/ContentTemplate/etc changes.
Alternatively, you could derive a class from ContentControl then override the OnContentChanged, OnContentTemplateChanged, etc methods. Then you'd need to search down the visual tree and set the focus. You may need to use the Dispatcher to delay the focus setting code.

Related

Fire an event when a property dependency in another user control changes

I have a custom treeview inside a user control. It exposes a dependency property that represents the currently selected treeviewitem. In the same window i have another user control that should change content of it's controls when the selected item changes. I need to do this changes from code behind. How do i fire up an event in the second user control when the selected item changes in the first one?
As the Dependency property whose change you want to be notified about is one created by yourself, why don't you register a PropertyChangedCallback for that property in your user control? This way, you can add a SelectedItemChanged event to the control and raise it from the PropertyChangedCallback code.
Any object that needs to know when the selectedItem has changed just has to listen to this new event.

UserControls: What am I missing?

I have created what I call a "LabeledTextBoxWithLookupControl" which inherits from UserControl. I've put several of these controls on a form.
Now I'm beginning to think that this was a bad idea.
When I call TopLevelControl.SelectNextControl(this, true, true, true, true) from a KeyPress event assigned to the TextBox in the UserControl, it's actually selecting the next UserControl, where I actually want it to select the text box inside the next user control. The UserControl's CanSelect property returns true, but I don't see any easy way to change a UserControl's Control Style.
Also, when I use the Tab Order mode, I'd prefer it not consider the user control itself, but the the just the TextBox in inside the UserControl as candidate for tab order. Should I override the TabIndex and TabStop properties of the UserControl and make them point to the TabIndex and TabStop of the TextBox?
Also, should I expose just the properties of the controls themselves, or should I expose each control as a property to set these properties I want to be able to set, such as the Text property of the label control, the click event of the LookupControl and the Text property of the TextBox.
If you don't want the UserControl to be a tab stop but rather it's contents, you have to make sure that it doesn't have the ControlStyles.Selectable style.
In the constructor of your UserControl add:
SetStyle(ControlStyles.Selectable, false);

How to set a value in a ViewModel from binding?

Kind of an odd question- if I'm thinking of this the wrong way please let me know. I am using an infragistics dock manager, which manages tabs as well. So I can create a TabGroupPane, and then add multiple ContentPanes, each of which has its own tab.
In each content pane, I set my viewmodel:
<ContentPane>
<viewmodels:MyViewModelForTab1 />
</ContentPane>
So here's the problem- while using a mediator pattern for communication, my viewmodels have no idea if they are on the visible tab or not, so they are always working even if hidden. The TabGroupPane does have a SelectedTab property, as well as each ContentPane having an IsActive property.
So the question is how do I set that information in my ViewModel? Making my VM a dependency object seems like a bad idea since I already implement INotifyPropertyChanged. Using a CLR prop in my VM also doesnt work, since you cannot bind to it.
How can I get my VM to know if it is the datacontext of an active tab?
Thanks!
I would put an IsSelected property on my ViewModel and bind it to the TabItem's IsSelected dependency property.
This should allow you to hook into when it is updated and perform whatever you need. You don't need a mediator pattern here since you are communicatining from the View to the ViewModel.
Make sure your ViewModel is bound to the DataContext property of the view (specifically, that the Tab's DataContext is the ViewModel). The way you have it now, your ViewModel is the content of the element, not bound to the DataContext, as it should be:
<Tab.Resources>
<viewmodels:MyViewModelForTab1 x:Key="Tab1ViewModel" />
</Tab.Resources>
<ContentPane DataContext="{StaticResource Tab1ViewModel}" />
Or something like that...
I don't know the Infragistics model, so my apologies if this is inapposite, but here's how I implement this with regular items controls - tab control, list box, whatever.
Create a container view model class that includes an observable collection of items and exposes a SelectedItem property. Make the container class the data context of the items control. Bind the items control's SelectedItem property to the container class's.
Hook the item objects up to the PropertyChanged event of the container. So now when the selected item in the UI changes, the container view model notifies all of the items that SelectedItem has changed. Each item object's event handler can determine for itself whether or not it's now the selected item.
The item objects thus don't know any implementation details of the UI - you can unit test your classes outside of a UI and the logic will still work correctly.

WPF: Detect when selected item changes

I have a control that is data-bound to a ListBox. All of the bound properties are being updated correctly. However, the control needs to know when the selected item changes so that it can do some other cleanup. Is there an event that covers this?
You can also bind to the SelectedItem property, say with ICollectionView.CurrentItem, and set the IsSynchronizedWithCurrentItem property to True.
There is SelectionChanged event in ListBox.

How do I BringToView the latest item added to a bound ObservableCollection

I have a silverlight control (View) which displays a list of items in a specified property of the datacontext (viewmodel).
What I need is for the scrollviewer in my control to scroll to the top or bottom depending on where the latest item has been added to the list. (It'll always be either the beginning or the end of the list, I don't need to worry about middle of list insertions.)
In WPF i'd just use the DataContextChanged event to start listening to the viewmodel, but in silverlight that event is internal.
Any ideas on how to tackle this?
A good starting point is Attached Behaviors on CodeProject.
A useful behavior would watch the ListBox.ItemsSource and attach to the observable collection when set. On the collection changed event, use ListBox.ScrollIntoView to display the changed item.
I can't use the CollectionChangedEvent of ObservableCollection since I need the DataContextChanged event to get the DataContext which holds the Collection in the first place.
Would you not do this in the ViewModel?
Whatever ViewModel has the ObservableCollection, expose a property of type T named SelectedItem and whenever the ObservableCollection changes with a new item, the CollectionChanged event will allow you to set the SelectedItem property. Once this is done, wire up the SelectedItem in the control to this property on your ViewModel.
This will obviously only work with controls like ListBox where a SelectedItem property exists.
In place of DataContextChanged in WPF , you can use CollectionChanged event of ObservableCollection. In the collection changed you will get to know the NewItem Index.

Resources