How to bind data to Dynamic LongListSelector - xaml

Hi I have a Pivot with dynamic PivotItems and I need put LongListSelector with StackPanels with TextBlock into PivotItem. I have a problem with binding text in TextBlock. Binding PivotHeader works fine but I don't know how to bind Name with TextBlock.
XAML
<phone:Pivot x:Name="ShelfsPivot">
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
<phone:LongListSelector ItemsSource="{Binding LongListSelector}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
and code behind
public class LongListData
{
public string Name { get; set; }
}
public class PivotData
{
public string Header { get; set; }
public LongListSelector LongListSelector { get; set; }
}
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
var pivotDataList = new List<PivotData>();
var pivotItem1 = new PivotData {Header = "Header1", LongListSelector = new LongListSelector()};
var pivotItem2 = new PivotData {Header = "Header2", LongListSelector = new LongListSelector()};
pivotDataList.Add(pivotItem1);
pivotDataList.Add(pivotItem2);
ShelfsPivot.ItemsSource = pivotDataList;
var list = new List<LongListData>();
var item0 = new LongListData {Name = "Item1"};
var item1 = new LongListData {Name = "Item2"};
var item2 = new LongListData {Name = "Item3"};
list.Add(item0);
list.Add(item1);
list.Add(item2);
foreach (var pivotItem in ShelfsPivot.Items)
{
var longlist = pivotItem as PivotData;
if (longlist != null)
longlist.LongListSelector.ItemsSource = list;
}
}
}

The item binding for LongListSelector shouldn't be itself a LongListSelector, it should be either a List or an ObservableCollection. If it's static data, use a List. If it's dynamic data, use an ObservableCollection.
So, it should look similar to this.
public class LongListData
{
public string Name { get; set; }
}
public class PivotData
{
public string Header { get; set; }
public ObservableCollection<LongListData> ListData { get; set; }
}
public MainPage()
{
InitializeComponent();
var list = new ObservableCollection<LongListData>();
var item0 = new LongListData {Name = "Item1"};
var item1 = new LongListData {Name = "Item2"};
var item2 = new LongListData {Name = "Item3"};
list.Add(item0);
list.Add(item1);
list.Add(item2);
var pivotDataList = new List<PivotData>();
var pivotItem1 = new PivotData {Header = "Header1", ListData = list};
var pivotItem2 = new PivotData {Header = "Header2", ListData = list};
pivotDataList.Add(pivotItem1);
pivotDataList.Add(pivotItem2);
ShelfsPivot.ItemsSource = pivotDataList;
}
With your binding looking like this.
<phone:Pivot.ItemTemplate>
<DataTemplate>
<phone:LongListSelector ItemsSource="{Binding ListData}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</DataTemplate>
</phone:Pivot.ItemTemplate>
Hope this helps and happy coding!

Related

How to create a list view with checkbox item with select all check box in uwp

