Master-Detail Display with Sorting - wpf

I have looked at ~15 threads on this topic, none of which seem to address my problem.
I have two tables in a strongly typed dataset. One is a list of Categories with primary key CategoryID. The second is a list of Items with the foreign key the same CategoryID. In my dataset, I define the relationship betweeen the two tables as relCtoI.
My wpf form contains a listbox listing the categories and a listbox that is to display those items from the category listbox category that the user picks. Both listboxs are to be sorted by name.
My pseudo-XAML looks like this:
<Window.Resources>
<CollectionViewSource x:Key="cvsCategories"
Source="{Binding Source={StaticResource MyDataSet}, Path=Categories}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="CategoryName" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<CollectionViewSource x:Key="cvsItems"
....Same thing for the Items with Path=Items ...
</CollectionViewSource>
<DataTemplate x:Key="myTemplate"
<TextBlock Text="{Binding Source={StaticResource cvsItems}, Path=ItemName}" />
</DataTemplate>
</Window.Resources>
<Grid DataContext="{StaticResource cvsCategories}">
<....define columns />
<ListBox Name="lbxCategories"
Grid.Column="0"
ItemsSource="{Binding}"
DisplayMemberPath="CategoryName" />
<ListBox Name="lbxItems"
Grid.Column="1"
ItemsSource="{Binding Path=relCtoI}"
ItemTemplate="{StaticResource myTemplate}"/>
The Category listbox works fine but the Item listbox is blank. What is wrong with my XAML?

Related

WPF TextBox Binding to SQL Table Column

This is for a WPF application with VS2010.
I have a SQL database in EquipmentTracker.mdf.
I have a table called EquipmentData.
This table contains a Column named Manufacturer.
<Window.Resources>
<my:EquipmentTrackerDataSet x:Key="equipmentTrackerDataSet" />
<CollectionViewSource x:Key="equipmentDataViewSource" Source="{Binding Path=EquipmentData, Source={StaticResource equipmentTrackerDataSet}}" />
</Window.Resources>
<TextBox DataContext="{Binding Source={StaticResource equipmentTrackerDataSet}, Path=EquipmentData/Manufacturer}" />
But when I run the application, the TextBox is still blank(empty).
What am I missing here?
Tried this way too...same result; blank TextBox:
<TextBox DataContext="{Binding Source={StaticResource equipmentTrackerDataSet}}" Text="{Binding Path=EquipmentData/Manufacturer}" />
I would still be interested in knowing why it would not display the value when bound directly to the table, but when I created a VIEW and bound to it, it appears to work as I had expected.
<TextBox DataContext="{Binding Source={StaticResource equipmentDataViewSource}}" Text="{Binding Path=Manufacturer}" />

CollectionViewSource: TreeView not updating, ViewModel looking good

I'm trying to populate a TreeView in a TestExplorerControl:
I never had to use a CollectionViewSource until now, so I used this tutorial to get a grasp of how to group my ObservableCollection<TestMethod> in XAML, and use that grouping for my tree view - I implemented the data templates in the <UserControl.Resources>, because I want the flexibility to eventually allow the user change the way tests are regrouped:
<CollectionViewSource x:Key="OutcomeGroupViewSource" Source="{Binding Model.Tests}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Result.Outcome" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
<DataTemplate x:Key="TestMethodTemplate" DataType="{x:Type local:TestMethod}">
<StackPanel Orientation="Horizontal">
<Image .../>
<TextBlock .../>
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="OutcomeTemplate" DataType="{x:Type CollectionViewGroup}"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource TestMethodTemplate}">
<StackPanel Orientation="Horizontal">
<Image ../>
<TextBlock ../>
<TextBlock ../>
</StackPanel>
</HierarchicalDataTemplate>
Then I have this markup for the actual <TreeView>:
<TreeView Grid.Row="2"
ItemsSource="{Binding Source={StaticResource OutcomeGroupViewSource}, Path=View.Groups}"
ItemTemplate="{StaticResource OutcomeTemplate}" />
What's wrong with this markup, for the TreeView to fail updating? The ViewModel clearly has all the data I need to display (the breakpoint that was hit is on the current line, in yellow):
Found it. It's the Path of the ItemsSource binding in the tree view:
ItemsSource="{Binding Source={StaticResource OutcomeGroupViewSource}, Path=View.Groups}"
Path=View.Groups satisfies IntelliSense, but is wrong.
It needs to be Path=Groups, even if the designer supposedly can't resolve the property:

How can I bind and sort a collection

