ToggleButtons in ItemsControl bound to an ObservableCollection - wpf

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.

Related

Best way to create a list of selectable and deletable items in Windows Phone 7

I want to solve a seemingly simple task. I want to create a list of text entries where each entry is selectable (and causes navigation to another page) and when the user holds his finger over an item I want a context menu with a single option to delete that item. This is very common pattern in WP applications. For example the browser does this with favourites.
Right now I have a listbox with a textblock in the item template and I start the navigation in the SelectionChanged event:
<ListBox Name="lbSnippets" SelectionChanged="lbSnippets_SelectionChanged">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
I can think of several ways to solve the hold problem but none of them sits well with me. For example I may handle the Hold event on the TextBlock but then I will have to dig for the item related to this TextBlock. Something tells me that there should be a better way to do this as it is so common. What is the right way to solve this task?
The Silverlight toolkit for WP7 includes a ContextMenu control.
You can install the toolkit via nuget: PM> Install-Package SilverlightToolkitWP
Then you an add ContextMenus to basically any control:
<DataTemplate>
<TextBlock Text="{Binding}">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Delete"
Command="{Binding YourDeleteCommand}"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</TextBlock>
</DataTemplate>
Where toolkit is an xml namespace:
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
You can start learning about the ContextMenu control from this article:
WP7 ContextMenu in depth | Part1: key concepts and API

Creating a static view in WPF that won't get initialized every time

I'm working on a WPF application that contains a wrapper UI that is actually the MainWindow.xaml and the content in it (ContentPresenter) gets changed each time the user chooses to move to a different section of the application.
When the user returns to the main content, I want the application not to initialize it each time, but to preserve it in the memory somehow and restore it when the user clicks on the "Home" button.
In its current state, the Home view gets initialized over and over again when moving back to the "Home" section, which causes the application to be kinda slow. My question is this: Is there a way to preserve that user control in the memory somehow so that I would be able to restore it fast?
Thanks!
Hiding is an option ofcourse as #Matt suggested. An other way is to explorer the wonderfull world of frameworks (Prism, Caliburn, Caliburn.Micro, ... )
Those deliver a great assistance in managing WPF applications.
In essence you need to keep a reference to the ViewModel, a collection in the mainviewmodel or mainview that keeps track of the loaded viewmodels.
Eventually I decided to move the ContentControl into an ItemsControl and then just hide all content controls except for the active one.
Here's a snippet of my code:
<ItemsControl ItemsSource="{Binding ViewModels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Visibility="{Binding Visibility}" Content="{Binding ViewModel}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In my ViewModel I have the actual content and another Visibility property that is set to false when the content is not the current one and true if it is.
Thanks to all helpers!

What standard WPF control should I use?

I am trying the master-detail presentation in my app: when an item in a listbox is selected, its details are displayed in an adjacent control.
This control will have a list of measurements such as height, width, weight, etc. It will also have some small graphics such as a green or red dot or a medium sized image. It will also have some rich text.
Which STANDARD WPF control should I use to contain all these elements. I am thinking of using a listbox but wonder if there are better controls to use.
My main consideration is ease of coding, then possibly efficiency of the code.
Thanks.
A listbox indicates a list of items that can be tailored using a DataTemplate for appearence. In this case you are showing the details of a selected item. I would actually use a container such as a Grid nested in your current UI and have a set of stackpanel including the details of the selected item.
<Grid>
<StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Detail1</TextBlock>
<TextBox></TextBox>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Detail2</TextBlock>
<TextBox></TextBox>
</StackPanel>
</StackPanel>
</Grid>
This is only one suggestion but the point is to use a container and use a set of controls in the containers - textblock,textbox,checkboxes(boolean details), etc... this will allow you to use any control type necessary to represent the specific data field of the selected item.
You don't want to use a listbox unless you have a collection of similar items, and you want one or more items to be 'selected' at some point. It sounds like that is not what you want for the details part.
You do have a collection, which is shown in your master list. You should bind the SelectedItem in your master list to a property in your viewmodel. Then you can bind that same property to the details section of your UI. When the selection in the master list changes, your details UI will automatically update to reflect the changes.
<ListBox x:Name="masterList" ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem, Mode=TwoWay}"></ListBox>
<UserControl x:Name="detailsControl" DataContext="{Binding MySelectedItem}"> </UserControl >

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.

How do you get data from controls on pages on a Tab Control

I've got a WPF tab control that contain several duplicate controls as Tab Page content
<TabControl ItemsSource="{Binding}" Name="tabControl">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<local:InnerDataEntryControl DataContext="{Binding Data}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
On the InnerDataEntry control there is a list box. I've got a command on the outer form that requires the selected items from the list box on the control. I can't figure out how to access the list box on the tab control itself. When I try to query the selected items, I get the bound items and not the list box itself.
I don't want to pollute the business layer with an 'IsSelected' property on my list items, and I suppose I could create a view model if necessary, but it just seems wrong that I can't get information about the actual content control of a tab page.
I hope that I'm just missing something obvious.
This was asked earlier in my WPF experience. To close the loop on the question, I'm going to post a link to the MSDN Magazine entry on the subject of MVVM.
Ultimately, the solution involves the creation of a view model that has the necessary properties bound to the parts of the tab control such that the view model doesn't need access in the way that I'm describing. Instead, the view model acts directly on the data that that is bound without having to reference the view directly.

Resources