wpf collectionview multiple filter - c#

I need some advice. I have two ListViews first ListView is "ListViewAlbums" and the second "ListViewTracks".
 
Items in ListViewTracks are organized into groups.
ListViewAlbums is set SelectionMode = "Extended" and Behaviours: MultiSelectorBehaviours.SynchronizedSelectedItems.
MultiSelectorBehaviours
When I select multiple items from ListViewAlbums, so I want to show all the items in ListViewTracks based ALBUMID.
My current code:
ListViewTracks GroupDescriptions:
PropertyGroupDescription groupDescription = new PropertyGroupDescription("AlbumID");
viewTrack.GroupDescriptions.Add(groupDescription);
viewTrack.SortDescriptions.Add(new System.ComponentModel.SortDescription("AlbumTitle", System.ComponentModel.ListSortDirection.Ascending));
viewTrack.SortDescriptions.Add(new System.ComponentModel.SortDescription("TitleTrack", System.ComponentModel.ListSortDirection.Ascending));
Employees data:
private ObservableCollection<EmployeesAlbums> _listAlbums = new ObservableCollection<EmployeesAlbums>();
public ObservableCollection<EmployeesTracks> _listTrack = new ObservableCollection<EmployeesTracks>();
public ObservableCollection<EmployeesTracks> PlayListTracks
{
get { return _listTrack; }
set { _listTrack = value; RaisePropertyChanged("PlayListTracks"); }
}
public ObservableCollection<EmployeesAlbums> PlayListAlbums
{
get { return _listAlbums; }
set { _listAlbums = value; RaisePropertyChanged("PlayListAlbums"); }
}
EmployeesAlbums model = new EmployeesAlbums
{
IdAlbums = int.Parse(rdr["Id"].ToString()),
TitleAlbum = rdr["TitleAlbums"].ToString(),
ArtistAlbum = rdr["ArtistAlbums"].ToString()
};
modelTracks = new EmployeesTracks
{
IdTrack = int.Parse(rdr["Id"].ToString()),
TitleTrack = rdr["TitleTrack"].ToString(),
PathTrack = rdr["Path"].ToString(),
AlbumTitle = rdr["AlbumTitle"].ToString(),
ArtistTrack = rdr["ArtistTrack"].ToString(),
AlbumID = int.Parse(rdr["AlbumId"].ToString()).ToString()
};
SelectedItem of ListViewAlbums:
SelectionChangedItemsAlbumCommand = new GalaSoft.MvvmLight.CommandWpf.RelayCommand(SelectionChangedItemsAlbum);
private EmployeesAlbums _selectedPlayListFileAlbum;
public EmployeesAlbums SelectedPlayListFileAlbum
{
get { return _selectedPlayListFileAlbum; }
set
{
if (_selectedPlayListFileAlbum != value)
{
_selectedPlayListFileAlbum = value;
RaisePropertyChanged("SelectedPlayListFileAlbum");
}
}
}
private IEnumerable<EmployeesAlbums> _selectedPlayListFilesAlbums;
public IEnumerable<EmployeesAlbums> SelectedPlayListFilesAlbums
{
get { return this.selectedPlayListFilesAlbums; }
set { Set(ref selectedPlayListFilesAlbums, value); }
}
Filtering:
public string AlbumID { get; set; }
void SelectionChangedItemsAlbum()
{
foreach (var items in SelectedPlayListFilesAlbums)
{
ListCollectionView empView = CollectionViewSource.GetDefaultView(PlayListTracks) as ListCollectionView;
// Enable Live Filtering of the ListViewCollection
empView.IsLiveFiltering = true;
// Enable the filtering on AlbumID
empView.LiveFilteringProperties.Add("AlbumID");
AlbumID = items.IdAlbums.ToString();
// Filter based upon AlbumID
empView.Filter = new Predicate<object>(IsMatchFoundAlbums);
// Refresh Collection
empView.Refresh();
}
}
bool IsMatchFoundAlbums(object d)
{
bool res = false;
EmployeesTracks emp = d as EmployeesTracks;
if (emp.AlbumID == AlbumID)
{
res = true;
}
return res;
}
XAML Code:
<ListView x:Name="ListViewTracks"
VirtualizingPanel.ScrollUnit="Pixel"
VirtualizingStackPanel.CacheLength="20,20"
VirtualizingStackPanel.CacheLengthUnit="Item"
ItemsSource="{Binding PlayListTracks}"
Style="{StaticResource CommonListViewStyleTracks}"
ItemContainerStyle="{DynamicResource styleListViewItem}"
>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<StackPanel>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" />
<ItemsPresenter Margin="0,0,0,20" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate >
<Grid d:DesignWidth="460" Height="51">
<StackPanel>
<TextBlock DataContext="{Binding Items}" Text="{Binding AlbumTitle}" FontSize="18" TextTrimming="CharacterEllipsis" Foreground="{DynamicResource ItemsListViewForeground}"/>
<TextBlock DataContext="{Binding Items}" Text="{Binding ArtistTrack}" TextTrimming="CharacterEllipsis" Foreground="{DynamicResource AccentColorApps}"/>
</StackPanel>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
<ListView
x:Name="ListViewAlbums"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding PlayListAlbums}"
SelectionMode="Extended"
SelectedItem="{Binding SelectedPlayListFileAlbum,UpdateSourceTrigger=PropertyChanged}" SelectionMode="Extended"
behaviours:MultiSelectorBehaviours.SynchronizedSelectedItems="{Binding SelectedPlayListFilesAlbums, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Background="{x:Null}" Grid.Column="1" Grid.RowSpan="4"
ItemTemplate="{DynamicResource AlbumsDataTemplate}"
BorderBrush="{x:Null}"
>
<ie:Interaction.Triggers >
<ie:EventTrigger EventName="SelectionChanged">
<ie:InvokeCommandAction Command="{Binding SelectionChangedItemsAlbumCommand}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"/>
</ie:EventTrigger>
</ie:Interaction.Triggers>
</ListView>
Thanks a lot.

