WPF schema - what defines a ListBox to have a ScrollViewer? - wpf

For years, I have felt I don't have a good understanding of WPF because I haven't found an authoritative reference on the possibilities. For example, I just found out that a ListBox has an attached ScrollViewer property.
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Auto">
Other than reading a book or article that tells that, how would I know that ScrollViewer is a valid attached property? Is there a XAML schema document or something? How does Visual Studio Designer know?

ScrollViewer isn't an attached property; it's a class.
ScrollViewer.HorizontalScrollBarVisibility is an attached property. But it's not an attached property that ListBox "has"; it's an attached property that can be attached to any DependencyObject at all, including ListBox.
Here's what you see if you right click on ScrollViewer.SetHorizontalScrollBarVisibility and ScrollViewer.GetHorizontalScrollBarVisibility. A pair of static methods like this is required for an attached property. The first parameter is the thing you're attaching the property to. It doesn't have to be DependencyObject; it could be FrameworkElement, ListBox, ItemsControl, or anything else that can support dependency properties.
// Summary:
// Sets the value of the System.Windows.Controls.ScrollViewer.HorizontalScrollBarVisibility
// dependency property to a given element.
//
// Parameters:
// element:
// The element on which to set the property value.
//
// horizontalScrollBarVisibility:
// The property value to set.
public static void SetHorizontalScrollBarVisibility(DependencyObject element, ScrollBarVisibility horizontalScrollBarVisibility);
//
// Summary:
// Gets the value of the System.Windows.Controls.ScrollViewer.HorizontalScrollBarVisibility
// dependency property from a given element.
//
// Parameters:
// element:
// The element from which the property value is read.
//
// Returns:
// The value of the System.Windows.Controls.ScrollViewer.HorizontalScrollBarVisibility
// dependency property.
public static ScrollBarVisibility GetHorizontalScrollBarVisibility(DependencyObject element);
The ListBox itself quite likely has no clue what ScrollViewer.HorizontalScrollBarVisibility means, or even that it exists. But in the ListBox's template, there's probably a ScrollViewer, which will probably have a binding a lot like this:
<ScrollViewer
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
Put that attached property on any control that might have a ScrollViewer in its template, and if the template was written correctly, the ScrollViewer will use that value.
This is really, really nice because ListBox doesn't have to think about its own scrolling behavior. That's all delegated. Building controls by composition is extremely powerful.
The downside is that the whole thing is just a vast box of undifferentiated barf and it's real hard to make sense out of stuff. Intellisense can't tell you much about the scrolling behavior of ListBox when nobody outside that particular ListBox's template at the moment can even guess what that scrolling behavior might be.
So, in answer to your question: Yes. Basically you just have to read a lot of stuff. And keep a "Cool XAML Tricks" text file to note down cool stuff you hear about that you don't have a use for just yet.
But that's the way this profession has always been. Even with Intellisense, you can't use a class you don't know about.
Today I learned about ColumnDefinition.SharedSizeGroup and Grid.IsSharedSizeScope, and I learned that you can derive value converters from MarkupExtension and give them strongly typed, named properties instead of having to pass some goofy string into CommandParameter.

I believe the best docs we have right now are the MSDN documentation pages for WPF controls. For example, if you look up ListBox, you can find information about the attached ScrollViewer, and also it's full default template.
https://msdn.microsoft.com/en-us/library/cc278062(v=vs.95).aspx

Related

How to avoid the '[Unknown]' property does not point to a DependencyObject in path '(0).(1)[1].(2)' exception in wpf

