Getting content of checkboxes in xaml.cs in Silverlight - xaml

I am new to silverlight. I am trying to generate a list of checkboxes(with content). The idea is that the user will select some of these checkboxes and will press a button. Then we try to read the content of selected checkboxes for further processing. I don't know how many number of checkboxes will be there and therefore I can't use bindings.
This is the code snippet in the .xaml file.
<StackPanel Grid.Row="21" Grid.Column="1" Margin="5" VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ItemsControl Name="infoPairItems" ItemsSource="{Binding InfoPair}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Grid.Column="0" Name="infoPairSelectBox" IsEnabled="True" IsThreeState="False"
Margin="0,5" FontSize="12" IsChecked="bool"
Content="{Binding Converter={StaticResource infoPairToStringValueConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</StackPanel>
I am trying to access these checkboxes in the .xaml.cs file like this.
foreach(var infoPairItem in infoPairItems.Items)
{
ContentPresenter container = infoPairItems.ItemContainerGenerator.ContainerFromItem(infoPairItem) as ContentPresenter;
if(container == null)
{
DebugLog.Log("container is null ");
}
DataTemplate dataTemplate = container.ContentTemplate;
CheckBox checkBox = (CheckBox)dataTemplate.LoadContent();
if (checkBox == null)
{
DebugLog.Log("checkBox is null !!!");
return;
}
if (checkBox.IsChecked.HasValue)
{
if (checkBox.IsChecked.Value)
{
DebugLog.Log("checkbox value true");
}
else
{
DebugLog.Log("checkbox value false");
}
}
}
The log 'checkbox value false' is always getting printed for all the checkboxes even when some of them are selected. I tried to use the debugger. It looks like that variable container is getting loaded with the correct value. Either the method LoadContent() is not working or I am using the wrong method.
I apologize beforehand if it is a repeat question. I tried to look into the previous questions on stackoverflow but could not find any answer. Please guide me in correct direction.

I will explain what happens and how to solve:
1.- You are getting the datatemplate not instances of the datatemplate, in case you want to manage the instances you can do by using the Loaded Event to add items to the List to create and update for instance a List.
2.- What makes all of these events a really complex code to manage is easier if you create the following:
2.1 A class for instance that has a bool and a string for the content with INotifyPropertyChanged:
public class InfoSelection : Model
{
Property bool for Selected
Property string for Info, or whatever and the converter
}
2.2 A list with the items you need of the type of that class in the DataContext
public List<InfoSelection> {get;set;}
(If you initialize just once in the constructor for instance, you do not need to implement INotiyPropertyChanged, just clear or removeitems, never reassign)
2.3 In the Xaml binding change to the following:
<CheckBox Grid.Column="0"
Name="infoPairSelectBox"
IsEnabled="True"
IsThreeState="False"
Margin="0,5"
FontSize="12"
IsChecked="{Binding Selected, Mode=TwoWay}"
Content="{Binding Info}"/>

