Tricky WPF styling issue - can you do it? - wpf

I have an observable collection of items, where each item has a name and a "group name" (both strings).
The tricky part is, in XAML, I need to style this collection such that all items with the same group name are listed next to each other, and the group name is shown at the top.
I have designed user controls for the layout of the group name, as well as the layout of each item being displayed. I have played around with ItemsControl but have no idea how to style it so that items with the same group are somehow "merged" into the same ItemsControl that uses the generic ItemControl user control as its source, with the group name displayed on top.
I did have this working by using a collection of "groups", with a collection of items inside each group, because the bindings work perfectly. However, I did not take into account that each item may be in more than one group (think of a person as being in a "work friends" as well as "colleagues" group, so it needs to be duplicated).
Any advice or solutions are much appreciated :)

First, use a CollectionViewSource to sort the items:
<CollectionViewSource x:Key="SortedItems" Source="{Binding YourUnsortedItems}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="GroupName"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Then bind to it from your ItemsControl (or whatever):
<ItemsControl Source="{Binding Source={StaticResource SortedItems}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- stick your template for each item here -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

Which tool is the best option for doing search in Datagrid in wpf?

I have created search option using combobox, for example
In combobox1 items are m1,m2,m3,m4,m5 based on that, if m1 item selected then
another combobox2 displays with items a,b,c,d and if a item is selected another
combobox3 dispalys, based on last combobox it searches on the datagrid.
I think it is long process, use of many combobox makes it lenghty. Is any
other way is their to implement this. plz help
<ComboBox Grid.Column="1"
Grid.Row="1"
x:Name="cmbType"
VerticalAlignment="Top"
IsEnabled="{Binding IsOther}"
ItemsSource="{Binding Source={StaticResource enumTypeOfType}}"
SelectedItem="{Binding SearchType,Mode=TwoWay}"
SelectedIndex="{Binding CmdResIndex,Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True"
SelectionChanged="DataSource1"
Margin="0,0,1,0">
</ComboBox>
So if i get this right, you have a collection a, which goes to collection b,etc, and the second collection will change based on the selected item of the first? You have to remember, that since the data will change for each selection, hard coding the value is out of the question.
Knowing this, WPF provides you with a great mechanism for this. Using a stackpanel, with a list view will actually work.
<ItemsControl ItemsSource="{binding collections}" ItemTemplate="{binding TemplateForListViewItems}" ItemPanelTemplate="{binding itemPanelTemplate}"></ItemsControl>
Now, with the items control, one can simply set an ItemTemplate/DataTemplate, to set the styling of each control. Linking to the onclick event, or using interactions, you can simply do collections.Add to add your new list view with generated data for the selection, and done.

How does wpf/databinding resolve this ambiguity?

<StackPanel DataContext="{StaticResource Employees1}">
<ListBox ItemsSource="{Binding}" DisplayMemberPath="Name"
IsSynchronizedWithCurrentItem="True"/>
<Label Content="{Binding Path=Count}"/>
<Label Content="{Binding Path=Name}"/>
</StackPanel>
How does the binding for the labels get resolved? How is it decided that the content of the second label is bound to Employees1.Count (and not to Employee.Count), while the first label is bound to
Employee.Name and synchonized with the listbox selection? Also, what if I would like to bind the first label to Employee.Count instead?
(Employee has properties Name (and possibly Count), Employees1 is an ObservableCollection of type Employee).
EDIT: So, the question here is WHY the first label displays the number of employees in the ObservableCollection, while the second label displays the name of a specific employee in the collection, the one that is currently selected in the ListBox. Apparently, the first label binds to the entire collection, and the second label to a specific employee in the collection. But why, and how to control this behavior.
From MSDN Data Binding Overview, Binding To Collections, section "Current Item Pointer":
Because WPF binds to a collection only by using a view (either a view
you specify, or the collection's default view), all bindings to
collections have a current item pointer.
and section "Master-Detail Binding Scenario":
This works because when a singleton object (the ContentControl in this
case) is bound to a collection view, it automatically binds to the
CurrentItem of the view.
In your example, the second Label automatically binds to the current item of the default view of the Employees1 collection. The first Label would also bind like this, but since the item object does not have a Count property it apparently falls back to a binding to the Count property of the collection itself. However i don't know if the latter behaviour is documented somewhere.
As Blam says - the labels have no relationship to the listbox - I think what you're trying to do here is bind an observableCollection of Employees with properties Count and Name to the listbox..
To do this you'll need an ItemsTemplate in the listbox
<ListBox ItemSource={Binding Employees1}>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Count}" />
<Label Content="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Let me try and answer the questions.
An ObservableCollection has a property Count.
As for getting a single property on the second label it is making some assumptions.
You might not get the same behavior in other version of .NET.
Should not bind a control that displays a single value to a collection.
If you want the selected item from the ListBox see this link
enter link description here