On button click, Updating the ListBox ItemsSource collection.
For 4 or 5 clicks its working fine but afterwards it throws an exception as '[Unknown]' property does not point to a DependencyObject in path '(0).(1)[1].(2)'
I googled it & find the reason for it.
"The ElementControl overrides PrepareContainerForItemOverride and
calls PrepareModel to insert a mesh into _modelContainer for each
Item. Later in ElementFlow.BuildTargetPropertyPath (which is called
via ElementFlow.SelectItemCore -> LayoutBase.SelectElement ->
ElementFlow.PrepareTemplateStoryboard) it is assumed that such a mesh
has been inserted into _modelContainer. This exception occurs when the
mesh has not been inserted into _modelContainer. WPF calls
PrepareContainerForItemOverride on ApplyTemplate. This is only done
once. Items added later are never processed like that. "
So please provide me a solution to overcome it.
It seems like maybe there is an item in your " itemsource collection" that is not of the right type, or does not contain one of the properties that your listbox itemstemplate is looking for. Or, perhaps if you have different classes in your collection, one of them may not have the property you are looking for as a DependencyProperty. If it is just a plain property, it may not work correctly.
Check all object types that are going into your itemssource collection and make sure they all have DependencyProperties that are named what the itemstemplate is looking for.

Dependency Properties - What's the point of having 2 owners?

If you look at Selector and TabItem classes they apparently both own the IsSelectedProperty.
static Selector()
{
...
IsSelectedProperty = DependencyProperty.RegisterAttached("IsSelected", typeof(bool), typeof(Selector), ...);
...
}
static TabItem()
{
IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(typeof(TabItem), ...);
...
}
So I guess my question is... since the Tabitem contains the actual propertychanged logic, what is the point of the IsSelectedProperty even residing in the Selector class?
In this specific case, Selector has the IsSelected DP because there are a number of controls that derive from it whose items can be selected (ComboBox, ListBox, ListView, TabControl, DataGrid). They all need an ability to mark an item with IsSelected, therefore that DP is declared in their common base class. Like Tim said, DRY.
Another reason that TabItem adds itself as an owner is that in the Selector class, IsSelected is an attached property because you can have just about anything as an item in a Selector. Attached properties are pretty mobile that way.
However, TabItem adds itself as an owner such that it is not an attached property on TabItem. It also registers a callback method to be called when the value changes so that it can do a few things when selected or unselected.
And yes, it is easier to type <TabItem and see IsSelected in Intellisense rather than going, "But how the heck do I make one selected?" and have to hunt around and find that you need to use an attached property from some other class.
It's basically just an instance of DRY (Don't Repeat Yourself). Here's a thread from MSDN forums on the topic:
DependencyProperty.AddOwner - What's the Point

What is the worst gotcha in WPF?

