How to avoid the '[Unknown]' property does not point to a DependencyObject in path '(0).(1)[1].(2)' exception in wpf - 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.

Related

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

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

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();

Binding failures when adding another property

I have a main view that binds to subviews like this (the backing property is of type object):
<ContentControl Content="{Binding WalletsView}"/>
Now, I've added another property to the corresponding viewmodel, namely
public SmartObservableCollection<Selectable<Type>> PriceGrabbers {get; private set;}
where SmartObservableCollection is derived from ObservableCollection to make multithreaded updates easier.
Now I get a lot of binding errors (in fact, all bindings in the sub viewmodels run through the debug window) like this (interestingly, if I remove the PriceGrabbers property again, all errors disappear):
System.Windows.Data Error: 40 : BindingExpression path error: 'OverviewHidden' property not found on 'object' ''MainWindowViewModel' (HashCode=30986197)'. BindingExpression:Path=OverviewHidden; DataItem='MainWindowViewModel' (HashCode=30986197); target element is 'ColumnDefinition' (HashCode=22768693); target property is 'NoTarget' (type 'Object')
So the binding engine apperently tries to find any and all bindings on the main viewmodel.
The bindings work perfectly fine. While this is okay, I'd rather have errors go away. Did anybody of you already encounter this problem, and if yes, how did you solve it?
The problem isn't with WPF but with my usage of MEF as composition container. The property modifies the import order of classes and the ViewModel coresponding to MainWIndow is assigned to all Views first, after which the correct one is assigned. When the data context is refreshed, all bindings are renewed, thus the application works.
edit and now I found the complete reason for it.
SmartObservableCollection takes an Action<Action>> parameter to execute on CollectionChanged events, this is needed due to most of my collections getting updated in a multithreaded manner, but the events have to be executed in the GUI thread, otherwise you will get an exception.
For this, my Views expose Dispatcher.Invoke() and Dispatcher.BeginInvoke() as methods, which I then supply to the collection.
At startup, the DataContexts are assigned in the base class ViewModel by the following lines:
Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate()
{
view.DataContext = this;
});
Who has an idea already?
The reason for this hickup was the simple fact I supplied the Dispatcher.Invoke() method instead of Dispatcher.BeginInvoke() to the collection. By doing this (and the fact it was used in the MainWindowViewModel), it got executed before any DataContexts got assigned to other ViewModels.
Now, the next step occurs - the WPF engine tries to bind to the data in the sub views. As DataContext is null, the binding engine walks up the visual tree until it finds a set DataContext, in this case the first set DataContext is in MainWindowView, and it is MainWindowViewModel. Now, after the collection finished, all other actions get called and the DataContexts are assigned appropiately, thus reexecuting the binding engine which finds a non-null DataContext on the sub views and binds correctly.

InvalidCastException when selection changes in a WPF TreeView

To handle the TreeView.SelectedItemChanged event, I have an attached behavior that binds to a command.
Ordinarily, the RoutedPropertyChangedEventArgs.NewValue property contains a reference to one of my view-model objects, and I can then pass this on as the argument to ICommand.CanExecute and ICommand.Execute. I'm using RelayCommand from here, but I've got a RelayCommand<T> that casts to the expected type.
However, in certain scenarios, RoutedPropertyChangedEventArgs.NewValue contains a TreeViewItem, displayed as {System.Windows.Controls.TreeViewItem Header:{DisconnectedItem} Items.Count:0} in the debugger.
This causes my RelayCommand<T> to throw an InvalidCastException.
Question: what is this mysterious TreeViewItem and where does it come from?
I'm aware that I can avoid the exception by changing RelayCommand<T>.Execute from using (T)value to using value as T, but I'd like to know what the root cause is.
A DisconnectedItem is a TreeViewItem that is no longer in your TreeView (i.e. that has been removed from the tree).
Interesting; do you do anything out of the ordinary with the treeview, as in control templating? Is it the actual built-in treeview or a class that inherits it? It could have something to do with virtualization but it definitely shouldn't happen ordinarily I think.

