WPF how to make a listbox/listview unfocusable - wpf

I've been trying for a while to display some data in a listbox/listview that would be unfocusable (I mean not only the list, but also the items in it).
I tried with both types of list (listbox and listview), and I used their ItemTemplate and ItemContainerStyle. Everywhere I could, I set the Focusable property to false.
I don't see any other way than disabling the list, but then I have to change all its style, to make it appear not disabled.
Have I missed something? Is there a read-only type of list that I don't know about?
Thank you for your ideas :)

The problem you're probably seeing is that each individual item in the list is focusable. However, you can override that... Try adding this to your listbox:
<ListBox.ItemContainerStyle>
<Style TargetType="Control">
<Setter Property="Focusable" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
Note however that this makes the items unselectable (by keyboard or by mouse). You can set the selected item programmatically, but it doesn't appear to be highlighted automatically any more - so really, this behaves almost the same as an ItemsControl.

Use an ItemsControl with TextBlocks instead of a ListBox
<ItemsControl ItemsSource="{Binding MyListBoxItemsSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyDisplayName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

WPF ComboBox: How to you utilise a generic ItemContainerStyle with binding

I want to utilise a generic style for my ComboBoxItem content and have the text content bound to different properties on my underlying class. So this is the best I can come up with but the bindings are hard coded. So for every class bound to a combobox using this ItemContainerStyle I'd have to implement a "MainText" and "SubText" property.
Question is, is there a way to have the binding soft coded so where the style referenced from a combobox I can specify which string properties of the underlying class are used.
<Style TargetType="{x:Type ComboBoxItem}" x:Key="ComboBoxItemStyleA1">
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="BB" Padding="8,3,8,3" Background="DarkGreen">
<StackPanel Margin="0">
<TextBlock Foreground="White" FontSize="16" Text="{Binding MainText}"/>
<TextBlock Foreground="White" FontSize="8" Text="{Binding SubText}"/>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" TargetName="BB" Value="#FF256294"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And to use the style...
<ComboBox ItemsSource="{Binding Items}"
ItemContainerStyle="{StaticResource ComboBoxItemStyleA1}" />
Further to dowhilefor's answer (many many thanks - WPF is great but sure is a voyage of discovery)
I used a data template to define the cell look originally - and then wanted to use a comboboxitem based style with a control template defined where I could specify the onmouseover triggers. i.e. these were to change the background color etc.
Butj
a) I couldn't remove the Border section of the template above - the triggers are tied to it by targettype="BB". so I kind of wanted to get the trigger bound to the container such that the datatemplate would pick up the background from the template binding but not sure how to get this plumbed in.
b) I realised that even if I comment out the BB specific bindings on the triggers just to get it to run - the combobox doesn't find and use the DataTemplate I defined. Seems that defining the controltemplate in my comboboxitemstyle stops it picking up the datatemplate.
I hope I make sense here - bottom line is I just want a style that I can apply with triggers in that set the background color of my cobobox item. It should not know what the data is - i.e. be able to plug in a datatemplate that will (template ?) bind to this background color.
Many thanks for the very fast response.
btw I'm using ItemContainerStyle in conjuction with ItemTemplate so I can have a different representation in the dropdown to what appears in the combobox list
First of all don't use the ItemContainerStyle for that. To be more precise never have any Bindings to the datacontext inside an ItemContainerStyle, at least try not. Why? The Style is used for defining the appearance of a combobox item disregarding the content. If you want to define how the content should look like, you use a DataTemplate for that. There are multiple ways to tell the combobox where he can find a proper DataTemplate for the Data you supply. Checkout the property ItemTemplate, ItemTemplateSelector and search for implicit styles, to find out more about them.
So to your problem, create one ItemContainerStyle for you combobox (if you really have to anymore) which doesn't care about the object that will be put into. Now you still need to provide multiple DataTemplates each and everyone with the knowledge of the data object that you want to be templated. There is no way around it, there is no soft databinding. Just try to keep your templates small and simple. If for some reason you need the exact same template, but your properties are just named differently, why not use a wrapper item for the DataContext with the properties Caption, Description and you can decide in code how these properties are filled with your real data wrapped into this object.

WPF-MVVM: Prevent the user select something else in the listbox

I've a small WPF application(.Net 3.5 :/ ).
In this application I've a listbox, which allows me to select an element to edit on the right part of the application.
If the right part is invalid, I need to prevent the user changing the selection of elements.
I've made a lot of search on this:
Some were telling to change the background/brush to make it look like the selection is not possible(but the selection is still possible)
Some other were telling me to update the IsFocusable property of sub elements:
<ListBox itemsSoutces={Binding Test}>
<ListBoxt.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</listBox.ItemContainerStyle>
</ListBox>
The problem with this solution is that this value has to comes from a value of my ViewModel, and I don't know(nor it's possible) to bind the Value of the Style Setter to a property of my ViewModel?
Is it possible? How?
I would simply disable the listbox if the right part is invalid by setting IsEnabled to false. If your ViewModel contains a corresponding property, you can bind to that:
<ListBox IsEnabled="{Binding IsValid}" ...> ... </ListBox>