I want to create a ListView which contains the department name. The ListView contains the CheckBox with department names. An user can check and unchecked the department and also the user can on clicking on select all check box user can select all department.
Which listview you want either a simple listview with textcell or imagecellits upto you, Here I'm posting code for listview with imagecell, also cell swipe option and just add Checkbox where you want to with its event and apply logics. Hope it works for you!
<AbsoluteLayout>
<ListView x:Name="Demolist" BackgroundColor="White" ItemSelected="Demolist_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell Height="30"
Text="{Binding deparment_name }"
Detail="{Binding department_description}"
ImageSource="ImageName.png">
<ImageCell.ContextActions>
<MenuItem x:Name="OnMore" Clicked="OnMore_Clicked" CommandParameter="{Binding .}" Text="More" />
<MenuItem x:Name="OnDelete" Clicked="OnDelete_Clicked" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" />
</ImageCell.ContextActions>
</ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</AbsoluteLayout>
Checkbox is not a control present in XF framework, so I think you can not add checkbox in listview in Xamarin.form, but you can use different to display check and uncheck status.
<ContentPage
x:Class="test2.Page3"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:convert="clr-namespace:test2"
x:Name="ToDoPage">
<ContentPage.Resources>
<convert:converter1 x:Key="converterbool" />
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<ListView x:Name="listview1" ItemsSource="{Binding todoList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding ItemDescription}" VerticalOptions="Center" />
<Button
Grid.Column="1"
Command="{Binding Source={x:Reference ToDoPage}, Path=BindingContext.UpdateCheckBoxCommand}"
CommandParameter="{Binding Id}"
Opacity="0" />
<Image
Grid.Column="1"
HeightRequest="20"
HorizontalOptions="Center"
Source="{Binding IsDone, Converter={StaticResource converterbool}}"
VerticalOptions="Center" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
public class TodoItem:INotifyPropertyChanged
{
private string _Id;
public string Id
{
get { return _Id; }
set
{
_Id = value;
RaisePropertyChanged("Id");
}
}
private string _ItemDescription;
public string ItemDescription
{
get { return _ItemDescription; }
set
{
_ItemDescription = value;
RaisePropertyChanged("ItemDescription");
}
}
private bool _IsDone;
public bool IsDone
{
get { return _IsDone; }
set
{
_IsDone = value;
RaisePropertyChanged("IsDone");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
class ToDoViewModel:INotifyPropertyChanged
{
public ObservableCollection<TodoItem> todoList { get; set; }
public ICommand UpdateCheckBoxCommand { get; set; }
public ToDoViewModel()
{
todoList = new ObservableCollection<TodoItem>()
{
new TodoItem(){ Id = "1", ItemDescription = "Task 1", IsDone = false},
new TodoItem(){ Id = "2", ItemDescription = "Task 2", IsDone = false},
new TodoItem(){ Id = "3", ItemDescription = "Task 3", IsDone = false},
new TodoItem(){ Id = "4", ItemDescription = "Task 4", IsDone = false},
new TodoItem(){ Id = "5", ItemDescription = "Task 5",IsDone=false }
};
UpdateCheckBoxCommand = new Command((Id) => UpdateCheckBox(Id.ToString()));
}
private void UpdateCheckBox(string id)
{
IEnumerable<TodoItem> items = todoList.Where(x=>x.Id==id);
foreach(var item in items )
{
if (item.IsDone) item.IsDone = false;
else item.IsDone = true;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
class converter1 : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool ischeck = (bool)value;
if(ischeck==false)
{
return "uncheck.png";
}
else
{
return "check.png";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Page3 : ContentPage
{
public Page3 ()
{
InitializeComponent ();
this.BindingContext = new ToDoViewModel();
}
}

Change color in listview item and remove item UWP

I would remove an item with button inside listview item and change color of ellipse with another button in listview item.
The class product code:
class Product
{
public string Name { get; set; }
public double Price { get; set; }
}
The xaml mainpage code:
<Page
x:Class="ListViewTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ListViewTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Loaded="Page_Loaded">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="ListViewProducts"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
FontSize="18"
BorderThickness="0"
Width="600"
Height="800"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ItemsSource="{Binding LineItems}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<Grid HorizontalAlignment="Left" VerticalAlignment="Center" Margin="5,0,0,0">
<Ellipse x:Name="EllipseColor" HorizontalAlignment="Left" Height="20" Stroke="Black" VerticalAlignment="Top" Width="20" StrokeThickness="1"/>
</Grid>
<TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
<TextBlock Text="{Binding Price}" Margin="5,0,0,0"/>
<Button x:Name="btnRemove" Click="btnRemove_Click" Height="20" Width="60" Margin="5"/>
<Button x:Name="btnChangeColor" Click="btnChangeColor_Click" Height="20" Width="60" Margin="5"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
The code behind of mainpage:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
ObservableCollection<Product> _listProduct = new ObservableCollection<Product>();
_listProduct = new ObservableCollection<Product>
{
new Product
{
Name = "Phone",
Price = 100
},
new Product
{
Name = "TV",
Price = 120
},
new Product
{
Name = "Computer",
Price = 80
},
new Product
{
Name = "Laptop",
Price = 250
},
new Product
{
Name = "Tablet",
Price = 150
},
new Product
{
Name = "Monitor",
Price = 200
},
};
ListViewProducts.ItemsSource = _listProduct;
}
private void btnRemove_Click(object sender, RoutedEventArgs e)
{
// Code to remove item
}
private void btnChangeColor_Click(object sender, RoutedEventArgs e)
{
// Code to color EllipseColor
}
}
With btnRemove i would delete listview item and with btnChangeColor i would color red the fill of EllipseColor, in btnChangeColor_Click i would the index of item.
Thanks in advance.
It looks to me like you've got several issues. First off is that you're setting your ListView source via binding to an apparently non-existent collection, as well as setting it in C#. You should move it to using a proper binding. For example, in MainPage.xaml.cs:
private ObservableCollection<Product> _products = new ObservableCollection<Product>();
public ObservableCollection<Product> Products { get => _products; set => _products = value; }
And then bind to it:
<ListView ItemsSource={x:Bind Products, Mode=OneWay} />
Then, in btnRemove_Click, you can just remove the item from the collection:
var product = (sender as Button).DataContext as Product;
Products.Remove(product);
As for coloring the Ellipse, you shouldn't really do that in C#. Instead, you should have a Status property on your Product class, and then change that property.
First off, you'll need to make sure your property changes fire notifications.
public class Product : INotifyPropertyChanged
{
private string _status;
public string Status
{
get => _status;
set
{
_status = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Status)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Then change the property.
var product = (sender as Button).DataContext as Product;
product.Status = "invalid";
Then in your XAML, use a binding converter to change the Ellipse's Fill property based on the status. E.g.
using System;
using Windows.UI;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
public class StatusConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language) =>
new SolidColorBrush(value.ToString() == "invalid" ? Colors.Red : Colors.Gray);
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
throw new NotImplementedException();
}
You'll then need to add the converter to your resources.
<Page...>
<Page.Resources>
<locationofyourconverter:StatusConverter x:Key="StatusConverter" />
</Page.Resources>
...
<Ellipse Fill={Binding Status, Mode=OneWay, Converter={StaticResource StatusConverter}} />

How to add multiple pivots using DataTemplate in winrt UWP?

I have a condition where I want to add multiple PivotItems(which is dynamic).
ie; I have a List<CustomModel> whose size is dynamic, And for every item in the List I want to create a PivotItem with header as CustomModel.Title.
Is it possible to achieve this with xaml alone by creating a DataTemplate and binding it to a Pivot?
It is surely possible. See below sample solution
<Pivot x:Name="TestPivot">
<Pivot.HeaderTemplate>
<DataTemplate x:DataType="local:TestClass">
<TextBlock Text="{Binding HeaderTitle, Mode=OneWay}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate x:DataType="local:TestClass">
<Grid>
<TextBlock Text="{Binding Content, Mode=OneWay}"/>
</Grid>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
Code behind for simulating the binding
public sealed partial class BlankPage6 : Page
{
ObservableCollection<TestClass> SampleSource = new ObservableCollection<TestClass>();
public BlankPage6()
{
this.InitializeComponent();
SampleSource.Add(new TestClass { HeaderTitle = "Test Header1", Content = "Test content 1" });
SampleSource.Add(new TestClass { HeaderTitle = "Test Header2", Content = "Test content 2" });
SampleSource.Add(new TestClass { HeaderTitle = "Test Header3", Content = "Test content 3" });
TestPivot.ItemsSource = SampleSource;
}
}
public class TestClass
{
public string HeaderTitle { get; set; }
public string Content { get; set; }
}
Output:

LonglistSelector binding to Image Collection does not display

I have a xaml page. xaml page wants to show two TextBlocks and one LonglistSelector.
the two TextBlocks datasource come from an object(SpecifiedArticle);the LonglistSelctor itemsSource comes from Collection(ImageUriCollection).
when the page launch, the images cannot be displayed.
two TextBlocks data show well
LonglistSelctor does not show images; but i am sure ImageUriCollection's data can be get from the xaml because i tested in a image control and it works
<Image Source="{Binding ImageUriCollection[0].ImageSource}" Width="108" Height="108" Stretch="UniformToFill">
</Image>
i think the issue is in the LonglistSelctor itemsSource binding. anyone can help?
all code below(without the httpclient wrapper):
DetailsPage.cs is below:
public partial class DetailsPage : PhoneApplicationPage
{
DetailsPageViewModel viewModel = new DetailsPageViewModel();
public DetailsPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(DetailsPage_Loaded);
}
private void DetailsPage_Loaded(object sender, RoutedEventArgs e)
{
DataContext = viewModel;
//imageList.ItemsSource = viewModel.ImageUriCollection;
//imageList.ScrollTo(imageList.ItemsSource[imageList.ItemsSource.Count - 1]);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string ArticleId = "";
try
{
if (NavigationContext.QueryString.TryGetValue("ArticleId", out ArticleId))
{
Debug.WriteLine(ArticleId);
viewModel.LoadPage(Int32.Parse(ArticleId));
//Debug.WriteLine(viewModel.SpecifiedArticle.Words.ToString());
//LayoutRoot.DataContext = new CollectionViewSource { Source = viewModel.SpecifiedArticle };
}
else
{
MessageBox.Show("No ArticleId passed in.");
}
}
catch(Exception ex)
{
MessageBox.Show("Error in DetailsPage.OnNavigatedTo");
}
}
}
ViewModel is below:
public class DetailsPageViewModel : INotifyPropertyChanged
{
private bool _isLoading = false;
public bool IsLoading
{
get
{
return _isLoading;
}
set
{
_isLoading = value;
NotifyPropertyChanged("IsLoading");
}
}
public DetailsPageViewModel()
{
this.SpecifiedArticle = new Article();
this.ImageUriCollection = new ObservableCollection<Photo>();
this.IsLoading = false;
}
private Article specifiedArticle;
public Article SpecifiedArticle
{
get
{
return specifiedArticle;
}
set
{
specifiedArticle = value;
NotifyPropertyChanged("SpecifiedArticle");
}
}
public ObservableCollection<Photo> ImageUriCollection
{
get;
private set;
}
public void LoadPage(int articleId)
{
IsLoading = true;
ReadArticle(articleId);
}
private async void ReadArticle(int articleId)
{
try
{
Article articleDetails = new Article();
articleDetails = await CollectionHttpClient.GetAsyncByArticleId(articleId);
SpecifiedArticle = articleDetails;
//articleDetails.FirstImage = new Uri(articleDetails.ImagePathList[0]);
if (articleDetails.ImagePathList != null)
{
foreach (var item in articleDetails.ImagePathList)
{
Photo p = new Photo();
p.ImageSource = new Uri(item);
this.ImageUriCollection.Add(p);
}
//var image = await CollectionHttpClient.GetImageByImageName(articleDetails.ImagePath);
//Bytelist.Add(image);
}
else
{
this.ImageUriCollection = null;
}
IsLoading = false;
}
catch(Exception ex)
{
MessageBox.Show("sorry, no data.");
IsLoading = false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
xaml is:
<phone:PhoneApplicationPage.Resources>
<vm:DetailsPageViewModel x:Key="viewModel"/>
<phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>
<phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>
<Style x:Key="JumpListStyle" TargetType="phone:LongListSelector">
<Setter Property="LayoutMode" Value="List" />
<Setter Property="Margin" Value="12,12,0,0"/>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundConverter}}"
Width="470"
Height="70"
Margin="6">
<TextBlock Text="{Binding Key}"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"
FontSize="28"
Padding="2"
VerticalAlignment="Bottom"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="GroupHeader">
<Border Background="Transparent">
<Border Background="Transparent" BorderBrush="Transparent" BorderThickness="1"
Width="400" Height="90"
HorizontalAlignment="Left">
<TextBlock Text="Pictures:"
Foreground="{StaticResource PhoneAccentBrush}"
FontSize="28"
Padding="2"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
</Border>
</Border>
</DataTemplate>
<DataTemplate x:Key="ItemTemplate">
<StackPanel Height="108" Width="108" Margin="6,6">
<Image Width="108" Height="108" Stretch="UniformToFill">
<Image.Source>
<BitmapImage UriSource="{Binding ImageSource}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="{Binding Path=SpecifiedArticle.Subject }" TextWrapping="Wrap" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place images here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Background="Transparent">
<!--
<Image Source="{Binding ImageUriCollection[0].ImageSource}" Width="108" Height="108" Stretch="UniformToFill">
<Image.Source>
<BitmapImage UriSource="{Binding ImageSource}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
-->
<phone:LongListSelector Name="imageList" Margin="13,-30,0,0"
ItemsSource="{Binding ImageUriCollection}"
ItemTemplate="{StaticResource ItemTemplate}"
JumpListStyle="{StaticResource JumpListStyle}"
IsGroupingEnabled="True"
LayoutMode="Grid"
GridCellSize="108,108"/>
</Grid>
<!--ContentPanel - place article words here-->
<StackPanel Grid.Row="2" Margin="12,17,0,28">
<TextBlock Text="{Binding Path=SpecifiedArticle.Words}" TextWrapping="Wrap" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
</Grid>
DetailsPage.cs is below:
public partial class DetailsPage : PhoneApplicationPage
{
DetailsPageViewModel viewModel = new DetailsPageViewModel();
public DetailsPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(DetailsPage_Loaded);
}
private void DetailsPage_Loaded(object sender, RoutedEventArgs e)
{
DataContext = viewModel;
//imageList.ItemsSource = viewModel.ImageUriCollection;
//imageList.ScrollTo(imageList.ItemsSource[imageList.ItemsSource.Count - 1]);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string ArticleId = "";
try
{
if (NavigationContext.QueryString.TryGetValue("ArticleId", out ArticleId))
{
Debug.WriteLine(ArticleId);
viewModel.LoadPage(Int32.Parse(ArticleId));
//Debug.WriteLine(viewModel.SpecifiedArticle.Words.ToString());
//LayoutRoot.DataContext = new CollectionViewSource { Source = viewModel.SpecifiedArticle };
}
else
{
MessageBox.Show("No ArticleId passed in.");
}
}
catch(Exception ex)
{
MessageBox.Show("Error in DetailsPage.OnNavigatedTo");
}
}
}
ViewModel is below:
public class DetailsPageViewModel : INotifyPropertyChanged
{
private bool _isLoading = false;
public bool IsLoading
{
get
{
return _isLoading;
}
set
{
_isLoading = value;
NotifyPropertyChanged("IsLoading");
}
}
public DetailsPageViewModel()
{
this.SpecifiedArticle = new Article();
this.ImageUriCollection = new ObservableCollection<Photo>();
this.IsLoading = false;
}
private Article specifiedArticle;
public Article SpecifiedArticle
{
get
{
return specifiedArticle;
}
set
{
specifiedArticle = value;
NotifyPropertyChanged("SpecifiedArticle");
}
}
public ObservableCollection<Photo> ImageUriCollection
{
get;
private set;
}
public void LoadPage(int articleId)
{
IsLoading = true;
ReadArticle(articleId);
}
private async void ReadArticle(int articleId)
{
try
{
Article articleDetails = new Article();
articleDetails = await CollectionHttpClient.GetAsyncByArticleId(articleId);
SpecifiedArticle = articleDetails;
//articleDetails.FirstImage = new Uri(articleDetails.ImagePathList[0]);
if (articleDetails.ImagePathList != null)
{
foreach (var item in articleDetails.ImagePathList)
{
Photo p = new Photo();
p.ImageSource = new Uri(item);
this.ImageUriCollection.Add(p);
}
//var image = await CollectionHttpClient.GetImageByImageName(articleDetails.ImagePath);
//Bytelist.Add(image);
}
else
{
this.ImageUriCollection = null;
}
IsLoading = false;
}
catch(Exception ex)
{
MessageBox.Show("sorry, no data.");
IsLoading = false;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Try this-
just change your ItemTemplate DataTemplate to a simpler one
If it works, add one change at a time.
<DataTemplate x:Key="ItemTemplate">
<Image Source="{Binding ImageSource}" Stretch="UniformToFill"/>
</DataTemplate>
it is the style problem.
delete the style, try again, images show well
<phone:LongListSelector Name="imageList" Margin="13,-30,0,0"
ItemsSource="{Binding ImageUriCollection}"
ItemTemplate="{StaticResource ItemTemplate}"
LayoutMode="Grid"
GridCellSize="108,108">
</phone:LongListSelector>
in the JumpListStyle, it contains the textblock which is not belong to the xaml, that is why the LonglistSelector does not display anything after binding collectly.

Issue with multiselect combobox control in Windows 8

I am creating a multiselect combobox in Windows 8 as shown in below image:
For this I have created custom control code for which is mentioned below:
The problem with below code is that
on selecting all the all items are not selected
Selected items are not displayed in textbox
How can I fix that?
XAML:
<UserControl
x:Class="App5.MultiSelectComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App5"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
x:Name="thisUC"
d:DesignWidth="400">
<ComboBox
x:Name="MultiSelectCombo"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Width="400" Height="20"
>
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Title}" Foreground="Black"
IsChecked="{Binding ElementName=thisUC, Path=IsSelected, Mode=TwoWay}"
Click="CheckBox_Click" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ControlTemplate TargetType="ComboBox">
<Grid >
<ToggleButton
x:Name="ToggleButton"
Grid.Column="2" IsChecked="{TemplateBinding IsDropDownOpen}"
ClickMode="Press" HorizontalContentAlignment="Left" >
<ToggleButton.Template>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="18"/>
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
CornerRadius="2"
Background="White"
BorderBrush="Black"
BorderThickness="1,1,1,1" />
<Border
x:Name="BorderComp"
Grid.Column="0"
CornerRadius="2"
Margin="1"
Background="White"
BorderBrush="Black"
BorderThickness="0,0,0,0" >
<TextBlock Foreground="Black" Text="{TemplateBinding TextValue}"
Padding="3" />
</Border>
<Path
x:Name="Arrow"
Grid.Column="1"
Fill="Black"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
<Popup
Name="Popup"
IsOpen="{TemplateBinding IsDropDownOpen}"
>
<Grid
Name="DropDown"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder"
BorderThickness="1" Background="White"
BorderBrush="Black"/>
<ScrollViewer Margin="4,6,4,6" DataContext="{Binding}">
<StackPanel />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<!--<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
</ControlTemplate.Triggers>-->
</ControlTemplate>
</ComboBox>
</UserControl>
C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
namespace App5
{
public sealed partial class MultiSelectComboBox : UserControl
{
private ObservableCollection<Node> _nodeList;
public MultiSelectComboBox()
{
InitializeComponent();
_nodeList = new ObservableCollection<Node>();
}
#region Dependency Properties
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(Dictionary<string, object>), typeof(MultiSelectComboBox), new PropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnItemsSourceChanged)));
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(Dictionary<string, object>), typeof(MultiSelectComboBox), new PropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedItemsChanged)));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("TextValue", typeof(string), typeof(MultiSelectComboBox), new PropertyMetadata(null));
public static readonly DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new PropertyMetadata(null));
public Dictionary<string, object> ItemsSource
{
get { return (Dictionary<string, object>)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
}
}
public Dictionary<string, object> SelectedItems
{
get { return (Dictionary<string, object>)GetValue(SelectedItemsProperty); }
set
{
SetValue(SelectedItemsProperty, value);
}
}
public string TextValue
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string DefaultText
{
get { return (string)GetValue(DefaultTextProperty); }
set { SetValue(DefaultTextProperty, value); }
}
#endregion
#region Events
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.DisplayInControl();
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.SelectNodes();
control.SetText();
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox clickedBox = (CheckBox)sender;
if (clickedBox.Content == "All")
{
if (clickedBox.IsChecked.Value)
{
foreach (Node node in _nodeList)
{
node.IsSelected = true;
}
}
else
{
foreach (Node node in _nodeList)
{
node.IsSelected = false;
}
}
}
else
{
int _selectedCount = 0;
foreach (Node s in _nodeList)
{
if (s.IsSelected && s.Title != "All")
_selectedCount++;
}
if (_selectedCount == _nodeList.Count - 1)
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = true;
else
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = false;
}
SetSelectedItems();
SetText();
}
#endregion
#region Methods
private void SelectNodes()
{
foreach (KeyValuePair<string, object> keyValue in SelectedItems)
{
Node node = _nodeList.FirstOrDefault(i => i.Title == keyValue.Key);
if (node != null)
node.IsSelected = true;
}
}
private void SetSelectedItems()
{
if (SelectedItems == null)
SelectedItems = new Dictionary<string, object>();
SelectedItems.Clear();
foreach (Node node in _nodeList)
{
if (node.IsSelected && node.Title != "All")
{
if (this.ItemsSource.Count > 0)
SelectedItems.Add(node.Title, this.ItemsSource[node.Title]);
}
}
}
private void DisplayInControl()
{
_nodeList.Clear();
if (this.ItemsSource.Count > 0)
_nodeList.Add(new Node("All"));
foreach (KeyValuePair<string, object> keyValue in this.ItemsSource)
{
Node node = new Node(keyValue.Key);
_nodeList.Add(node);
}
MultiSelectCombo.ItemsSource = _nodeList;
}
private void SetText()
{
if (this.SelectedItems != null)
{
StringBuilder displayText = new StringBuilder();
foreach (Node s in _nodeList)
{
if (s.IsSelected == true && s.Title == "All")
{
displayText = new StringBuilder();
displayText.Append("All");
break;
}
else if (s.IsSelected == true && s.Title != "All")
{
displayText.Append(s.Title);
displayText.Append(',');
}
}
this.TextValue = displayText.ToString().TrimEnd(new char[] { ',' });
}
// set DefaultText if nothing else selected
if (string.IsNullOrEmpty(this.TextValue))
{
this.TextValue = this.DefaultText;
}
}
#endregion
}
public class Node : INotifyPropertyChanged
{
private string _title;
private bool _isSelected;
#region ctor
public Node(string title)
{
Title = title;
}
#endregion
#region Properties
public string Title
{
get
{
return _title;
}
set
{
_title = value;
NotifyPropertyChanged("Title");
}
}
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
I think I understand what you want. Overall, I would recommend a slightly different approach. I would recommend, for one, that you not use a ComboBox to accomplish this - an ItemsControl will accomplish what you want with less work and overhead. Using a Popup like you are is great, but let me show you a slightly simplified way that (this is the best part) works the way you are asking in your question.
Here's your XAML:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.DataContext>
<local:ViewModel/>
</Grid.DataContext>
<StackPanel Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox Width="200" FontSize="24" Text="{Binding Header, Mode=TwoWay}"
IsReadOnly="True" TextWrapping="Wrap" MaxHeight="200" />
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="200" Width="200" Background="White">
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}"
FontSize="24"
Foreground="Black"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
IsThreeState="False" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</StackPanel>
</Grid>
Here's your code-behind:
public class Item : BindableBase
{
public string Text { get; set; }
bool _IsChecked = default(bool);
public bool IsChecked { get { return _IsChecked; } set { SetProperty(ref _IsChecked, value); } }
}
public class ViewModel : BindableBase
{
public ViewModel()
{
_Items = new ObservableCollection<Item>(Enumerable.Range(1, 10)
.Select(x => new Item()
{
Text = string.Format("Item {0}", x),
IsChecked = (x < 4) ? true : false,
}));
foreach (var item in this.Items)
item.PropertyChanged += (s, e) => base.RaisePropertyChanged("Header");
}
public string Header
{
get
{
var array = this.Items
.Where(x => x.IsChecked)
.Select(x => x.Text).ToArray();
if (!array.Any())
return "None";
return string.Join("; ", array);
}
}
ObservableCollection<Item> _Items;
public ObservableCollection<Item> Items { get { return _Items; } }
}
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void SetProperty<T>(ref T storage, T value,
[System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (!object.Equals(storage, value))
{
storage = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] String propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Best of luck!
Your all code is correct, except one thing, that's data binding of CheckBox in ComboBox's DataTemplate. You don't need to use ElementName=thisUC
Incorrect
<CheckBox Content="{Binding Title}" Foreground="Black"
IsChecked="{Binding ElementName=thisUC, Path=IsSelected, Mode=TwoWay}"
Click="CheckBox_Click" />
Correct
<CheckBox Content="{Binding Title}" Foreground="Black" Click="CheckBox_Click"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/>