Try this
Right after you have initialized the property PlaylistTracks, do:
ListCollectionView empView = CollectionViewSource.GetDefaultView(PlayListTracks) as ListCollectionView;
empView.Filter = IsMatchFoundAlbums;
And let your Match method be:
bool IsMatchFoundAlbums(object d)
{
EmployeesTracks emp = d as EmployeesTracks;
return SelectedPlayListFilesAlbums.Any(x => x.IdAlbums == emp.AlbumID);
}

Related

How to add grid to my combobox and display obervableCollection data?

I use a combobox and I would like to proceed as follows:
I choose an element in cmb1, this allows to display in cmb2 a Collection.
This code allows me to retrieve the data I want ( result A = ObservableCollectionA, result B = ObservableCollection B...)
<ComboBox Name="cmbResultatListe"
Margin="0,10,0,10"
Grid.Row="4"
Grid.Column="2"
Height="25"
Width="250" >
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Sections}"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedChoiceList}" Value="Etablissement">
<Setter Property="ItemsSource" Value="{Binding Etablissements}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedChoiceList}" Value="Service">
<Setter Property="ItemsSource" Value="{Binding Services}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
I would now like to divide my combobox into three grids, so that I can proceed as follows:
If result A is selected => cmb2 grid0 = ObservableCollectionA.ID, cmb2 grid1 = observableCollectionA.Name...
If result B is selected => cmb2 grid0 = ObservableCollectionB.Name, cmb2 grid1 = observableCollectionB.Years...
And i don't know how can i do that.
Any tips ?
Thank you for your help.
Edit :
c# code :
private ObservableCollection<Etablissement> _EtablissementsUtilisateur;
public ObservableCollection<Etablissement> EtablissementsUtilisateur
{
get
{
return _EtablissementsUtilisateur;
}
set
{
if (value != _EtablissementsUtilisateur)
{
_EtablissementsUtilisateur = value;
RaisePropertyChanged(nameof(EtablissementsUtilisateur));
}
}
}
private ObservableCollection<ServiceSectionModel> _Services;
public ObservableCollection<ServiceSectionModel> Services
{
get
{
return _Services;
}
set
{
if (value != _Services)
{
_Services = value;
RaisePropertyChanged(nameof(Services));
}
}
}
private ObservableCollection<ServiceSectionModel> _Sections;
public ObservableCollection<ServiceSectionModel> Sections
{
get
{
return _Sections;
}
set
{
if (value != _Sections)
{
_Sections = value;
RaisePropertyChanged(nameof(Sections));
}
}
}
private string _SelectedChoiceList;
public string SelectedChoiceList
{
get
{
return _SelectedChoiceList;
}
set
{
if (value != _SelectedChoiceList)
{
_SelectedChoiceList = value;
RaisePropertyChanged(nameof(SelectedChoiceList));
}
}
}
Etablissements = new ObservableCollection<Etablissement>((await _dataService.GetEtablissements().ConfigureAwait(false)));
Services = await _dataService.GetServicesAsync(false).ConfigureAwait(false);
Sections = await _dataService.GetSectionsAsync(_dataService.ParamGlobaux.IDEtablissement).ConfigureAwait(false);
Etablissement contain ID, Name, Years.
Service contain Color, ID, Name.
Section contain Color, ID, SectionName.
Edit 2 : I would like something like this exemple :
<ComboBox Name="CbService" HorizontalAlignment="Left" Margin="115,67,0,0" VerticalAlignment="Top" Width="150" ItemsSource="{Binding}" SelectionChanged="CbRecherche_SelectionChanged" KeyboardNavigation.TabIndex="1" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Libelle}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid x:Name="gd" TextElement.Foreground="Black" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="Auto" MinWidth="50" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Fill="{Binding Fond}" Grid.Column="0"/>
<TextBlock Margin="5" Grid.Column="0" Text="{Binding ID}"/>
<TextBlock Margin="5" Grid.Column="1" Text="{Binding Libelle}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
Currently my combobox displays a string. I want something like this :
In this example, there is an ID, a color only in the ID part, and a Name. I can't do that with my string at the moment.
I belive you may be able to reduce the size of your codes by removing the RaisePropertyChanged event as ObservableCollections already contain the INotifyPropertyChanged interface, I have made a simple example of how to use Datatemplate to display information from ObservableCollections.
Step 1: C# codes:
namespace WpfApp1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
ComboBox1.ItemsSource = Services;
Services.Add(new ServiceSectionModel { Color = Brushes.Red, ID = "Clem", Name = "Clementine" });
Services.Add(new ServiceSectionModel { Color = Brushes.White, ID = "011", Name = "Logistique" });
Services.Add(new ServiceSectionModel { Color = Brushes.Green, ID = "MBT", Name = "Montbrilland" });
}
public class ServiceSectionModel
{
public string ID { get; set; }
public string Name { get; set; }
public SolidColorBrush Color { get; set; }
}
ObservableCollection<ServiceSectionModel> Services = new ObservableCollection<ServiceSectionModel>();
}
}
Step 2: XAML codes:
<ComboBox x:Name="ComboBox1" HorizontalAlignment="Center" VerticalAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Background="{Binding Color}" Text="{Binding ID}" Margin="0,0,10,0" Padding="5,2,10,2"></TextBlock>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Not getting value from StackPanel