How do I apply a Style Setter for ListBoxItems of a certain DataType?

My WPF ListBox contains two types of object: Product and Brand.
I want my Products selectable. I want my Brands not selectable.
Each of the two types has its own DataTemplate.
By default, anything may be selected:
<ListBox ... >
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:Product}">
...
</DataTemplate>
<DataTemplate DataType="{x:Type local:Brand}">
...
</DataTemplate>
</ListBox.Resources>
</ListBox>
I can set Focusable with a Setter, but then nothing may be selected:
<ListBox ... >
<ListBox.Resources>
...
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False" />
</Style>
</ListBox.Resources>
</ListBox>
I cannot put the Setter within the DataTemplate.
I cannot put a DataType onto the Style.
How do I style only the ListBoxItems of type Brand?
Thanks to the StyleSelector class you can attach styles depending on type of data for the ItemContainerStyle. There is a really good example here : http://www.telerik.com/help/wpf/common-data-binding-style-selectors.html
Can you use a data trigger on your ListBoxItem style? If so, bind to the DataContext (your class) and use a value converter to test the type. If it's the one you're interested in, style the ListBoxItem so that it cannot appear selected.
I don't think you can disallow selection of an item in a Selector (parent of ListBox) without codebehind or a custom Behavior.

Silverlight databinding to itemsource in parent's parent datacontext

I have a datagrid where in one of the column's header I would like to have a dropdown that filters the data in the grid. The issue being that the datacontext that has the values that would be in this dropdown is in the usercontrol's viewmodel not the datagrids itemssource so the list doesn't seem to be available to the dropdown.
<sdk:DataGridTemplateColumn.HeaderStyle>
<Style TargetType="sdk:DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Assignee" />
<ComboBox x:Name="cboAttorneyHdr" ItemsSource="{Binding Path=Attorneys}"
Margin="3,0,0,0" SelectedItem="{Binding Path=SelectedAttorney, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</sdk:DataGridTemplateColumn.HeaderStyle>
I found an example using relative source for WPF that seems to be asking the same thing but it seems that this doesn't work for Silverlight. I have tried setting this manually in the code behind but the combobox does appear to be available there either!
One way I've found around this problem is to use some helpers as detailed here - it's just one of the possible implementations, but it amounts to emulating the WPF RelativeSourceBinding with AncestorLevel/AncestorType which is still not available in SL4. Or you could try to google 'silverlight combobox in datagrid' for more ways to solve it, I'm sure you can imagine it's a pretty common problem :)
I found this solution which actually ended up working great though it's going to take me a bit to actually understand what the heck it's really doing.
http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx

WPF: Dynamically change ListBox's ItemTemplate based on ListBox Items Size

I need to change the DataTemplate of my ListBox, based on the ListBox items count. I have come up with the following XAML:
<Window.Resources>
<DataTemplate x:Key="DefaultTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Text}"/>
<TextBlock Text="default template" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="OtherTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Text}"/>
<TextBlock Text="other template" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<ListBox Name="listBox1" ItemsSource="{Binding Path=Items}">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate" Value="{StaticResource DefaultTemplate}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count}" Value="1">
<Setter Property="ItemTemplate" Value="{StaticResource OtherTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
With the above XAML, once I added two or more items to the bound list, the data template changed as expected (from other to default). However, if I remove the first item in the list with more than two items, the entire listbox just becomes empty (I verified that the bound list is non-empty). Removing the second item in a two items list works fine though (i.e. template changed from default to other).
Any ideas why this is happening? Or perhaps I went about the wrong way to solve this problem?
you could use data triggers, or you could use a DataTemplateSelector Here is an article that shows the basics. and here is the MSDN on applying it to the items control (also, a listbox)
I can't speak for the exact problem or the cause, but it is because a DataTrigger is setting a template when the count is 1 and only 1.
You can do 1 of 3 things to solve this problem, but only 1 I would recommend.
a) Implement your own DataTrigger by deriving from System.Windows.TriggerBase
b) Use an implementation of System.Windows.Data.IValueConverter that will convert from ItemsControl.Items.Count into a DataTemplate. Retrieve the templates by placing an element in scope of your resources as Binding.ConverterParameter, casting them to FrameWorkElement and call FrameWorkElement.FindResource().
C) This is my recommendation, write your own DataTemplateSelector to do the grunt work. This mechanism is specifically targeted at the functionality you with you achieve. I recently wrote one that will pick a DataTemplate based on the type of the source object without requiring a DataTemplate with no x:Key set. Using Properties on the template selector, you can pass DataTemplates into the DataTemplateSelector using XAML, removing that FindResource code 'todo' list.

Resources