I don't know how many number of checkboxes will be there and therefore I can't use bindings.
Incorrect.
To Visually display two levels of data generically, the use of a ItemsControl with individual DataTemplate`s for the parent items and their child items can be done.
Then to allow for the editing (your deletion operation) one needs to identify who the parent node is from the child nodes, along with getting the state of the checkbox.
That identification requires us to project the initial data into a wrapper class to facilitate binding/identification.
Let me explain.
Say our data displays a top level last name and all first names associated with the last name.
The above simulates a top level checkbox (to delete all) and children checkbox (to delete an individual item) for the following data class retrieved from the database:
public class VectorStrings
{
public int Id { get; set; }
public string LastName { get; set; }
public List<string> FirstNames { get; set; }
}
With simulated data loaded as such:
LastNames = new List<VectorStrings>()
{
new VectorStrings() { Id=9, LastName="Smith", FirstNames = new List<string>() { "Bob", "Victoria" } },
new VectorStrings() { Id=12, LastName="Jones", FirstNames = new List<string>() { "Peter", "Paul", "Mary" } },
};
Now for display I can generically display those items to the above data, but because we need to operate on the child data, we need to project that information into a holding wrapper class.
public class VectorCheckbox
{
public int Id { get; set; }
public int ParentId { get; set; }
public string DisplayName { get; set; }
public List<VectorCheckbox> Children { get; set; }
public object Tag { get; set; } // Same concept as a visual control property 'Tag'
}
so our code to project the original data looks like this:
CheckBoxData =
LastNames.Select(ln => new VectorCheckbox()
{
DisplayName = ln.LastName,
Id = ln.Id,
Tag = ln,
Children = ln.FirstNames.Select((fn, index) => new VectorCheckbox()
{
Id = index,
ParentId = ln.Id,
DisplayName = fn,
Tag = ln.Id // Hold the parent Id for identification
}).ToList()
})
.ToList();
Sweet! Now we just need nested ItemControl classes to display our data:
<ItemsControl ItemsSource="{Binding CheckBoxData}">
<ItemsControl.Resources>
<system:String x:Key="Format">Delete All for ID: '{0}' </system:String>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Margin="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="6,0,0,0">
<CheckBox Tag="{Binding Id}" Margin="0,0,0,10" Click="DeleteAll_Click">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Id, StringFormat={StaticResource Format}}"/>
<TextBlock Text="{Binding DisplayName}" Margin="4,0,6,0"/>
<ItemsControl ItemsSource="{Binding Children}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Tag="{Binding Tag}"
Content="{Binding DisplayName}"
Click="DeleteIndividual_Click"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</CheckBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
Now in code behind we subscribe to the click events. I use a message box to show that I have identified the right items. For example if one clicks on a delete all check box, it identifies the children and the state of the checkbox, and if I click on a child it identifies its parent and itself.
Parent Click
private void DeleteAll_Click(object sender, RoutedEventArgs e)
{
var cb = sender as CheckBox;
if (cb != null)
{
var id = (int)cb.Tag;
var nameInstance = ViewModel.LastNames.FirstOrDefault(nm => nm.Id == id);
if (nameInstance != null)
MessageBox.Show(string.Format("Delete all for {0} of names {1} (Status {2})",
nameInstance.LastName,
string.Join(",", nameInstance.FirstNames),
((cb.IsChecked ?? false) ? "Checked" : "UnChecked")
));
}
}
Child Click
private void DeleteIndividual_Click(object sender, RoutedEventArgs e)
{
var cb = sender as CheckBox;
if (cb != null)
{
var parentId = (int)cb.Tag; // Parent Id
var nameInstance = ViewModel.LastNames.FirstOrDefault(nm => nm.Id == parentId);
if (nameInstance != null)
MessageBox.Show(string.Format("Delete individual for {0} of name {1} (Status {2})",
nameInstance.LastName,
cb.Content,
((cb.IsChecked ?? false) ? "Checked" : "UnChecked")
));
}
}
So from that I have identified the checkbox state along with the target original items. This code simulates ultimately what you want to do. I leave the actual plumbing of the observable collection remove items up to you. But this gets the idea across.
I recommend that you experiment in WPF then take it to Silverlight, for the concepts are the same, but its easier/faster to test out in WPF.

Related

How to display a label with click on listview

I want to show a label when i click on my item in my listview.
The real problem i don't know how to link between my viewmodel and my views
I want modify my label in viewmodel but I don't know if its possible currently.
My xaml :
<StackLayout>
<Label x:Name="labelperso"
Text="{Binding newProduct}"
IsVisible="{Binding Addproduct}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
BackgroundColor="#000000"
FontSize="20"
Opacity="0"/>
<ListView ItemsSource="{Binding Products}" CachingStrategy="RecycleElement" RowHeight="50" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding CodeReferenceLibelle}" TextColor="Black"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<b:EventToCommandBehavior EventName="ItemSelected" Command="{Binding
SelectCommand}" Converter="{StaticResource SelectedItemConverter}"/>
</ListView.Behaviors>
my viewmodel :
#region labelperso property
private string _newProduct;
public string newProduct
{
get { return _newProduct; }
set { SetProperty(ref _newProduct, value); }
}
#endregion
#region Addproduct property
private bool _Addproduct;
public bool Addproduct
{
get { return _Addproduct; }
set { SetProperty(ref _Addproduct, value); }
}
#endregion
when I click on my item :
async Task Select()
{
newProduct = "Produit ajouté !";
basketManager.AddProductSkuAsync(sku);
newProduct = "";
await Task.Run(() => ShowText());
}
//I have tried this but I can't use my label in my view
async Task ShowText()
{
await labelperso.FadeTo(1);
await Task.Delay(1000);
await labelperso.FadeTo(0);
}
Why are you want to take the label "labelperso" in VM ? you can use it in xaml.cs instead.
You just need to add the event ItemSelected like this:
<ListView ItemsSource="{Binding Products}" ItemSelected="OnSelection">
In xaml.cs
void OnSelection(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
//suppose the binding Object is Product
Product product = (Product)e.SelectedItem;
//labelperso.Text = "name = " + product.Name;
labelperso.FadeTo(1);
Task.Delay(1000);
labelperso.FadeTo(0);
}
Normally, VM are unrelated to Xaml, and we should not get labels from VM.
And we don't recommend it.But if you must, you can pass the Label in from the xaml.cs file like this:
You can define a variable in yourpage.xaml.cs:
public Label pageLabel;
and initial like this:
pageLabel = labelperso;
BindingContext = new YourViewmodel(this);
And in YourViewmodel.cs:
public Label ss;
public YourViewmodel(ContentPage parentPage)
{// here HomePage is your contentPage name of the page`
ss = ((HomePage)parentPage).pageLabel;//after this you can use it
}
You need to add a SelectedProduct property to your VM.
private string _SelectedProduct;
public string SelectedProduct
{
get { return _SelectedProduct; }
set { SetProperty(ref _SelectedProduct, value); }
}
You can then bind your ListView's SelectedItem to it
<ListView ItemsSource="{Binding Products}"
SelectedItem="{Binding SelectedProduct}"
CachingStrategy="RecycleElement"
RowHeight="50" >
You can then control the visibility of your label by binding to SelectedProduct via a "nullToVisibility" converter, or by using triggers etc.
You should try to use MVVM pattern rather than hacking with code behind.
Using MVVM you can add a Visible property to your viewmodel and bind the IsVisible property of the label to it.
Code will be much easy to read and maintain.

