WPF listbox : problem with selection - wpf

In my XAML file, I have a ListBox declared like this :
<ListBox x:Name="lstDeck" Height="280" ItemsSource="{Binding Path=Deck}" >
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In my view model, Deck is an ObservableCollection, so that binding directly displays the content of my collection.
But when I have several value that hold the same value (for example "10" six times),
the selection in the ListBox has a weird behaviour : it select 2-3 elements instead of the only the one on which I clicked.
Moreover, when I click to another listBoxItem, it doesn't unfocus the previous selected one.
Then it is impossible to see which item is actually selected, and impossible to get the SelectedIndex value.
Has someone an idea?

The problem is that the listbox cannout distinguish between the different values. Therefore, once you click one of the "10"s, it sets it SelectedItem property and updates its presentation. Because it cannot distinguish between the value types it marks every "10" as selected.
But why do you have "10" several times in your listbox? If it is just the numeric value 10 or the string "10" it does not make any sense to me.
If you have a more complex model behind that and you just display one property, than you should bind the complex model and set the DisplayMemberPath instead.
C#
public class Model
{
public Guid Id { get; set; }
public string Value { get; set; }
}
XAML
<ListBox ItemsSource="{Binding Path=Models}" DisplayMemberPath="Value" />
<ListBox ItemsSource="{Binding Path=Models}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Best Regards
Oliver Hanappi

Related

WPF binding UserControl collection to ItemsControl. DataTemplate issue

http://www.filedropper.com/wpfapplication9
that link has a project in VS2013 with a sample issue.
my problem is, how to set DataTemplate to UserControl, in ItemsControl.
<ItemsControl ItemsSource="{Binding Collection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
my Collections is a
public IEnumerable<MyUC> Collection {get;}
my MyUC is a
public partial class MyUC : UserControl
{
public string Title { get; set; }
}
When i try to show that collection im getting
MyUC.Content
insted
MyUC.Title
when i change ItemsSouce to ListBox, datatemplate starts working.
but i need to show collection without ListBox addons.
If I understand you correctly, you just want to display the Title property value of your UserControls from your collection. All that you have to do is to declare an appropriate DataTemplate for them in the Resources section:
<DataTemplate DataType="x:Type={YourPrefix:MyUC}">
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
To be honest though, you seem to be going about this in the wrong way. In WPF, we generally don't put UI elements into collections, instead preferring to work with custom data classes that have DataTempates to define what they should look like. In your case, it would look something like this:
<DataTemplate x:Key="TitleTemplate" DataType="x:Type={YourPrefix:MyDataClass}">
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
<DataTemplate x:Key="ControlTemplate" DataType="x:Type={YourPrefix:MyDataClass}">
<YourControlPrefix:MyUC />
</DataTemplate>
You'd then use the TitleTemplate when you want to see just the Title property values and the ControlTemplate when you want to see the whole UserControl.

Binding one ElementUI in XAML to 2 source

