CompositeCollection breaks ComboBox AutoComplete-Feature? - wpf

push
Hello everybody!
I'm using a WPF ComboBox with IsTextSearchEnabled="True" (Autocomplete) and want to bind its ItemsSource-Property to a CompositeCollection. Unfortunately, the Combobox doesn't seem to recognize the items provided by a CollectionContainer within the CompositeCollection. They are shown, but not selected by AutoComplete.
Please try the example, type in "def". If "def" doesn't get selected, you've reproduced the problem I'm facing. Is there any solution, something that I've overseen or a practical way to work around while having some mergedcollection-capability?
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<XmlDataProvider x:Key="XData1" XPath="/Info">
<x:XData>
<Info xmlns="">
<Item>def</Item>
<Item>efg</Item>
</Info>
</x:XData>
</XmlDataProvider>
<CollectionViewSource x:Key='Data1' Source="{Binding Source={StaticResource XData1}, XPath=Item}" />
</Window.Resources>
<Grid>
<ComboBox IsEditable="True" IsTextSearchEnabled="True" Margin="0,0,0,283">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem>abc</ComboBoxItem>
<ComboBoxItem>bcd</ComboBoxItem>
<ComboBoxItem>cde</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={StaticResource Data1}}" />
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>
</Grid>
Thanks!
- dartrax

I've found out that this is solved as soon as you override the ToString()-Function of your Items-object, so that it returns what the items DataTemplate shows.
A complete working example is here:
--------> X
dartrax

Related

WPF XAML defined MenuItem reuse starts working, then disappears

The following simple code attempts to reuse a MenuItem defined in the Window.Resources on two separate Menus.
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<collections:ArrayList x:Key="menuItemValues">
<MenuItem Header="First"/>
<MenuItem Header="Second"/>
<MenuItem Header="Third"/>
</collections:ArrayList>
<MenuItem x:Key="menuItem" x:Shared="False"
ItemsSource="{StaticResource menuItemValues}"
Header="Shared menu item"/>
</Window.Resources>
<StackPanel>
<Menu HorizontalAlignment="Left" VerticalAlignment="Top">
<StaticResource ResourceKey="menuItem"/>
<StaticResource ResourceKey="menuItem"/>
</Menu>
</StackPanel>
</Window>
This starts out great and when you first select the menus, all looks well. The first menu has the desired MenuItems,
So does the second:
But when you navigate back to the first menu, the MenuItems disappear:
Can someone explain why the menu disappears and a way to get this to work?
This was discovered while investigating another SO question that was getting an exception. I tried to use a strategy discussed on another SO question and it seemed to solve the problem until you navigate back to the menu a second time and it disappears.
I have reproduced this issue on 2 separate machines:
Win 10, VS2013 Ult V12.0.40629.00 Update 5, .NET V4.6.0138
Win 7, VS2013 Prem V12.0.31101.00 Update 4, .NET V4.5.51209
This is happening because, while the top-level MenuItem is x:Shared="False", the MenuItem objects in your collection are not. They are declared once each in the ArrayList collection, and then reused in each instance of the menuItem object that's created.
To get the code to work, you'll need to force WPF to create new instances. One option would be to apply the x:Shared="False" to the collection as well. For example:
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<collections:ArrayList x:Key="menuItemValues" x:Shared="False">
<MenuItem Header="First"/>
<MenuItem Header="Second"/>
<MenuItem Header="Third"/>
</collections:ArrayList>
<MenuItem x:Key="menuItem" x:Shared="False"
ItemsSource="{StaticResource menuItemValues}"
Header="Shared menu item"/>
</Window.Resources>
<StackPanel>
<Menu HorizontalAlignment="Left" VerticalAlignment="Top">
<StaticResource ResourceKey="menuItem"/>
<StaticResource ResourceKey="menuItem"/>
</Menu>
</StackPanel>
</Window>
Of course, given that the items are simply given Header values, you could just use the default MenuItem templating behavior, by providing string values instead of MenuItem values. This allows you to reuse the collection itself (which has no underlying inability for reuse):
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<collections:ArrayList x:Key="menuItemValues">
<s:String>First</s:String>
<s:String>Second</s:String>
<s:String>Third</s:String>
</collections:ArrayList>
<MenuItem x:Key="menuItem" x:Shared="False"
ItemsSource="{StaticResource menuItemValues}"
Header="Shared menu item"/>
</Window.Resources>
<StackPanel>
<Menu HorizontalAlignment="Left" VerticalAlignment="Top">
<StaticResource ResourceKey="menuItem"/>
<StaticResource ResourceKey="menuItem"/>
</Menu>
</StackPanel>
</Window>

Binding to a new IENumerable declared in XAML NOT CodeBehind