ToggleButtons in ItemsControl bound to an ObservableCollection

First of all i want to excuse my English.
What i want to achieve looks very simple but i'm a bit lost in the implementation.
Background: I have an ObservableCollection of Contacts. these contacts all have 1 or more ContactRoles. I bind the contacts to the itemssource of an ItemsControl and want a ToggleButton for every role in the contact to be displayed.
Question: My first question is how can i go from a list of contacts with roles to a lot of ToggleButtons on screen. The second question i have is If i click one ToggleButton all other buttons that have the same contact need to be checked as well. If i click another togglebutton which belong to another contact all checked buttons needs to be unchecked and the buttons belonging to the new contact needs to be checked.
What do i have now: What i have now is an itemscontrol in an itemscontrol and the internal itemscontrol it's itemtemplate is printing the ToggleButtons look an the code below:
<Button Content="Add" Width="72" Height="27" Command="{Binding Path=AddContact}" VerticalAlignment="Top"/>
<ItemsControl ItemsSource="{Binding Path=Contacts}" IsTabStop="False" Name="Parent">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding ContactRoles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Content="{Binding}" CommandParameter="{Binding ElementName=Parent, Path=DataContext.Item}" Template="{StaticResource toggleButtonTemplateButtonBar}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ViewContact}" Height="27" MinWidth="100">
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This part of the code is showing.
I hope someone can help me with this.
Some other questions i have is Do i need to make a Custom Control that inherits from ItemsControl or can this be done by templates and styles?
I you need more information let me know.
Thanks, Jordy
EDIT:
I'm sorry i was not so clear with formulating my questions. to come back on you comment. The ItemsSource of the first ItemsControl hold a list with unique contacts, the ItemsSource of the second hold a list of strings (roles) that belong to this contact. I want to show an ToggleButton for each role of all contacts. But i think you've guested that from my codeexample.
This image will show what i'm trying to do.
I hope this makes thing more clear.
As Snowbear said please provide more inputs... From your questions I see ...
My first question is how can i go from a list of contacts with roles
to a lot of ToggleButtons on screen.
What do you mean by GO? Are you asking that how are Contacts or Contact.Roles tranformed into ToggleButtons? Then that is what your ItemTemplate is doing. If you are asking that you want some property or data from Contact object to be held by the toggle button then you have already used Binding in your ItemTemplate.
<ToggleButton Content="{Binding}" Tag="{Binding Roles}">
</ToggleButton>
In the above example, Tag which is one of the non-visual properties of FrameworkElements in WPF, is bound to the list of Roles from the corresponding Contact object.
The second question i have is If i click one ToggleButton all other
buttons that have the same contact need to be checked as well.
Are you saying that in your list of Contacts some Contact object is added multiple times in the list? If so that is a bad design and may cause blunders while using ItemsSource. If no, then this statement of yours all other buttons that have the **same contact** is confusing. Do you mean that you have Contacts which may repeat but they are not the same object by reference. Probably they share by some identifying value e.g. they have same Contact.Name or Contact.ID etc.
If some identifying value of contact is what is same among different contact objects then you will have to intelligently use the SelectedValue binding.
If i click another togglebutton which belong to another contact all
checked buttons needs to be unchecked and the buttons belonging to the
new contact needs to be checked.
Again this is possible once you decide what are you really trying to do i.e. are you adding same Contact object multiple time or you have different Contact objects having some value common.
Do i need to make a Custom Control that inherits from
ItemsControl or can this be done by templates and styles?
in WPF, ANYTHING can be achieved using common templates and styles. They definitely eliminate need for creating a custom control for various visually similar looking controls.
BUT if you control has a behavior or functionality that you need to perform exactly the same in multiple places and you want it sealed and to limit itself performing that specific function, then creating a custom control makes sense.
So please rephrase your question and provide clearer inputs.

Can I databind to properties of a custom class (instantiated in xaml) that then forms the content of a templated listboxitem