<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<Textblock Text={Binding Path=Content} Foreground={Binding Path=TextColor}/>
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>
Hi, I'm developing a book reader application in WP8. I have a stoy with a list of paragraph which I use ListBox to display. Each paragraph content is binding to a textblock as you can see in my code. In Paragraph class, I define a field call TextColor to bind the foreground color of textblock to it. Now, each time user change the color, I have to loop through all paragraph in story and change the value of TextColor. Is there any way to separately bind 2 different property (ie. the Foreground and the Text) of a ListboxItem to different source> So I'll only have to change the Foreground one time. Thank
KooKiz solution is pretty good. However, if you don't want to include any properties to manage foreground colors, or any visual property for that matter, at all you can simply make it a static resource and bind to that instead where you can modify them independently of your model.
For example, you could define a ForegroundResouces class and add in different types of foregrounds your app needs.
In App.xaml
<Application.Resources>
<local:ForegroundResouces xmlns:local="clr-namespace:YOUR-NAMESPACE" x:Key="ForegroundResouces" />
</Application.Resources>
Then define your class
public class ForegroundResouces {
public static Brush TitleForeground { get; set; }
public static Brush ContentForeground { get; set; }
// ...
}
Then define your binding
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<Textblock
Text={Binding Path=Content}
Foreground={Binding Path=ContentForeground, Source={StaticResource ForegroundResouces} />
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>
Then you can simply change the foreground by modifying your static properties
ForegroundResources.ContentForeground = new SolidBrush(Colors.Red);
You could sort of make different set of themes but this solution is probably only worth it if you have more than one visual property to manage.
There is ways to specify a different source for your bindings. For instance, you can use ElementName to point at your listbox and retrieve its datacontext:
<ListBox x:Name="MyList" ItemsSource="{Binding Path=Paragraphs}">
<ListBox.ItemTemplate>
<DataTemplate>
<Textblock Text="{Binding Path=Content}" Foreground="{Binding Path=DataContext.TextColor, ElementName=MyList}"/>
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>
But in your case, it's probably easier to just set the Foreground property on the parent list. It will be automatically applies to all child controls:
<ListBox x:Name="MyList" ItemsSource="{Binding Path=Paragraphs}" Foreground="{Binding Path=TextColor}">
<ListBox.ItemTemplate>
<DataTemplate>
<Textblock Text="{Binding Path=Content}" />
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>

Consuming Complex Comboboxes WPF

I want to have complex combobox with checkboxes, text, and may be a thumbnail. I have already looked at the following links which helped me alot while building complex comboboxes.
http://blogs.microsoft.co.il/blogs/justguy/archive/2009/01/19/wpf-combobox-with-checkboxes-as-items-it-will-even-update-on-the-fly.aspx
Looking for a WPF ComboBox with checkboxes
But, I can not find a way to consume these complex usercontol in my application. I am new to WPF, so any kind of demonstration support would be highly appreciated.
Dean, I was looking a solution of how to bind in code behind file with following example mentioned in an SO post earlier.
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}"
Width="20" />
<TextBlock Text="{Binding DayOfWeek}"
Width="100" />
</StackPanel>
</DataTemplate>
So the question is, Do I need DataTable or something else to bind my list of Checkboxes and Titles with this combobox template?
Thanks in Advance
A Combobox is an ItemsControl. All ItemsControls can be filled "hardcoded" with items or containers.
This adds a new entry in the combobox, and wrappes the string into an ItemsContainer, which is a ComboBoxItem.
<ComboBox>
<sys:string>Hello</string>
<ComboBox>
Here we create a combobox item directly, and add its content to a string with the value "Hello"
<ComboBox>
<ComboBoxItem Content="Hello"/>
<ComboBox>
Both look visually the same. Its important to understand that in the first case the ComboBox takes care of wrapping our, to the ComboBox unknown type string, into an ComboBoxItem, and uses a default DataTemplate to display it. The default DataTemplate will display a TextBlock and calls ToString() on the given data item.
Now to have dynamic data, we need a ObservableCollection with our data items.
class Employee
{
public BitmapSource Picture {get;set;}
public string Name{get;set}
}
ObservableCollection<Employee> employees;
myComboBox.ItemsSource = employees;
We have a DataClass called Employee, an observable Collection which holds many of our dataitem, and set this collection as the ItemsSource. From this point on, our Combobox listens to changes to this collection. Like adding and removing Employees and automatically takes care of wrapping the new Employee into a ComboBoxItem. Everything is done automatically. The only thing we need to do is to provide a proper DataTemplate. The combobox doesn't know how to "display" an employee and thats exactly what a DataTemplate is for.
<DataTemplate x:Key="employeeTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Picture}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
We know an employee is wrapped in a ComboBoxItem, and the ComboBoxItem uses a provided Datatemplate to display its data, which means that inside the DataTemplate we can use Binding to access all properties on the data item.
Hope that helps you.
to just answer your question. all you need is a collection of an object with at least 2 public properties (IsSelected as bool and DayOfWeek as string) and just set these collection as the itemssource.
so all you need is a collection of such an object. just comment if you need an example.
ps: pls read through the www for wpf and binding to get the basics.
you could simple add the items directly
<ComboBox>
<ComboBox.Items>
<ComboBoxItem>
<TextBlock Text="test text" />
</ComboBoxItem>
<ComboBoxItem>
<CheckBox Content="test checkbox" />
</ComboBoxItem>
<ComboBoxItem>
<Button Content="test button" />
</ComboBoxItem>
</ComboBox.Items>
</ComboBox>
or if you want to use ItemsSource, the a DataTemplateSelector would be required
<ComboBox>
<ComboBox.ItemTemplateSelector>
<local:MyCustomTemplateSelector />
</ComboBox.ItemTemplateSelector>
</ComboBox>
here is a link that explains DataTemplateSelectors
http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemtemplateselector.aspx