The XAML below is incorrect, but it represents what I'm trying to do. I'm fairly new to WPF, but I want to know if something like this doable without instead declaring the instance in the code behind?
<ListBox Name="lbInstalledFonts" VerticalContentAlignment="Center" DisplayMemberPath="Name" ItemsSource="{Binding Source={new System.Drawing.Text.InstalledFontCollection().Familes}}" />
To elaborate, I only need the list of System.Drawing.Text.InstalledFontCollection().Familes for this ListBox. That's it. So I was thinking I could do it entirely through the XAML in a similar way to how you could bind to a DataSource in ASP.NET (through the use of <% and %> in the aspx/ascx files)? Is this at all possible? I did some searching but didn't have much luck.
Yes, it is possible:
<Window x:Class="HelpStackOverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:drawing="clr-namespace:System.Drawing.Text;assembly=System.Drawing"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<drawing:InstalledFontCollection x:Key="InstalledFontCollection" />
</Window.Resources>
<Grid>
<ListBox Name="lbInstalledFonts"
VerticalContentAlignment="Center"
DisplayMemberPath="Name"
ItemsSource="{Binding Source={StaticResource InstalledFontCollection}, Path=Families}" />
</Grid>
</Window>

Problem with static data binding in wpf

I'm relatively new to wpf and I quite don't understand binding yet.
I want to have several combo boxes in my application with the same items. The basic solution would be to copy paste but that just isn't good practice. So I thought to put a static resource with the content I want and bind all combo boxes to it. It compiles and runs well but the combo box is empty.
Here's the code:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ItemsControl x:Key="Validations">
<ItemsControl.Items>
<ComboBoxItem>String</ComboBoxItem>
<ComboBoxItem>Numeric</ComboBoxItem>
</ItemsControl.Items>
</ItemsControl>
and here's the combo box:
<ComboBox ItemsSource="{Binding Source={StaticResource Validations}}"/>
I know the solution for this is probably simple but I haven't figured it out yet. I'll keep trying ;)
Thanks
Make the resource a list of strings, not a visual element, then use the StaticResource extension to assign it to the ItemsSource property, like so:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:ArrayExtension x:Key="Data" Type="{x:Type sys:String}">
<sys:String>String1</sys:String>
<sys:String>String2</sys:String>
<sys:String>String3</sys:String>
</x:ArrayExtension>
</Window.Resources>
<Grid>
<StackPanel>
<ComboBox ItemsSource="{StaticResource Data}"/>
<ComboBox ItemsSource="{StaticResource Data}"/>
<ComboBox ItemsSource="{StaticResource Data}"/>
</StackPanel>
</Grid>
</Window>
Note the definition of the xmlns:sys namespace (maps to namespace System in assembly mscorlib) and the use of the x:ArrayExtension element to declare a simply array in XAML.

Converter problem with XmlDataProvider

Sorry for this, I've just started programming with wpf. I can't seem to figure out why the following xaml displays "System.Xml.XmlElement" instead of the actual xml node content. This is displayed 5 times in the listbox whenever I run it. Not sure where I'm going wrong...
<Window x:Class="TestBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<XmlDataProvider x:Key="myXmlSource" XPath="/root">
<x:XData>
<root xmlns="">
<name>Steve</name>
<name>Arthur</name>
<name>Sidney</name>
<name>Billy</name>
<name>Steven</name>
</root>
</x:XData>
</XmlDataProvider>
<DataTemplate x:Key="shmooga">
<TextBlock Text="{Binding}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemTemplate="{StaticResource shmooga}"
ItemsSource="{Binding Source={StaticResource myXmlSource}, XPath=name}">
</ListBox>
</Grid>
</Window>
Any help would be very much appreciated. Thanks!
Your ItemsSource Binding is returning the collection of 'name' elements. These are of type XmlElement. This is done because it allows bindings to get at other properties of the XmlElement, but means that if you textually display the result of the binding then you get System.Xml.XmlElement rather than the textual content.
To get the textual content, add an additional XPath to your ItemTemplate binding to specify that the TextBlock.Text property should bind specifically to the text of the element, not the element object itself:
<DataTemplate x:Key="shmooga">
<TextBlock Text="{Binding XPath=text()}"/> <!-- Note XPath on Binding -->
</DataTemplate>

WPF ListBox ItemsSource StaticResource/Binding question

Given the following code:
<Window x:Class="WpfApplication76.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<CollectionViewSource x:Key="myCol">
<CollectionViewSource.Source>
<col:ArrayList>
<ListBoxItem>Uno</ListBoxItem>
<ListBoxItem>Dos</ListBoxItem>
<ListBoxItem>Tres</ListBoxItem>
</col:ArrayList>
</CollectionViewSource.Source>
</CollectionViewSource>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{StaticResource myCol}" />
<ListBox ItemsSource="{Binding Source={StaticResource myCol}}" />
</Grid>
</Window>
In this example, the
<ListBox ItemsSource="{StaticResource myCol}" />
Gives me an error complaining that it cannot bind to a "CollectionViewSource" object.
But the other listbox:
<ListBox ItemsSource="{Binding Source={StaticResource myCol}}" />
binds perfectly fine.
So my question is why does one work and the other one does not? AT the end, aren't both ItenSources being set to the same "CollectionViewSource" object?
Thank you.
The ItemsSource property is of type IEnumerable. A CollectionViewSource is not an IEnumerable. CollectionViewSource's View property will give you an IEnumerable.
When you Bind to a CollectionViewSource the Binding is smart enough to grab the View property and actually bind to that. Maybe CollectionViewSource has a [DefaultBindingProperty] on it.
It boils down to the fact that when you go through the Binding you don't actually bind to the CollectionViewSource, but its View property.

Resources