I've started to make myself a list of "WPF gotchas": things that bug me and that I had to write down to remember because I fall for them every time....
Now, I'm pretty sure you all stumbled upon similar situations at one point, and I would like you to share your experience on the subject:
What is the gotcha that gets you all the time? the one you find the most annoying?
(I have a few issues that seem to be without explanation, maybe your submissions will explain them)
Here are a few of my "personnal" gotchas (randomly presented):
For a MouseEvent to be fired even when the click is on the "transparent" background of a control (e.g. a label) and not just on the content (the Text in this case), the control's Background has to be set to "Brushes.Transparent" and not just "null" (default value for a label)
A WPF DataGridCell's DataContext is the RowView to whom the cell belong, not the CellView
When inside a ScrollViewer, a Scrollbar is managed by the scrollviewer itself (i.e. setting properties such as ScrollBar.Value is without effect)
Key.F10 is not fired when you press "F10", instead you get Key.System and you have to go look for e.SystemKey to get the Key.F10
... and now you're on.
Always watch the output window for
binding errors. Ignoring the output
window is a recipe for tears.
Use PresentationTraceOptions.TraceLevel="High" in a binding to get verbose binding information when debugging binding failures.
Make static, unchanging resources such as brushes PresentationOptions:Freeze="True" to save resources at runtime.
Use the WPF DataGrid as a datagrid. Modifying it to behave like Excel is a massive pain in the butt.
BindingList<T> does not play well with CollectionViewSource. Expose ObservableCollection<T> from your viewmodels instead.
The internet supplies half a dozen different ideas for displaying CueBanner text in a WPF textbox. They are all broken.
1) One that used to get me every half an hour when I was making my transition from WinForms: use TextBlock instead of Label when putting random text on the UI (or don't use any tag at all, if the text is static)!
2) DataTriggers/Triggers can't be put into Control.Triggers, but have to go into Control.Styles/Style/Style.Triggers
3) Property's type must implement IList, not IList<T>, if the property is to be recognized by XAML as a collection property.
4) Bindings capture exceptions.
5) Use singleton converters/static converter class, so you don't have to create a new converter every time you use it.
6) A type for default value of DependencyProperty has to be clearly specified: 0u as uint, (float) 0 as float, 0.0 as double...
7) It matters if the control's property definitions are before or after its content.
8) NEVER use PropertyMetadata to set a default value of reference type DependencyProperty. The same object reference will be assigned to all instances of the owning class.
When first starting out, the main gotchas that would get me would be
Lists not updating due to forgetting
to use ObservableCollection
Properties not being updated either
forgetting to add OnPropertyChanged
or incorrectly typing the property
name
Recently I have stumbled across these issues
Application failing to start due to
corrupt font cache
StringFormat localization issues
If enabled, Button.IsCancel assigns false to Window.DialogResult but Button.IsDefault no.
They are so similar and for me it seemed intuitive at first that both should close dialog. I usually break MVVM and fix this in code-behind
Button.IsCancel + Command = Dialog won't close (Window.DialogResult left unassigned) but Command executes
As I understand it: If IsCancel had higher priority than Command then on Esc it would assign 'false' to DialogResult and Command won't be called. Or, if Command would have higher priority then it would be called first and DialogResult would be assigned. I don't understand how it is skipped?
Binding swallows exceptions!
It not only steals time while debugging it is also wrong from the OOP point of view because if exception is thrown it means that something exceptional had happened somewhere in our system (anything from wrong data supply to unauthorized access to memory failure) so it can be handled only if you know what to do. You can't just catch(Exception){} catch 'em all and then ignore. If there is unknown exception in program it should notify user, log and close not pretend like everything is ok...
HeaderContent can have only one child control and has no padding
Everything should have padding even logical controls (containers), right? I think it is inconsistent. What do you think?
If you set focus to ListBox via FocusManager.FocusedElement you still won't be able to switch it's content with keyboard because focus is set to ListBoxes frame not it's content. I think I don't know other UI API that would expose something like controls frame to UI programmer it should be encapsulated from us because abstractly ListBox represents a list, it is just a list of things not a list of things in a box. ok it has box in its name but still... We almost have two different controls here.
MVVM not breaking fix
ListBox.IsSynchronizedWithCurrentItem by default is false so if you assign different value or null to ItesSource then SelectedItem still holds old value until user selects something from a new list. It could mess up CanExecute for example. Need to set it every time by hand.
No binding exposed in PasswordBox results in time waste and dirty hacks... But still it has a string property PasswordBox.Password exposed so don't even try to argue about security because Snoop...
It is not a gotcha but table layout is so IE6 IMO. Container design helps separate content from its layout.
Because every time I need to change something in places I need to mess up with Grid.Row and Grid.Column. Yes, we have DockPanel, StackPanel and others but you can't do some column alignment inside of them. (And DockPanel is like completely separate gotcha) If UniformGrid would be more customizable it would be ideal I think. You always need to choose between Grid and Panels and usually if you gain something you loose something else.
I got a pretty nifty one last week:
When Templating a RichTextBox, the event handling inside the template follows a strange route that has nothing to do neither with tunnelling nor bubbling
e.g.: In the case of an event that is supposed to tunnel: the event first tunnels through the ContentPresenter, then it tunnels back from the top of the template.
see my question on the subject
ToolTips and ContextMenus not sharing the DataContext of its owner? I think that gets everyone at first
There is no clean way to handle validation in WPF, I am not a fan of magic string which IDataErrorInfo offers by default:
public string this[string columnName]
{
if (columnName == "FirstName")
{
if (string.IsNullOrEmpty(FirstName))
result = "Please enter a First Name";
}
}
However, I have tried many frameworks like SimpleMVVM, FluentValidation and MVVMValidation and BY FAR MVVM Validation is the best getting to do stuff like:
Validator.AddRule(() => RangeStart,
() => RangeEnd,
() => RuleResult.Assert(RangeEnd > RangeStart, "RangeEnd must be grater than RangeStart");
My personal favorite is this one:
public double MyVariable
{
get { return (double)GetValue(MyVariableProperty); }
set { SetValue(MyVariableProperty, value); }
}
public static readonly DependencyProperty MyVariableProperty = DependencyProperty.Register(
"MyVariable", typeof(double), typeof(MyControl), new UIPropertyMetadata(0));
Try it, once this property is declared it will crash. Why? Because 0 can't be assigned to a double using reflection apparently.
Not really a gotcha but an advice: Use Snoop or something similar, if you don't use it you must be crazy ... Crazy i tell ya!
Binding.StringFormat only works if the type of the target property is string.
TreeView's SelectedItem property is not settable. Instead you have to bind TreeViewItem's IsSelected property to your item's viewmodel and set your selection there.
ListBox's SelectedItem, on the other hand is settable, but item selection is not equal to item focus. If you want to implement proper keyboard navigation along with selecting items from within viewmodel, you have to implement manual focus fix, like:
public void FixListboxFocus()
{
if (lbFiles.SelectedItem != null)
{
lbFiles.ScrollIntoView(lbFiles.SelectedItem);
lbFiles.UpdateLayout();
var item = lbFiles.ItemContainerGenerator.ContainerFromItem(viewModel.SelectedFile);
if (item != null && item is ListBoxItem listBoxItem && !listBoxItem.IsFocused)
listBoxItem.Focus();
}
}
...and call it every time you change selected item from viewmodel:
SelectedFile = files.FirstOrDefault();
viewAccess.FixListboxFocus();

How can an AttachedProperty have multiple values?

How can an AttachedProperty which is a single property defined by an owning parent element, be set with multiple values through several child elements of that parent?
For example:
If I have:
<DockPanel>
<CheckBox DockPanel.Dock="Top">Hello</CheckBox>
<CheckBox DockPanel.Dock="Bottom">World</CheckBox>
</DockPanel>
Here we have a single DockPanel element and it has a single Dock property. How can it be set to "Top" and then "Bottom" simultaneously?
It will end up in a method looking like this
public class DockPanel : Panel
{
public static readonly DependencyProperty DockProperty;
// ...
public static void SetDock(UIElement element, Dock dock)
{
element.SetValue(DockProperty, value);
}
}
As you can see, it's actually not set on the parent, but the CheckBox itself, through the static method SetDock on DockPanel and not the parent instance. Doing it in code behind makes this a little clearer, notice how we never use an instance of a DockPanel.
DockPanel.SetDock(checkBox1, Dock.Top);
DockPanel.SetDock(checkBox2, Dock.Bottom);
Hopefully this was clear, unless your question was how this works "under the hood". In that case, see this question.
Quote from link.
The purpose for this mechanism is to
"attach" to other objects information
needed by parent objects, not the
child objects themselves.
A CheckBox has no use for a Dock property unless it is in a DockPanel. Same goes for Grid.Row, Canvas.Left, Validation.HasError (read only) etc. So basically, the DockPanel is the one needing the information, but it needs all its childs to be able to store it. Hence, it's using an Attached Property for it. If you created a new Panel, called PuneetPanel, and you needed an Angel to calculate the child position, then you could define your own Attached Property, PuneetPanel.Angel inside this panel and all childs could use this without having to be subclassed.
This is a very nice question. The answer lies in how the AttchedProperty works. The AttachedProperty is used by the parent to render a child. Before rendering the child, the parent looks out for any attached property defined on child and applies to the child.
I found this from msdn which might be useful for you ::
DockPanel defines the DockPanel.Dock attached property, and DockPanel has class-level code as part of its rendering logic (specifically, MeasureOverride and ArrangeOverride). A DockPanel instance will always check to see whether any of its immediate child elements have set a value for DockPanel.Dock. If so, those values become input for the rendering logic applied to that particular child element....
You can see this link to get detailed overview ::
http://http://msdn.microsoft.com/en-us/library/ms749011.aspx
Hope it helps you!!
For your own custom attached properties there are two options to achieve what you are looking for:
1. If the number of combinations of settable values are not to complex you could make your attached property of type enum that has the FlagsAttribute set. You can the combines the values you want to set using bitwise-or |:
[Flags]
public enum MultiDock
{
Left,
Top,
Right,
Bottom
}
And its usage in code:
MyCustomPanelOrWhatever.SetMultiDock(MultiDock.Left | MultiDock.Bottom);
This has one small proplem though, you can not do the above in xaml directly, you would have to write a MarkupExtension that can convert string to flagged enum values. Its usage would then look like this:
<CheckBox src:MyCustomPanelOrWhatever.MulitDock="{src:FlaggedEnum Left|Bottom}" />
2. Since attached properties can be of any type, they can of course also be complex types (with multiple subproperties) or even collections, so it is easily possible to do something like this:
MyCustomPanelOrWhatever.SetMultiDock(new List<MultiDock> { MultiDock.Left, MultiDock.Bottom });
If you have defined your attached property that way, you do not need any converters for xaml, you can use it directly:
<CheckBox>
<src:MyCustomPanelOrWhatever.MultiDock>
<src:MultiDock.Left/>
<src:MultiDock.Bottom/>
</src:MyCustomPanelOrWhatever.MultiDock>
</CheckBox>

How can I animate a property dynamically in a Silverlight 4 UserControl?

I've run into a puzzling limitation in a Silverlight 4 UserControl.
What I'm trying to achieve is to have a panel, which slides out from a minimised state when a button is pressed, but the title bar of it should be draggable with which this maximised state can be resized.
What I've done for the sliding out is to animate the MaxHeight property of the parent Grid of this panel which works quite well even with no hardcoded Height for the panel, but I don't know how can I make this dynamic.
Trying to bind a variable from the code-behind to the 'To' parameter of the 'DoubleAnimation' didn't work, it just silently gets ignored.
As I'm creating UserControls to represent Views, the elements with x:Name properties won't get autogenerated.
I tried to work around this using the code below which mimics what happens in the autogenerated code (with the added bonus of only being done after the layout is actually loaded):
public DoubleAnimation PanelOpenMaxHeightDoubleAnimation;
private void LayoutRoot_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
var LayoutRootreference = sender as Grid;
PanelOpenMaxHeightDoubleAnimation = ((DoubleAnimation)(LayoutRootreference.FindName("PanelOpenMaxHeightDoubleAnimation")));
PanelOpenMaxHeightDoubleAnimation.To = 383;
}
This however breaks when trying to set the value of To, as FindName returns null (I have x:Name manually set in XAML for this particular animation to "PanelOpenMaxHeightDoubleAnimation"). I have the sneaking suspicion FindName can't pick DoubleAnimations up from VisualStates, only actual layout children?
I did find the documentation about XAML Namescopes at http://msdn.microsoft.com/en-us/library/cc189026(v=VS.95).aspx#UserControls, but didn't really understand what my options are from this paragraph (other than being very limited):
For the case of a UserControl, there is no equivalent template part attribute convention for parts of the UserControl in the definition XAML, nor is there a template applied at all. Nevertheless, the namescopes between definition and usage remain disconnected, because the definition namescope is defined and then effectively sealed when you package your UserControl into an assembly for reuse. A best practice here is to define your UserControl such that any value that needs to be set to modify the definition XAML is also exposed as a public property of the UserControl.
What does it mean by the last sentence?
Wondering can I do next? Should I try to generate the entire state from code?
Well, managed to work it out so I'm sharing the solution.
Instead of trying to get a reference to the DoubleAnimation in Resources, I named the Grid in the layout I want to animate and get a reference to that using the code in the original question:
var SlidePanel = ((Grid)(LayoutRootreference.FindName("SlidePanel")));
This does return the element and using that it's possible to create a DoubleAnimation and a Storyboard from scratch purely in code. I just used this code example as a starting point: http://msdn.microsoft.com/en-us/library/cc189069(VS.95).aspx#procedural_code
Best part is, you can change the DoubleAnimation.To parameter even after setting everything up in the Storyboard, so now what I'm doing is just resetting that to my calculated value every time before calling Storyboard.Begin().
It's a bit fiddly to set all these up manually, but at least it works nicely once you do.

Resources