I have been having a problem with getting the exact value from the stackpanel.
XAML
<Page
x:Class="MedicinesApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MedicinesApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<CollectionViewSource x:Name="MedicinesCollectionViewSource" IsSourceGrouped="True" />
</Page.Resources>
<GridView
ItemsSource="{Binding Source={StaticResource MedicinesCollectionViewSource}}"
x:Name="MedicinesGridView"
Padding="30,20,40,0"
SelectionMode="Single"
IsSwipeEnabled="false"
IsItemClickEnabled="True" SelectionChanged="MedicinesGridView_SelectionChanged"
ItemClick="MedicinesGridView_ItemClick">
<GridView.ItemTemplate>
<DataTemplate x:Name="templateTrending">
<Grid HorizontalAlignment="Left" Width="250" Height="250" x:Name="wow">
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}">
<Image Source="{Binding Path=DiseaseImageSource}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
</Border>
<StackPanel VerticalAlignment="Bottom" Background="{ThemeResource ListViewItemOverlayBackgroundThemeBrush}">
<StackPanel Orientation="Vertical">
<TextBlock Text="Disease Name" Foreground="{ThemeResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextBlockStyle}" Height="30" Margin="15,0,15,0"/>
<TextBlock x:Name="DiseaseNameBro" Text="{Binding Path=DiseaseName, Mode=TwoWay}" Style="{StaticResource TitleTextBlockStyle}" Height="30" Margin="15,0,15,0"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock Text="Category of Disease" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" Margin="15,0,87,10"/>
<TextBlock Text="{Binding Path=CategoryOfDisease}" Foreground="{ThemeResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text='{Binding Key}' Foreground="Gray" Margin="5" FontSize="30" FontFamily="Segoe UI Light" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid MaximumRowsOrColumns="2" Orientation="Horizontal" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid GroupPadding="0,0,70,0" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
C#
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.UI.Xaml.Controls;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace MedicinesApp
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public string getMedicinesName;
public ObservableCollection<Disease> diseaseList = new ObservableCollection<Disease>();
public MainPage()
{
this.InitializeComponent();
diseaseList.Add(new Disease { DiseaseName = "Malaria", DiseaseImageSource = "/Assets/133px-Malaria.jpg", CategoryOfDisease = "Blood" });
diseaseList.Add(new Disease { DiseaseName = "Typhod", DiseaseImageSource = "../Assets/apple.jpg", CategoryOfDisease = "Thorat" });
diseaseList.Add(new Disease { DiseaseName = "Cancer", DiseaseImageSource = "../Assets/orange.jpg", CategoryOfDisease = "Body" });
diseaseList.Add(new Disease { DiseaseName = "Headache", DiseaseImageSource = "../Assets/bilberry.jpg", CategoryOfDisease = "Brain" });
//diseaseList = new ObservableCollection<Disease>(diseaseList.OrderBy(c => c.DiseaseName));
MedicinesCollectionViewSource.Source = GetGroupsByLetter();
}
internal List<GroupInfoList<object>> GetGroupsByLetter()
{
var groups = new List<GroupInfoList<object>>();
var query = from item in diseaseList
orderby item.DiseaseName
group item by item.DiseaseName[0] into g
select new { GroupName = g.Key, Items = g };
foreach (var g in query)
{
var info = new GroupInfoList<object>();
info.Key = g.GroupName;
foreach (var item in g.Items)
{
info.Add(item);
}
groups.Add(info);
}
return groups;
}
public class GroupInfoList<T> : List<object>
{
public object Key { get; set; }
public new IEnumerator<object> GetEnumerator()
{
return base.GetEnumerator();
}
}
public class Disease
{
public string DiseaseName { get; set; }
public string DiseaseImageSource { get; set; }
public string CategoryOfDisease { get; set; }
}
private void MedicinesGridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
getMedicinesName = ((Disease)MedicinesGridView.SelectedItem).DiseaseName;
}
private void MedicinesGridView_ItemClick(object sender, ItemClickEventArgs e)
{
this.Frame.Navigate(typeof(malaria), getMedicinesName);
}
}
the problem is whenever I click on Malaria,
it goes to the other page and shows cancer, which is the first vaule in the list.
How can I get the value of the item I click and not of the first item. I Have attached screenshot for you'll to get a better knowledge of things.
I looked at your code and there is one thing that I don't understand.
Why are you using 2 events to navigate. Only one would do the job.
private void MedicinesGridView_ItemClick(object sender, ItemClickEventArgs e)
{
var selectedDisease = e.ClickedItem as Disease;
this.Frame.Navigate(typeof(malaria), selectedDisease);
}
You don't need the getMedicinesName either.
Don't forget to remove the SelectionChanged event both from you code behind and XAML.