DomainDataSource, binding and cursors

Databinding in WPF/Silverlight revolves around dependency properties, DataContext objects and DataSource objects. As far as I can tell, dependency properties are the same thing as ambient properties and their significance to binding is basically that if you put a bunch of widgets in a container then you only need to specify a DataContext for the container.
There are several parts to this question.
What is the difference between DataContext and DataSource, and how do they relate?
What manages cursors in WPF/Silverlight databinding? Is there a direct equivalence to the WinForms CurrencyManager and BindingContext?
How do I go about manipulating a Cursor in WPF/Silverlight databinding?
DataGrid seems to have a CurrentItem property. If you bind a bunch of widgets to the various columns of a datasource and they share the same datacontext as the datagrid then interactively moving the selected row in the datagrid changes the row whose values are expressed in the widgets. Could someone please explain to me how it all fits together? Preferably with reference to SL4.
When I do this:
private void buttonNew_Click(object sender, RoutedEventArgs e)
{
Guid newId = Guid.NewGuid();
Employee emp = new Employee() { Id = newId, FirstName = "NOT SET", LastName = "NOT SET" };
AtomDomainContext adc = employeeDomainDataSource.DomainContext as AtomDomainContext;
DomainDataSourceView ddsv = grid1.DataContext as DomainDataSourceView;
}
I get this compilation error:
The type 'System.ComponentModel.IPagedCollectionView' is defined in an assembly
that is not referenced. You must add a reference to assembly 'System.Windows.Data,
Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
D:\Argent\Views\ManageEmployees.xaml.cs, 57, 7, Argent
which sounds easy to fix but when I attempt to add a reference to the Argent project the list of references is empty; presumably one is confined to those assemblies that Silverlight deploys to the target computer. So now what do I do?
I found some answers so in the absence of a useful contribution from anyone else I'll answer my own question.
A DataContext is a kind of cursor object. You assign to the DataContext property any object or IEnumerable collection of objects to which you want to bind, and a wrapper is constructed around it. If you assign an IEnumerable, the DataContext surfaces a CurrentItem property that references one of the elements of the IEnumerable. If you assign something that isn't an IEnumerable, the DataContext wrapper behaves as though it contructs an IEnumerable and adds your object to the collection and then proceeeds as if that was what you passed in the first place, the object being set up as the CurrentItem.
One possible IEnumerable is the DomainDataSource, for which DataSource is a base clase.
Every widget in Silverlight has a DataContext property. Generally you don't set this directly, due to what Microsoft has taken to calling "dependency properties" which as far as I can tell are exactly the same as ambient properties, which is to say that unless you set them explicitly they "inherit" a value from the immediate container, which may in turn so inherit. So instead of setting the same IEnumerable as DataContext on a bunch of widgets, you make them all children of some container and set the DataContext for that, and they all miraculously get bound to the same cursor.
You can create a new DataContext object in XAML simply by explicitly specifying it; this creates a new instance and assigning it to the DataContext property of the widget on which you specify it; this is a new instance, a new cursor that is independent of any other DataContext.
In Silverlight4 you can reference the DataContext in use by another object; see element binding.
But a binding is only partly specified by a DataContext. Having specified a DataContext so that a widget has object foo contributing its context, specifying a binding path of A will look for a property named A on object foo and if this is found will mashall its value to and from your widget.
What's really confusing to the newbie is that while the whole binding can be specified in one spot, normally the context is specified miles away up a big complex container hierarchy, and just the path is specified on each widget, yet for (eg) binding the ItemsSource of a combobox to a lookup table you do specify the whole thing. I hope I've made it all a bit clearer for those following in my footsteps.
As for the location of the elusive 'System.Windows.Data', it's in %ProgramFiles%\Microsoft SDKs\Silverlight\v4.0\Libraries\Client\System.Windows.Data.dll

Resources