If I have an unsorted collection, is there an easy way to bind and sort it. I would like to do it in XAML (no Linq, no C#)
If my DataContext has a property, say, MyItems, it is easy to bind against it:
<ListBox ItemsSource={Binding MyItems}/>
However, I'd like to sort it as well. Using the CollectionViewSource should be the solution but it does not work for me:
<ListBox>
<ListBox.ItemsSource>
<Binding>
<Binding.Source>
<CollectionViewSource Source={Binding MyItems}/>
</Binding.Source>
</Binding>
</ListBox.ItemsSource>
</ListBox>
At this point, my ListBox loses its elements.
Am I missing something obvious?
You can define the CollectionViewSource as a resource and provide your desired sorting...
<Window.Resources>
<CollectionViewSource x:Key="cvs" Source="{Binding MyItems}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="MyItemName" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}"/>
</Grid>
The scm namespace is xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
Create a CollectionViewSource in the CodeBehind which reads from MyItems, and bind your ListBox to that
<ListBox ItemsSource="{Binding MyCollectionViewSource"} />
Neither of the other answers actually address sorting. They are both right about a CollectionViewSource, but you can use that to do the sorting, with CollectionViewSource.SortDescription. Taken from here and modified:
<Window.Resources>
<src:MyItems x:Key="MyItems"/>
<CollectionViewSource Source="{StaticResource MyItems}" x:Key="cvs">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="CityName"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}"
DisplayMemberPath="CityName" Name="lb">
<ListBox.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ListBox.GroupStyle>
</ListBox>
In this example,CityName would be the property on each item in MyItems used to do the sorting

WPF ComboBox "option group (optGroup)" type behaviour

I want to have a wpf combobox that displays the dropdown list box with the options grouped under a heading like the <optgroup> behaviour in html. Has anyone seem something like this done before?
See How to: Sort and Group Data Using a View in XAML. You apply a grouping to the CollectionView for your data and then set the GroupStyle on the ComboBox. Done entirely XAML, it would look like this:
<StackPanel>
<StackPanel.Resources>
<CollectionViewSource x:Key="groupedData" Source="{Binding}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Length"/>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</StackPanel.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource groupedData}}">
<ItemsControl.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ItemsControl.GroupStyle>
</ComboBox>
</StackPanel>
Or you could apply the grouping in code:
this.DataContext = new List<string>() { "foo", "barr", "baz", "fizz" };
var cv = CollectionViewSource.GetDefaultView(this.DataContext);
cv.GroupDescriptions.Add(new PropertyGroupDescription("Length"));
And use the default collection view in Xaml:
<ComboBox ItemsSource="{Binding}">
<ItemsControl.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ItemsControl.GroupStyle>
</ComboBox>
You could customize the look of the grouped data by providing a custom GroupStyle with your own HeaderTemplate.

Databinding 2 WPF ComboBoxes to 1 source without being "linked"

I have a master-detail scenario where I have 1 ComboBox listing companies from an ObjectDataSourceProvider. Under that I have 2 ComboBoxes binding to the Contacts property from the current Company object. I need to be able to select a different contact in each ComboBox; however, as soon as I change selection in one list the other list updates to the same contact.
I have tried different settings (OneWay vs. TwoWay) but so far nothing seems to work. Here is an excerpt of my XAML.
<Page.Resources>
<!-- This is a custom class inheriting from ObjectDataProvider -->
<wg:CustomersDataProvider x:Key="CompanyDataList" />
</Page.Resources>
<Grid>
<!--- other layout XAML removed -->
<ComboBox x:Name="Customer" Width="150"
ItemsSource="{Binding Source={StaticResource CompanyDataList},Path=Companies,Mode=OneWay}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
IsSynchronizedWithCurrentItem="True"
SelectedValue="{Binding Path=Id, Mode=OneWay}"
VerticalAlignment="Bottom" />
<ComboBox x:Name="PrimaryContact" Width="150"
DataContext="{Binding ElementName=Customer,Path=Items,Mode=OneWay}"
ItemsSource="{Binding Path=Contacts,Mode=OneWay}"
DisplayMemberPath="FullName"
SelectedValuePath="Id"
IsSynchronizedWithCurrentItem="True"
SelectedValue="{Binding Path=Id,Mode=OneWay}" />
<ComboBox x:Name="AdminContact" Width="150"
DataContext="{Binding ElementName=OwnerCustomer,Path=Items,Mode=OneWay}"
ItemsSource="{Binding Path=Contacts,Mode=OneWay}"
DisplayMemberPath="FullName"
SelectedValuePath="Id"
IsSynchronizedWithCurrentItem="True"
SelectedValue="{Binding Path=Id,Mode=OneWay}" />
<!--- other layout XAML removed -->
</Grid>
I thought that creating a CollectionViewSource would be the way to go, but I have not been able to make that work. Is there a simple way to do this so the PrimaryContact and AdminContact aren't linked?
Change your "IsSynchronizedWithCurrentItem" attributes to "False".

Categories

Resources