Select text from a list view when that is cliked C# Metro App

I have a list view which I populate it from an API.. I want it fill a text box with the value which is found in the text block when I click..
My Listview...
<ListView Width="300" Height="134" x:Name="lsvObjectives" IsItemClickEnabled="True" SelectionMode="Multiple" ItemsSource="{Binding Source={StaticResource cvsObjectives}}" ItemClick="lsvObjectives_ItemClick">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" HorizontalChildrenAlignment="left"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="-7"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="0,0,0,0" HorizontalAlignment="Center" >
<StackPanel Orientation="Horizontal" Width="310" Height="33" Background="#FFE9D5F0" HorizontalAlignment="Left">
<StackPanel Width="270" VerticalAlignment="Center" Margin="10,5,0,0">
<TextBlock Text="{Binding objective}" Style="{StaticResource ContentTextBlockStyle}" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Left" FontSize="13"/>
</StackPanel>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is how I populate the list:
private async void getObjectives()
{
string getObjectives = baseAddress + "unitPlansDetailsByUnit/1";
var content = await httpClient.GetStringAsync(new Uri(getObjectives));
objectivesHelper data = JsonConvert.DeserializeObject<objectivesHelper>(content);
foreach (var item in data.result)
{
cvsObjectives.Source = data.result;
}
}
My Classes:
public class objectives
{
public int id { get; set; }
public string objective { get; set; }
}
class objectivesHelper
{
public List<objectives> result { get; set; }
}
I am unable to read the value from the text block which is found in my list view..
Someone kindly help me do this..
Any kind of help is appreciated....
You can read the value in your lsvObjectives_ItemClick method by casting the ItemClickEventArgs.ClickedItem to your type objectives.
For example:
private void lsvObjectives_ItemClick(object sender, ItemClickEventArgs e)
{
objectives item = e.ClickedItem as objectives;
var itemText = item.objective;
youtTextBox.Text = item.Description.ToString();
}