How to dynamically bind data in WPF notify Icon window

Hello I want to create notify icon to my task-bar and when I click that icon one popup window open and that popup showing me which tasks are I have to complete today and also want to show today's appointment list.
Doubts
Suppose I get 10 task from database for today's date then All task should be display with scroll bar.
How to bind data with WPF control([textBlock])?
How to create [textBlock] control dynamically means Suppose I get task description from description column then it display otherwise description [textBlock] is not create.
I have refereed following link to achieve this.
http://www.codeproject.com/Articles/36468/WPF-NotifyIcon
but I really don't know how to bind data with WPF application.
Edit the FancyPopup.xaml
Add:
<ListView ItemsSource="{Binding TasksCollection, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TaskName}"/>
</DataTemplate>
<ListView.ItemTemplate/>
</ListView>
In the code behind you can set your view model like this:
public FancyPopup()
{
InitializeComponent();
this.DataContext = new PopupViewModel();
}
And then in your ViewModel:
public ObservableCollection<TaskDataModel> tasksCollection;
public ObservableCollection<TaskDataModel> TasksCollection
{
get
{
if (tasksCollection == null)
{
tasksCollection = new ObservableCollection<TaskDataModel>();
}
return tasksCollection;
}
set
{
tasksCollection = value;
this.OnPropertyChanged("tasksCollection");
}
}
Where TaskDataModel is class describing your data model.
public class TaskDataModel : INotifyPropertyChanged
{
public TaskDataModel()
{
}
private string taskName;
public string TaskName
{
get { return taskName; }
set
{
if (taskName != value)
{
taskName = value;
OnPropertyChanged("TaskName");
}
}
}
}

How to Bind a column with a function which take the value of another column in parameter

