I used to have a window with an attached property to track the focused control:
FocusManager.FocusedElement="{Binding CurrentlySelectedTextBox, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
CurrentlySelectedTextBox was a property in the window's viewmodel.
Now my window has a frame. The content of the frame is a page. I moved the original window's content to the page with its own viewmodel. I moved the attached property from the window to the page. Since then the CurrentlySelectedTextBox property is never set.
Long days of searching gave nothing. Are pages immune to FocusManager.FocusedElement?
Update: If the attached property is on the window, FocusManager.FocusedElement gets set even if the focus is on the page's control.
There's a concept of focusscope in wpf which can cause issues like this.
The basic problem is your page is a different focusscope to the window.
Focusscope allows wpf to maintain a logical rather than physical concept of focus for controls such as tabcontrol and menu.
In order to maintain which has logical focus the focusmanager will by default be concerned with the element which has focus within each focusscope.
The behaviour is somewhat configurable but you need to be very careful before altering this as there are side effects.
Related
in several Views we have container components - for example Grid or ScrollViewer- that are bound to a property on their own ViewModel or ViewModelItem.
In some cases the View (parent) containing these components can be shown without the ViewModel/ViewModelItem of the components being initialized. To avoid showing a user empty datagrids we are using FallBackValue=Hidden to make sure the container is only shown when it's ViewModel/ViewModelItem is initialized/loaded.
A hypothetical example would be a Window containing a DataGrid and a more detailed view to the right. The detailed view would be its own UserControl with its own ViewModel and the DataGrid would have its own ViewModel as well. When opening said Window the ViewModel of the DataGrid would be loaded immediately - but since no row has been selected the ViewModel that belongs to the detailed View would not be intialized, which means that the Visibility Binding of the detail View would fail and the binding's FallbackValue would be used to hide the detail View.
The issue with this approach is that the Visual Studio WPF/XAML designer will not show the content of the affected containers since they are hidden due to their FallbackValue.
Question: Is there a way to get the designer to show specific controls/components that have the FallBackValue of a Visibility binding set to Hidden? Clicking into the XAML code that is inside these hidden containers does not show them.
Edit 1
I found this answer. Setting d:IsHidden="false" does not help. Regardless of if it's set before or after the Visibility property.
When it comes to the designer you would have to set the Design Data Context.
To do that you would typically do the following in your xaml file:
<Control, Page or Window
xmlns:vm="clr-namespace:VM.ViewModel"
d:DataContext="{d:DesignInstance {x:Type vm:YourViewModelNameHere}, IsDesignTimeCreatable=True}"
.../>
However, sometimes like in your case, more flexibility is needed for the complex ViewModel. For this I would use Blend and it's functionality, what that is it will generate dummy data for you and set the data context of the Control for you.
For more information refer to this MSDN article.
I've been working to improve scrolling performance for an ItemsControl. Initially each item is a simple row of information and when an item is clicked, a detail UserControl is expanded below the item. I'm trying to eliminate the processing being done on the detail UserControl during scrolling. I eventually achieved this with a CustomControl, but I feel like I must be missing a simpler way to do it using the existing framework controls.
Initially, this detail view was a UserControl with Visibility.Collapsed. I should note that Virtualizing and Recycling are enabled for this ItemsControl. Therefore, scrolling performance was poor since each detail view was being bound to the data as the item scrolled into view, even though the detail was not visible.
I then tried using a ContentPresenter where the Content was bound to a DetailViewModel property and the ContentTemplate was set to a keyed DataTemplate. That DetailViewModel property was initialized to Nothing and then set to the appropriate ViewModel object when the item was clicked. This improved scrolling performance because there was no data binding, but I found that the detail UserControl was still getting constructed for each item, and I presume there was some rendering going on as well.
I eventually got the desired behavior with a custom ContentControl that provides dependency properties for GatedContentTemplate and IsGateOpen. When IsGateOpen goes True, the GatedContentTemplate is passed to the ContentTemplate property and the Content is set to the DataContext of the control, which causes the content to then get constructed, rendered, and bound.
<my:GatedContentControl IsGateOpen="{Binding IsDetailVisible}">
<my:GatedContentControl.GatedContentTemplate>
<DataTemplate>
<my:DetailUserControl/>
</DataTemplate>
</my:GatedContentControl.GatedContentTemplate>
</my:GatedContentControl>
I can live with this solution, but it's a little janky, and I wonder if I'm missing some way that WPF intends for this to be done.
Looks like I wasn't missing anything and this is a need that Microsoft is addressing in .net 4.6.
The Content Deferral feature is discussed in this video, starting at 26:30.
http://channel9.msdn.com/Events/dotnetConf/2015/WPF-in-46-and-beyond
Thanks for the comment HighCore.
I'm wanting to have a tooltip for disabled TabItems in a TabControl. The standard way of putting tooltips onto disabled controls in Silverlight is by wrapping the control in a dummy element that has the tooltip, but I can't get at the TabItem like that. The TabItems' host control is a TabPanel, which doesn't seem to expose any useful properties.
Any ideas?
I had the same problem with putting a Toolip on a disabled menu item, i solved it by changing the VisualState of my menu item to Disabled and then disabling the MouseButton events.
VisualStateManager.GoToState(tabitem, "Disabled", true);
You'll have to be careful with other events though, because the VisualState will change according to different events. It's not a perfect solution, but it will work for certain scenarios.
Hope this helps
My current workaround for my own problem:
I've got a TabControl Behavior that finds the "TabPanelTop" template part (or left, right, or bottom depending on TabStripPlacement), along with the "TemplateTop". I add a Canvas into the TemplateTop (which is a Grid), and fill it with Transparent Rectangles whose positions (using TransformToVisual) and sizes are calculated (and updated) to be the same as the TabItems, which are the children of the TabPanelTop.
The visibility of the Rectangles is bound to the inverse of TabItem IsEnabled, and the ToolTipService.ToolTip is bound to the ToolTipService.ToolTip on the TabItem.
It's a bit scary but it works and is easy to use.
FindAncestor RelativeSource only supports 'Self' and 'TemplatedParent',
but I have to bind the width of a popup to the width of the page.
Giving the page a name causes problems because sometimes it will
throw exceptions saying a control with that name is already present in the visual tree.
<Popup IsOpen="True"
Width="{Binding ElementName=BordPage, Path=Width}"
Height="{Binding ElementName=BordPage, Path=Height}">
Background information:
I'm using a SL4 navigation based application here. BordPage is a navigation page,
which I'm using multiple times within the application. So giving it a name in the page itself is not really a good idea,
but I don't know how else I can bind to the width and height of the page.
What I'm trying to do is have a black border (with opacity 0.8) cover the entire screen,
(including the controls of the MainPage). Then on top of that I want to display some other controls.
Since the application is touch controlled, providing the user with a ComboBox to select a value doesn't really work wel. Instead I want to show this black overlay window with a listbox taking up most of the screen so the user can simply touch the value he wants with a single click.
Update: I just realized I can use the ChildWindow class to do this.
But my original question remains.
My general solution for this problem is by writing a custom behavior. It's not a pure XAML solution but it gives you a lot more flexibility.
Create a behavior that searches up the VisualTree to find the right item and then have it set the width of the Popup correctly.
It may be a little more complicated than a straight binding but it avoids all the naming issues.
Put the following in the constructor of your control so you can avoid naming it:
DataContext = this;
I have a custom text box control which raises a routed event when its TEXT property changes. This text property is data bound to a property on our view-model object.
When I place this control on a TabControl page or Expander control, it appears as if data binding only occurs when the control becomes visible for the first time, therefore I never receive any of the routed events until I swap to the tab the control is on or expand the expander.
Is there any way I can force data binding to occur before the control is shown?
Sounds like you relying on the data binding to genreate the routed event is the wrong approach. Instead you need to have your Model or ViewModel generate an event when the text is modified and then you watch this event from an appropriate place in your View.
Not very likely. WPF is a fairly efficient framework and won't do any work that it doesn't absolutely have to. This includes scenarios like data binding. Why bother exercising a collection for a control that might not ever be shown?