Listbox IsSynchronizedWithCurrentItem causes selection of the first item even though nothing its telling it to do it

I came across something that maybe a bug in wpf listbox. Please see the code and then I explain what happens
Window
<Window >
<Grid>
<local:MultiSelectionComboBox Width="200"
MinHeight="25"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ASLDisplayMemberPath="FirstName"
ASLSelectedItems="{Binding SelectedModels}"
ItemsSource="{Binding Models}" />
<ListBox HorizontalAlignment="Right"
VerticalAlignment="Top"
DisplayMemberPath="FirstName"
ItemsSource="{Binding SelectedModels}" />
</Grid>
</Window>
User control
<ComboBox>
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid x:Name="MainGrid"
Width="Auto"
Height="Auto"
SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0" />
</Grid.ColumnDefinitions>
<Popup x:Name="PART_Popup"
Grid.ColumnSpan="2"
Margin="1"
AllowsTransparency="true"
IsOpen="{Binding Path=IsDropDownOpen,
RelativeSource={RelativeSource TemplatedParent}}"
Placement="Center"
PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
<Border x:Name="DropDownBorder"
MinWidth="{Binding Path=ActualWidth,
ElementName=MainGrid}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<ScrollViewer CanContentScroll="true">
<StackPanel>
<CheckBox x:Name="checkBox"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ComboBox}, Path=CheckAllCommand}">select all</CheckBox>
<ListBox x:Name="lstBox"
here lies the problem without the line below I dont get to see the result on start up,
with the it selects the first item even if nothing is triggering it
IsSynchronizedWithCurrentItem="True"
ItemsSource="{TemplateBinding ItemsSource}"
KeyboardNavigation.DirectionalNavigation="Contained"
SelectionChanged="ListBoxOnSelectionChanged"
SelectionMode="Multiple"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</StackPanel>
</ScrollViewer>
</Border>
</Popup>
<ToggleButton Grid.ColumnSpan="2"
MinWidth="20"
HorizontalAlignment="Right"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
IsChecked="{Binding Path=IsDropDownOpen,
Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"
Style="{DynamicResource ToggleButtonStyle1}" />
<ItemsControl x:Name="itemsControl"
Margin="4,2,0,2"
ItemsSource="{Binding Path=SelectedItems,
ElementName=lstBox}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="#383838"
CornerRadius="2"
Padding="5,2,3,2">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="Test"
Foreground="White"
Loaded="Test_OnLoaded"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ComboBox}},
Path=ASLDisplayMemberPathActualValue}" />
<Button Width="12"
Height="12"
Margin="5,0,0,0"
Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=ComboBox},
Path=UnselectCommand}"
CommandParameter="{Binding}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Ellipse x:Name="PART_ButtonBackground"
Fill="White"
Opacity="0" />
<TextBlock x:Name="PART_Text"
Margin="0,0,0,1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="10"
Foreground="White"
Text="X" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PART_ButtonBackground" Property="Opacity" Value="0.8" />
<Setter TargetName="PART_Text" Property="Foreground" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.Style>
</ComboBox>
code behind user control
public partial class MultiSelectionComboBox : ComboBox
{
#region fields, dependencies, command and constructor
private ListBox listBox;
private ItemsControl itemsControl;
private CheckBox checkBox;
public static readonly DependencyProperty ASLSelectedItemsProperty = DependencyProperty.Register("ASLSelectedItems", typeof(ObservableCollection<object>), typeof(MultiSelectionComboBox), new PropertyMetadata(null));
public static readonly DependencyProperty ASLDisplayMemberPathProperty = DependencyProperty.Register("ASLDisplayMemberPath", typeof(string), typeof(MultiSelectionComboBox), new PropertyMetadata("Description"));
public MultiSelectionComboBox()
{
InitializeComponent();
}
public DelegateCommand<object> UnselectCommand { get; private set; }
public DelegateCommand CheckAllCommand { get; private set; }
public ObservableCollection<object> ASLSelectedItems
{
get { return (ObservableCollection<object>)GetValue(ASLSelectedItemsProperty); }
set { SetValue(ASLSelectedItemsProperty, value); }
}
public string ASLDisplayMemberPath
{
get { return (string)GetValue(ASLDisplayMemberPathProperty); }
set { SetValue(ASLDisplayMemberPathProperty, value); }
}
#endregion
private void CheckAll()
{
if (checkBox.IsChecked == true)
{
listBox.SelectAll();
}
else
{
listBox.UnselectAll();
}
}
private void GetControls()
{
checkBox = Template.FindName("checkBox", this) as CheckBox;
listBox = Template.FindName("lstBox", this) as ListBox;
itemsControl = Template.FindName("itemsControl", this) as ItemsControl;
}
private bool bug = true;
private void ListBoxOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
e.AddedItems.Cast<object>().Where(item => !ASLSelectedItems.Contains(item)).ForEach(p => ASLSelectedItems.Add(p));
e.RemovedItems.Cast<object>().Where(item => ASLSelectedItems.Contains(item)).ForEach(p => ASLSelectedItems.Remove(p));
checkBox.IsChecked = (listBox.ItemsSource as IList).Count == listBox.SelectedItems.Count;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
GetControls();
SetControls();
UnselectCommand = new DelegateCommand<object>(p => listBox?.SelectedItems.Remove(p));
CheckAllCommand = new DelegateCommand(CheckAll);
}
private void SetControls()
{
listBox.DisplayMemberPath = ASLDisplayMemberPath;
itemsControl.DisplayMemberPath = ASLDisplayMemberPath;
}
private void Test_OnLoaded(object sender, RoutedEventArgs e)
{
(sender as TextBlock)?.SetBinding(TextBlock.TextProperty, ASLDisplayMemberPath);
}
}
view model
public class MainWindowViewModel
{
public ObservableCollection<Model> Models { get; set; }
public ObservableCollection<object> SelectedModels { get; set; }
public MainWindowViewModel()
{
Models = new ObservableCollection<Model>()
{
new Model() {FirstName = "Amelia", Age = 0},
new Model() {FirstName = "Bruno", Age = 5},
new Model() {FirstName = "Colin", Age = 47},
new Model() {FirstName = "Daniel", Age = 32},
new Model() {FirstName = "Iza", Age = 28},
new Model() {FirstName = "James", Age = 23},
new Model() {FirstName = "Simon", Age = 23}
};
SelectedModels = new ObservableCollection<object> {Models.FirstOrDefault() };
}
}
Now the problem is that if inside the user control (where the listbox is) if I don’t set synchronize to true, then it won’t see the first item on start-up, if I do set it, then something forces an add to the collection. And then even if inside selected children I don’t set a value, it still sets the value of the first child.
This is actually multiselect combobox, got so far and this one simple thing stopped me for half of the day. And I can't find what is causing it.
Any help would be appreciated
This will help us on how to understand how listbox behaves when IsSynchronizedWithCurrentItem is set to true. Link
Given your requirement, this should be false.
Your LisBox.SelectionChanged event handler will be invoked every time you set the Values to ASLSelectedItems.
I think it will work by:
Remove your handler from your ListBox (lstBox).
Then modify your DP
public static readonly DependencyProperty ASLSelectedItemsProperty = DependencyProperty.Register("ASLSelectedItems", typeof(ObservableCollection<object>), typeof(MultiSelectionComboBox), new PropertyMetadata(null, OnSelectedItemsChanged));
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Add your logic from your handler
}