For now, I have something like that (2 columns with dropboxes containing values independent from each other):
<xcdg:DataGridControl.Columns>
<xcdg:Column Title="A"
FieldName="A"
CellContentTemplate="{StaticResource ADT}"
GroupValueTemplate="{StaticResource ADT}"
Converter="{StaticResource AConverter}"
CellEditor="{StaticResource AEditor}"/>
<xcdg:Column Title="B"
FieldName="B"
CellContentTemplate="{StaticResource BDT}"
GroupValueTemplate="{StaticResource BDT}"
Converter="{StaticResource BConverter}"
CellEditor="{StaticResource BEditor}"/>
</xcdg:DataGridControl.Columns>
And I would like the B column to be a dropbox containing values depending on the value selected in the first column.
I don't know how to achieve that. I read about Binding.RelativeSource but I think it is not at all what I should use.
Thanks
I can think of two ways to do that, and since you didn't provide your exact case, i will provide a simple scenario and build my answer base on it,
let say you have a DataGrid with two editable columns (A and B), in the edit mode you can choose the A value from a combobox list, and then the B combobox will be filtered to show only the items whom their value starts with the A value for example, if A="aa", B should be {"aaaa","aabb"}, to implement that you need first a Model that represent the DataGrid Items
public class GridItem
{
public String A { get; set; }
public String B { get; set; }
}
In your codebehind / ViewModel define those properties (the DataGrid , and the comboboxes ItemSource Collections) :
private ObservableCollection<GridItem> _gridItemsCollection = new ObservableCollection<GridItem>()
{
new GridItem()
{
A="aa",
B="bbbb"
}
};
public ObservableCollection<GridItem> GridItemsCollection
{
get
{
return _gridItemsCollection;
}
set
{
if (_gridItemsCollection == value)
{
return;
}
_gridItemsCollection = value;
OnPropertyChanged();
}
}
//for the first Combobox
private ObservableCollection<String> _aCollection = new ObservableCollection<String>()
{
"aa",
"bb"
};
public ObservableCollection<String> ACollection
{
get
{
return _aCollection;
}
set
{
if (_aCollection == value)
{
return;
}
_aCollection = value;
OnPropertyChanged();
}
}
//for the second Combobox
private ObservableCollection<String> _bCollection ;
public ObservableCollection<String> BCollection
{
get
{
return _bCollection;
}
set
{
if (_bCollection == value)
{
return;
}
_bCollection = value;
OnPropertyChanged();
}
}
Define a full B collection from which your B combobox's itemsource will be populated
ObservableCollection<String> MainBCollection = new ObservableCollection<String>()
{
"aaaa",
"aabb",
"bbaa",
"bbbb"
};
Finally the population of the B combobox will be based on the selected item in the A combobox using this property,
private String _selectedAItem;
public String SelectedAItem
{
get
{
return _selectedAItem;
}
set
{
if (_selectedAItem == value)
{
return;
}
_selectedAItem = value;
OnPropertyChanged();
var returnedCollection = new ObservableCollection<String>();
foreach (var val in MainBCollection)
{
if (val.StartsWith(_selectedAItem))
{
returnedCollection.Add(value);
}
}
BCollection = new ObservableCollection<string>(returnedCollection);
}
}
You need of course to implement the INotifypropertyChanged Interface, so that the B Combobox Itemsource will be updated,
Now regarding the Xaml, due to some limitations in Xceed you need to specify the Combobox's ItemSource and SelectedItem using the RelativeSource and Ancestor binding,
<Grid >
<xcdg:DataGridControl ItemsSource="{Binding GridItemsCollection}" AutoCreateColumns="False" SelectionMode="Single" >
<xcdg:DataGridControl.Columns>
<xcdg:Column Title="A"
FieldName="A"
>
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
<xcdg:Column.CellEditor>
<xcdg:CellEditor>
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<ComboBox Name="AComboBox" SelectedItem="{Binding SelectedAItem, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}}" SelectedValue="{xcdg:CellEditorBinding}"
ItemsSource="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type wpfApplication3:MainWindow}},
Path=ACollection}">
</ComboBox>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
</xcdg:Column.CellEditor>
</xcdg:Column>
<xcdg:Column Title="B"
FieldName="B"
>
<xcdg:Column.CellContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</xcdg:Column.CellContentTemplate>
<xcdg:Column.CellEditor>
<xcdg:CellEditor>
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<ComboBox Name="AComboBox" SelectedValue="{xcdg:CellEditorBinding}" ItemsSource="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type Window}},
Path=BCollection}">
</ComboBox>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
</xcdg:CellEditor>
</xcdg:Column.CellEditor>
</xcdg:Column>
</xcdg:DataGridControl.Columns>
</xcdg:DataGridControl>
</Grid>
and the result is something like that
The Other way to do that is by using a MultivalueConverter and update the B Collection eachtime the A SelectedValue is changed,
something like that :
<xcdg:CellEditor.EditTemplate>
<DataTemplate>
<ComboBox Name="AComboBox" SelectedValue="{xcdg:CellEditorBinding}">
<ComboBox.ItemsSource>
<MultiBinding Converter="{StaticResource BCollectionConverter}">
<Binding Path="BCollection" RelativeSource="{RelativeSource AncestorType={x:Type Window}}"/>
<Binding Path="SelectedValue" ElementName="AComboBox" />
</MultiBinding>
</ComboBox.ItemsSource>
</ComboBox>
</DataTemplate>
</xcdg:CellEditor.EditTemplate>
And implement the converter to update the B Combobox's ItemSource,
public class BCollectionConverter:IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null)
return null;
var bCollection = (values[0] as ObservableCollection<String>);
var aSelectedItem = (values[1] as String);
if (aSelectedItem == null)
return null;
var returnedCollection = new ObservableCollection<String>();
foreach (var value in bCollection)
{
if (value.StartsWith(aSelectedItem))
{
returnedCollection.Add(value);
}
}
return returnedCollection;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I didn't try that last one, you might as well give it a try, I hope that did help.