ListBox bound to collection does not automatically refresh. Why?

I have a ListBox which is bound to a collection. When I add an item to the collection I see no change in the ListBox.
However, when I resize the window a little, then the new item suddenly appears in the ListBox. So the binding seems to be working, just the refresh is missing.
What might I be doing wrong here?
XAML:
<ListBox Grid.Row="2" Grid.Column="1" Name="TestModules" ItemsSource="{Binding ModuleList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding TE}"/>
<TextBlock Text="-"/>
<TextBlock Text="{Binding AF}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code:
private List<PruefModule> _moduleList = new List<PruefModule>();
public ICollectionView ModuleList { get; private set; }
ModuleList = CollectionViewSource.GetDefaultView(_moduleList);
_moduleList.Add((PruefModule)ModulesGrid.SelectedItem);
You should use an ObservableCollection instead of the ICollectionView and it should work ok.
From MSDN:
Represents a dynamic data collection that provides notifications when
items get added, removed, or when the whole list is refreshed.
like Adrian said you should use ObservableCollection.
nevertheless you can call Refresh after adding a item.
_moduleList.Add((PruefModule)ModulesGrid.SelectedItem);
ModuleList.Refresh();

What's the simplest way to bind a list of checkboxes to a list of checked values

I have a list of AvailableItems that I want to display as a list of checkboxes, so that users can pick which items to generate, which are then stored in another list called ItemsToGenerate (my lists are actually just lists of strings).
Showing all available items with corresponding checkboxes is easy:
<ItemsControl ItemsSource="{Binding Path=AvailableItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But now I need to bind each Checkbox.IsChecked property, to the fact that the item is in the ItemsToGenerate list. I thought of making a ListContainmentToBoolConverter like this:
IsChecked="{Binding Path=ItemsToGenerate,
Converter={StaticResource ListContainmentToBoolConverter}}"
But that doesn't work because I'm missing a ConverterParameter to pass the value of each item, but I can't do that, because ConverterParameter does not support binding.
Any ideas?
I've found a solution to my problem.
I've changed my ItemsControl to a ListBox, and added a binding between the SelectedItems with my ItemsToGenerate collection using the technique described here. It basically allows me to synchronize any custom collection to ListBox.SelectedItems using a simple attached property.
<ListBox ItemsSource="{Binding AvailableItems}"
Behaviors:MultiSelectorBehaviours.SynchronizedSelectedItems=
"{Binding ItemsToGenerate}"
SelectionMode="Multiple"
Background="{x:Null}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding}"
Margin="3"
IsChecked="{Binding RelativeSource=
{RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}},
Path=IsSelected}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
I'm still able to display this as I initially wanted (a list of checkboxes), by adding a data template to change each ListBoxItem to a checkbox and binding each Checkbox.IsChecked to ListBoxItem.IsSelected.
I had this pattern in so many places in my application that this is the ideal solution for me, because now I just need to specify one attached property, and the rest is all handled by the data bindings, and I don't need any additional code.
I honestly would create a list of objects containing both the string and a boolean indicating if it is checked.
With a little Linq you can generate your list of objects and bind it to itemSource instead of binding the list of strings.
It will be simpler in the end, especially if you actually need to update something if the user is allowed to check/uncheck the checkboxes.
== update ==
in answer to the comment, my take on this because I'm not sure I understand what the actual problem would be: provided we have the full list (AvailableItems) and the list of selected items (ItemsToGenerate):
public class ItemEntry
{
public string Name { get; set; }
public bool IsSelected {get; set; }
}
...
_Items = from item in AvailableItems
select new ItemEntry() {
Name = item,
IsSelected = ItemsToGenerate.contains(item)
}).ToList();
You can then bind your list like so, by exposing _Items as a property named Items:
<ItemsControl ItemsSource="{Binding Path=Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can at a later time select from _Items where IsSelected is true to get the selected items if you need to.
Also, if ItemsToGenerate can get big, you should create a HashSet of the values and use it in the query, that should make it faster if need be.

Resources