Any help on this really appreciated. In summary I'm trying to databind to properties of a custom class instantiated in xaml that then forms the content of a templated listboxitem (phew!).
I have a simple c# class called MenuItem. It has two properties:
- Heading
- Icon
Concentrating on just one of those menu items (i.e. to provide a simple example of where I am stuck) If I do this (with the values hard coded) it works fine:
<ListBox>
<ListBoxItem ContentTemplate="{StaticResource MenuItemTemplate}">
<myclasses:MenuItem Heading="News" IconImage="News.png"/>
</ListBoxItem>
</Listbox>
Where MenuItemTemplate is an appropriate DataTemplate in the resources section binding each property) containing lines such as:
<TextBlock x:Name="tbHeading" Text="{Binding Heading}">
Wheareas when I try to use binding to set the Heading property it falls over (AG_E_PARSER_BAD_PROPERTY_VALUE error)- e.g.:
<ListBox>
<ListBoxItem ContentTemplate="{StaticResource MenuItemTemplate}">
<myclasses:MenuItem Heading="{Binding NewsHeading, Mode=OneWay}" Icon="News.png"/>
</ListBoxItem>
<Listbox>
I've wondered if it is because I'm doing some kind of double binding (i.e. the template is binding to a value on the MenuItem class that needs to be bound) and that's not possible? I've tried having the properties declared as dependency properties but no difference (although I only learned about those today so I may be missing something).
I know I could set the menuitem objects up in the view model, and bind from there, but I would like to understand why the above doesn't work (as for my purposes there are advantages in constructing the menu items in the xaml).
Thank you!!!!
Ian
thanks for sticking with this. I agree the listbox might not be needed - but even if I reduce it to just one item in a contentcontrol:
<ContentControl ContentTemplate="{StaticResource MenuItemTemplate}">
<myclasses:MenuItem Heading="{Binding NewsHeading, Mode=OneWay}" IconImage="News.png"/>
</ContentControl>
I still have the same problem - which is that I can get databinding to work within the content of a contentcontrol (prior to it being presented by the datatemplate referred to in ContentTemplate) using purely xaml.
I.e. the above bit of xaml doesn't work - it throws an error on the bit that binds the NewsHeading:
Heading="{Binding NewsHeading, Mode=OneWay}
So I am trying to understand whether what I'm doing is impossible, or whether it is but I'm doing it wrong.
Thanks.
Assuming that you have multiple MenuItem classes (because you're putting them in a listbox and ti wouldn't make sense to do that if you just had one). You need to bind the collection to the ItemsSource property of the ListBox.
Somehting like this:
<ListBox ItemsSource="{Binding MyMenuItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Heading}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note that the above assumes you've set the DataContext on the page to an object with a property called MyMenuItems which is a collection of your MenuItem objects.
To see a full example of this, look at the default code created when you create a new "Windows Phone Databound Application".
Edit:
Based on your comments, it seems that a ListBox is not the most appropriate solution to your needs. A ListBox is designed/intended to take a collection of items and display them in a list.
If you have a number of different objects which you know about at design time and simply wish to have them one on top of another (giving the appearance of a list) you could simply put them inside a ScrollViewer and/or a StackPanel (or other appropriate container). Plus, you would still be able to databind if you did it this way.

Silverlight: Datagrid like grouping in ItemsControl

Is it possible to group items in a ItemsControl or Listbox in Silverlight? These controls are bound to a DomainDataSource.
Or are there any 3rd party controls that do this?
UPDATE:
This is the sort of UI I am trying to create.
You can do this by using nested ItemsControls bound to a PagedCollectionView.
Say I have a datasource - MyItems - with fields: Category, Section and Option. I can create a PagedCollectionView from an IEnumerable(of MyItems) and tell it which fields to group by.
Dim original As IEnumerable(Of MyItems) = GetMyItems()
Dim pcv = New PagedCollectionView(original)
pcv.GroupDescriptions.Add(New PropertyGroupDescription("Category"))
pcv.GroupDescriptions.Add(New PropertyGroupDescription("Section"))
Then I bind my first ItemsControl to the PagedCollectionView
hisMyItems.ItemsSource = pcv.Groups
The PCV creates a nested hierachy like:
-Name
-Items
where Name is the value in the grouped field and Items contains the rows/objects in that grouping. I guess you could also create the PCV in xaml if you prefer.
The xaml would look something like:
<controls:HeaderedItemsControl x:Name="hisMyItems" Header="{Binding Name}" ItemsSource="{Binding Items}" >
<controls:HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<controls:HeaderedItemsControl Header="{Binding Name}" ItemsSource="{Binding Items}" ItemsPanel="{StaticResource ItemsPanelTemplate1}" >
<controls:HeaderedItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Option}" />
</DataTemplate>
</controls:HeaderedItemsControl.ItemTemplate>
</controls:HeaderedItemsControl>
</DataTemplate>
</controls:HeaderedItemsControl.ItemTemplate>
</controls:HeaderedItemsControl>
I hope that makes sense. I have tried to simplify things from my actual app but I could have made some mistakes in copying it over. Obviously you could use normal ItemsControls or other controls too and customize with templates etc.
The DataGrid control supports grouping.
Tim Heuer has a good blog on grouping with a datagrid.
link text
Perhaps the control you are really looking for is the Accordian Control from the Toolkit.
See sample of Accordian behaviour here.
Note that the actual appearance is as style-able as any other control. The basic function is to group categories of items that would otherwise be a straight-forward List.

Resources