How to list AlbumArt from MediaLibrary on WP?

I've been looking for a long time how to list album cover from Windows Phone Media Library, but I didn't found any answer.
I'm developping a music player for wp8, and actually I can successfully list album info as album name, artist name, duration, etc, but I can't get the AlbumArt.
Here is the code I'm actually using :
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="AlbumInfoTemplate">
<StackPanel VerticalAlignment="Top" Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Image Source=" " Margin="5" Height="80" Width="80" Stretch="UniformToFill"/>
<StackPanel Grid.Column="1">
<TextBlock FontWeight="Normal" Text="{Binding Name}" Margin="10,0,0,0" FontSize="25" Foreground="Black"/>
<TextBlock FontWeight="Normal" Text="{Binding Artist}" Margin="10,0,0,0" FontSize="20" Foreground="Black" Opacity="0.75"/>
</StackPanel>
</Grid>
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<phone:LongListSelector
x:Name="llsAlbums"
SelectionChanged="llsAlbums_SelectionChanged"
Margin="0,-35,0,0"
JumpListStyle="{StaticResource JumpListStyle}"
Background="Transparent"
GroupHeaderTemplate="{StaticResource GroupHeaderTemplate}"
ItemTemplate="{StaticResource AlbumInfoTemplate}"
LayoutMode="List"
IsGroupingEnabled="true"
HideEmptyGroups ="true"/>
Hope you could help me guys !
Before anything you need to do a small modification to the LongListSelector definition in XAML. Add this ItemsSource="{Binding}" to it. Then is should look like this.
<phone:LongListSelector
x:Name="llsAlbums"
SelectionChanged="llsAlbums_SelectionChanged"
Margin="0,-35,0,0"
JumpListStyle="{StaticResource JumpListStyle}"
Background="Transparent"
GroupHeaderTemplate="{StaticResource GroupHeaderTemplate}"
ItemTemplate="{StaticResource AlbumInfoTemplate}"
LayoutMode="List"
IsGroupingEnabled="true"
HideEmptyGroups ="true"
ItemsSource="{Binding}"/>
Since you are using JumpLists and GroupHeaders in the LongListSelector, you need to to more work than usual. Start off with creating a class to hold the Album information. Lets call it MusicAlbum Its like this.
public class MusicAlbum
{
public string Name { get; set; }
public string Artist { get; set; }
public BitmapImage Art { get; set; }
}
Then create this class and methods included for the GroupHeaders and JumpLists to work.
public class AlphaKeyGroup<T> : List<T>
{
public delegate string GetKeyDelegate(T item);
public string Key { get; private set; }
public AlphaKeyGroup(string key)
{
Key = key;
}
private static List<AlphaKeyGroup<T>> CreateGroups(SortedLocaleGrouping slg)
{
List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>();
foreach (string key in slg.GroupDisplayNames)
{
list.Add(new AlphaKeyGroup<T>(key));
}
return list;
}
public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
{
SortedLocaleGrouping slg = new SortedLocaleGrouping(ci);
List<AlphaKeyGroup<T>> list = CreateGroups(slg);
foreach (T item in items)
{
int index = 0;
index = slg.GetGroupIndex(getKey(item));
if (index >= 0 && index < list.Count)
{
list[index].Add(item);
}
}
if (sort)
{
foreach (AlphaKeyGroup<T> group in list)
{
group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
}
}
return list;
}
}
Here i have written a small method to get the Album Art for the album, this makes it easy.
private BitmapImage GetAlbumArt(Album album)
{
BitmapImage img = new BitmapImage();
img.DecodePixelHeight = 80;
img.DecodePixelWidth = 80;
img.SetSource(album.GetAlbumArt());
return img;
}
Then this actual methods gets the list of albums from the MediaLibrary and makes a list of MusicAlbums we can use in the LLS
public List<MusicAlbum> GetAlbums()
{
if (lib == null)
lib = new MediaLibrary();
List<MusicAlbum> albumList = new List<MusicAlbum>();
var albums = lib.Albums;
foreach (var album in albums)
{
albumList.Add(new MusicAlbum()
{
Name = album.Name,
Artist = album.Artist.Name,
Art = album.HasArt ? GetAlbumArt(album) : null
});
}
return albumList;
}
After doing this, you need to make the list and set the ItemSource of the LongListSelector. In the Constructor of the page or in OnNavigatedTo method add this code.
List<AlphaKeyGroup<MusicAlbum>> albumList = AlphaKeyGroup<MusicAlbum>.CreateGroups(this.GetAlbums() as List<MusicAlbum>, Thread.CurrentThread.CurrentUICulture, (MusicAlbum s) => { return s.Name; }, true);
llsAlbums.ItemsSource = albumList;
Then you are done, run the app and you will see the albums listed..