Longlist is not populated with items

I'm trying to populate the Longlist via WCF following this tutorial. I want to group users by their income (from min to max), but groups are displayed randomly. Also there are no items in the list (see picture below). What am I missing?
My XAML code is:
<phone:PhoneApplicationPage.Resources>
<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
<DataTemplate x:Key="usersHeaderTemplate">
<Border Width="72" Height="72" HorizontalAlignment="Left" Background="{Binding Converter={StaticResource BackgroundConverter}}" Margin="6">
<TextBlock Text="{Binding Income}"
FontSize="20" Padding="6"
VerticalAlignment="Center" HorizontalAlignment="Center"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}" />
</Border>
</DataTemplate>
<DataTemplate x:Key="usersItemTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Flag}" Height="50" Margin="0,0,10,0"/>
<StackPanel>
<TextBlock Text="{Binding Name}" Style="{StaticResource PhoneTextSubtleStyle}" />
<TextBlock Text="{Binding Income,StringFormat='Income: {0}'}" />
<TextBlock Text="{Binding Job}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
<Style x:Key="LongListSelectorJumpListStyle" TargetType="phone:LongListSelector">
<Setter Property="GridCellSize" Value="113,113"/>
<Setter Property="LayoutMode" Value="Grid" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundConverter}}"
Width="113" Height="113" Margin="6" >
<TextBlock Text="{Binding Title}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
FontSize="48" Padding="6"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="usersListHeader">
<Border Background="White" Opacity="0.2" Height="70">
<TextBlock Text="List Header" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black" />
</Border>
</DataTemplate>
<DataTemplate x:Key="usersListFooter">
<Border Background="White" Opacity="0.2" Height="70">
<TextBlock Text="List Footer" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black"/>
</Border>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="longlist2" Height="608" Margin="10,15,24,0" VerticalAlignment="Top" Width="422"
IsGroupingEnabled="True" LayoutMode="List" HideEmptyGroups="False"
ItemTemplate="{StaticResource usersItemTemplate}"
GroupHeaderTemplate="{StaticResource usersHeaderTemplate}"
JumpListStyle="{StaticResource LongListSelectorJumpListStyle}"
ListHeaderTemplate="{StaticResource usersListHeader}"
ListFooterTemplate="{StaticResource usersListFooter}" >
</phone:LongListSelector>
</Grid>
</Grid>
My service implementation is:
public IEnumerable<mTeachers> GetStuffList(string Job)
{
List<mTeachers> stuffList = new List<mTeachers>();
DataClasses1DataContext data = new DataClasses1DataContext();
List<mTeachers> finalList = new List<mTeachers>();
foreach (var d in data.Stuffs)
{
stuffList.Add(new mTeachers() { Name = d.stuffName, Income = (int)d.stuffIncome, Job = Job, Flag = new Uri(#"/Assets/users.png", UriKind.Relative) });
}
return stuffList;
}
private List<Group<mTeachers>> GetUsersGroups(string Job)
{
IEnumerable<mTeachers> usersList = GetStuffList(Job);
return GetItemGroups(usersList, c => c.Income);
}
private static List<Group<T>> GetItemGroups<T>(IEnumerable<T> itemList, Func<T, int> getKeyFunc)
{
IEnumerable<Group<T>> groupList = from item in itemList
group item by getKeyFunc(item) into g
orderby g.Key
select new Group<T>(g.Key, g);
return groupList.ToList();
}
public class Group<T> : List<T>
{
public Group(int income, IEnumerable<T> items)
: base(items)
{
this.Income = income;
}
public int Income
{
get;
set;
}
}
My service interface:
[OperationContract]
IEnumerable<mTeachers> GetStuffList(string Job);
}
[DataContract]
public class mTeachers
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Income { get; set; }
[DataMember]
public string Job { get; set; }
[DataMember]
public System.Uri Flag { get; set; }
}
EDIT: WP page code:
public MainPage()
{
InitializeComponent();
ServiceReference1.Service1Client proxy = new ServiceReference1.Service1Client();
proxy.GetStuffListCompleted += showList;
proxy.GetStuffListAsync("teacher");
}
private void showList(object sender, ServiceReference1.GetStuffListCompletedEventArgs e)
{
this.longlist2.ItemsSource = e.Result;
}
Add ItemsSource="{Binding}" to the LongListSelector declaration in your XAML. So it should look like this.
<phone:LongListSelector x:Name="longlist2" Height="608" Margin="10,15,24,0" VerticalAlignment="Top" Width="422"
IsGroupingEnabled="True" LayoutMode="List" HideEmptyGroups="False"
ItemTemplate="{StaticResource usersItemTemplate}"
GroupHeaderTemplate="{StaticResource usersHeaderTemplate}"
JumpListStyle="{StaticResource LongListSelectorJumpListStyle}"
ListHeaderTemplate="{StaticResource usersListHeader}"
ListFooterTemplate="{StaticResource usersListFooter}"
ItemsSource="{Binding}" >
</phone:LongListSelector>
I think there are two things going on here.
First I think your GetStuffList(string Job) function is doing something weird, please check the return values to see if it's exactly what you want.
Second I think the ItemSource needs to be set like KasunKV said.
Here are my fixes and the resulting screenshot showing it works.
// create a static group list to see if it works
private List<Group<mTeachers>> GetUsersGroups(string Job)
{
List<mTeachers> usersList = new List<mTeachers>();
usersList.Add(new mTeachers() { Name = "Bob", Income = 1000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Dan", Income = 1000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Kate", Income = 2000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Girl" });
usersList.Add(new mTeachers() { Name = "Charlie", Income = 2000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Jeff", Income = 2000, Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
usersList.Add(new mTeachers() { Name = "Jeff2", Flag = new Uri(#"/Assets/AlignmentGrid.png", UriKind.Relative), Job = "Guy" });
return GetItemGroups(usersList, c => c.Income);
}
// Constructor
public MainPage()
{
InitializeComponent();
// create the user group and bind it to item source
this.longlist2.ItemsSource = GetUsersGroups("whatever");
}
Results of the change can be view here:

Categories