Bind a grouped Collection in Xaml

I've searched a bit, but the info I've found isn't what I need. So I decided to ask you all - I'm sure it's a newbie question but i really don't get it.
Let's start:
I have a DataSource which is a grouped observable collection. At the moment I've 2 groups with a different count of items. The two groups and the items belong to the same common base:
public DataCommon(String uniqueId, String title, String subtitle, String imagePath, String description)
{
this._uniqueId = uniqueId;
this._title = title;
this._subtitle = subtitle;
this._description = description;
this._imagePath = imagePath;
}
This is the constructor of the model.
In the ViewModel I fill it.
Now I would like bind the ItemClick with a Command to my ViewModel. I do like this (only a short part):
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="2"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
>
<WinRtBehaviors:Interaction.Behaviors>
<Win8nl_Behavior:EventToCommandBehavior Event="ItemClick" Command="ItemClickCommand" CommandParameter="{Binding UniqueId}"/>
</WinRtBehaviors:Interaction.Behaviors>
But now the problem. At the "Binding UniqueId" it's saying the DataContext is my ViewModel, so i can't connect it to the properties of the Model. Looked at the Page.DataContext i told XAML tu use my ViewModel as DataContext. I guess this was correct. But how can I access the Model-properties?
I've tried to do it like this (defined my Model as DataModel):
<WinRtBehaviors:Interaction.Behaviors>
<Win8nl_Behavior:EventToCommandBehavior Event="ItemClick" Command="ItemClickCommand" CommandParameter="{Binding DataModel:SampleDataCommon.UniqueId}"/>
</WinRtBehaviors:Interaction.Behaviors>
but as I guessed beforehand it didn't work - as parameter i get null.
I would be thankful for any help, because as i said at the beginning of the post: I really don't get it...
You can't use EventToCommandBehavior in this way - this was also stated by its author in the comments.
I'm using the following attached property in such cases:
public static class ItemClickBehavior
{
public static DependencyProperty ItemClickCommandProperty = DependencyProperty.RegisterAttached("ItemClickCommand",
typeof(ICommand),
typeof(ItemClickBehavior),
new PropertyMetadata(null, OnItemClickCommandChanged));
public static void SetItemClickCommand(DependencyObject target, ICommand value)
{
target.SetValue(ItemClickCommandProperty, value);
}
public static ICommand GetItemClickCommand(DependencyObject target)
{
return (ICommand)target.GetValue(ItemClickCommandProperty);
}
private static void OnItemClickCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
var element = target as ListViewBase;
if (element != null)
{
// If we're putting in a new command and there wasn't one already
// hook the event
if ((e.NewValue != null) && (e.OldValue == null))
{
element.ItemClick += OnItemClick;
}
// If we're clearing the command and it wasn't already null
// unhook the event
else if ((e.NewValue == null) && (e.OldValue != null))
{
element.ItemClick -= OnItemClick;
}
}
}
static void OnItemClick(object sender, ItemClickEventArgs e)
{
GetItemClickCommand(sender as ListViewBase).Execute(e.ClickedItem);
}
}
This is how you would bind a command to it:
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Grid.RowSpan="2"
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
SelectionMode="None"
IsSwipeEnabled="false"
IsItemClickEnabled="True"
itbmb:ItemClickBehavior.ItemClickCommand="{Binding ItemClickCommand}"
>
I guess it wouldn't be all that difficult to create a behavior from the attached property if you really wanted to.