Windows Phone 8.1 LongListSelector with Images - windows-phone-7

I have a long list selector in my application. The list should display an icon and a caption below it. It appears as a grid as seen in the image below
The icon should be downloaded from the server and displayed, the icon is downloaded from the server as an byte array which can be used to generate the Bitmap. How do i bind the Bitmap to the Image in my LongListSelectors template. My data template is as below.
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid Margin="5,5,5,5" Background="{StaticResource PhoneAccentBrush}">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Image Height="70" Width="70" Margin="10,0,0,0" Source="/Assets/Images/appimg.png">
</Image>
</Grid>
<StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Center">
<TextBlock Margin="5,5,5,5" TextTrimming="WordEllipsis" TextWrapping="NoWrap" Text="{Binding appTitle}"></TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
Currently in the template the icon path is hardcoded. Please provide some input on how to bind the bitmap to the image.

Use a Conveter
Assuming the assembly name of the phone project is: PhoneApp1
Create a converter with the following code:
using System;
namespace PhoneApp1.Converters
{
using System.Globalization;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;
public class ByteToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var data = value as byte[];
if (data != null)
{
using(var stream = new MemoryStream(data))
{
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
return bitmapImage;
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
use the following namespace declaration in your xaml:
xmlns:converters="clr-namespace:PhoneApp1.Converters"
XAML:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Resources>
<converters:ByteToImageConverter x:Key="ByteToImageConverter" />
</Grid.Resources>
<phone:LongListSelector x:Name="lstTiles">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid Margin="5,5,5,5" Background="{StaticResource PhoneAccentBrush}">
<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
<Image Height="70" Width="70" Margin="10,0,0,0" Source="{Binding Image, Converter={StaticResource ByteToImageConverter}}">
</Image>
</Grid>
<StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Center">
<TextBlock Margin="5,5,5,5" TextTrimming="WordEllipsis" TextWrapping="NoWrap" Text="{Binding Title}"></TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
Code Behind and Model
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
this.BindTiles();
}
private void BindTiles()
{
var sampleRandomImageBytes = Convert.FromBase64String(#"iVBORw0KGgoAAAANSUhEUgAAAGgAAABbCAYAAACf8sCiAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADeSURBVHhe7dExAQAwDMCgmVj9O21tcORAAe/PbFwF4QrCFYQrCFcQriBcQbiCcAXhCsIVhCsIVxCuIFxBuIJwBeEKwhWEKwhXEK4gXEG4gnAF4QrCFYQrCFcQriBcQbiCcAXhCsIVhCsIVxCuIFxBuIJwBeEKwhWEKwhXEK4gXEG4gnAF4QrCFYQrCFcQriBcQbiCcAXhCsIVhCsIVxCuIFxBuIJwBeEKwhWEKwhXEK4gXEG4gnAF4QrCFYQrCFcQriBcQbiCcAXhCsIVhCsIVxCuIFxBuIJwBeEKos0e0/44s5MWYKUAAAAASUVORK5CYII=");
var data = new[]
{
new AppTitle { Title = "Tile 1", Image = sampleRandomImageBytes }, new AppTitle { Title = "Tile 2", Image = sampleRandomImageBytes },
new AppTitle { Title = "Tile 3", Image = sampleRandomImageBytes }, new AppTitle { Title = "Tile 4", Image = sampleRandomImageBytes }
};
lstTiles.ItemsSource = data;
}
}
public class AppTitle
{
public string Title { get; set; }
public byte[] Image { get; set; }
}

Related

Color converter binding not being called

I have a label with black text color inside a frame with white background color, the thing is, I want to assign the background color and text color from the viewmodel, I have created the converter, and did the bindings, but for some reason it isn't working
this is my view code:
?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ComanderoMovil.Views.PlatillosView"
xmlns:ios="clr -namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.UseSafeArea="true"
xmlns:behaviorsPack="clr- namespace:Xamarin.Forms.BehaviorsPack;assembly=Xamarin.Forms.Behaviors Pack"
xmlns:converterPack="clr-namespace:ComanderoMovil.Converters">
<ContentPage.Resources>
<ResourceDictionary>
<converterPack:ColorConverter x:Key="ColorConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<SearchBar> </SearchBar>
<CollectionView ItemsSource="{Binding Grupos}"
HeightRequest="50"
ItemsLayout="HorizontalList"
SelectionMode="Single"
SelectionChangedCommand="{Binding
SelectedGrupoCommand, Mode=TwoWay}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView Padding="2">
<Frame BorderColor="Black"
HasShadow="False"
Padding="2"
BackgroundColor="{Binding
ButtonBackColor, Converter={StaticResource ColorConverter}}">
<StackLayout>
<Label Margin="10"
Text="{Binding nombre}"
TextColor="{Binding
TextColor, Converter = {StaticResource ColorConverter}}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="Small"
VerticalOptions="CenterAndExpand"></Label>
</StackLayout>
</Frame>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage.Content>
</ContentPage>
Here is my ViewModel:
public class PlatillosViewModel : INotifyPropertyChanged
{
private INavigation Navigation;
private ObservableCollection<PlatilloModel> _platillos;
private string _textColor;
private string _backColor;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<GrupoModel> Grupos { get; set; }
public ObservableCollection<PlatilloModel> Platillos
{
get => _platillos;
set
{
_platillos = value;
OnPropertyChanged();
}
}
public string TextColor
{
get => _textColor;
set
{
_textColor = value;
OnPropertyChanged();
}
}
public string ButtonBackColor
{
get => _backColor;
set
{
_backColor = value;
OnPropertyChanged();
}
}
public PlatillosViewModel(INavigation navigation)
{
Navigation = navigation;
TextColor = "Black";
ButtonBackColor = "White";
PlatillosRepository repository = new PlatillosRepository();
Platillos = repository.GetAll();
GrupoRepository grupoRepository = new GrupoRepository();
Grupos = grupoRepository.GetAll();
}
public ICommand SelectedPlatilloCommand => new Command<PlatilloModel>(async platillo =>
{
await Navigation.PushAsync(new PlatilloView());
});
public ICommand SelectedGrupoCommand => new Command<GrupoModel>(async grupo =>
{
ButtonBackColor = "Black";
TextColor = "White";
PlatillosRepository platillosRepository = new PlatillosRepository();
Platillos = platillosRepository.GetFilteredByGroup(grupo);
});
protected virtual void OnPropertyChanged([CallerMemberName] string property = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
and Here is my converter:
public class ColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var valor = value.ToString();
switch(valor)
{
case "White":
return Color.White;
case "Black":
return Color.Black;
default:
return Color.Red;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Your issue is not with the ValueConverter but with your Bindings.
<CollectionView ItemsSource="{Binding Grupos}"
HeightRequest="50"
ItemsLayout="HorizontalList"
SelectionMode="Single"
SelectionChangedCommand="{Binding SelectedGrupoCommand, Mode=TwoWay}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView Padding="2">
<Frame BorderColor="Black"
HasShadow="False"
Padding="2"
BackgroundColor="{Binding ButtonBackColor, Converter={StaticResource ColorConverter}}">
<StackLayout>
<Label Margin="10"
Text="{Binding nombre}"
TextColor="{Binding TextColor, Converter = {StaticResource ColorConverter}}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="Small"
VerticalOptions="CenterAndExpand">
</Label>
</StackLayout>
</Frame>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
You are using a CollectionView and when you set the ItemSource
<CollectionView ItemsSource="{Binding Grupos}"
All the bindings you do inside will assume this as the BindingContext.
<Label Margin="10"
Text="{Binding nombre}"
TextColor="{Binding TextColor, Converter = {StaticResource ColorConverter}}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="Small"
VerticalOptions="CenterAndExpand" />
The same way the nombre property you are binding to the Label Text Property, is part of the GroupModel class, that way the TextColor and ButtonBackColor properties are expected to be part of the same class you did bind as the ItemSource.
If you want to make it work: either add these two properties (TextColor and ButtonBackColor) to the GroupModel class or change the binding so that these two properties are accessed from the parent Binding.
The first one will give you more flexibility but at the same time might add repeated code (if all the items will share the same color for example).
The second option can be accomplished this way:
Add a name to the CollectionView
<CollectionView ItemsSource="{Binding Grupos}"
HeightRequest="50"
x:Name="GruposList"
....
Then we are gonna change a bit the binding of those items that are not part of your GrupoModel but are part of the ViewModel
<DataTemplate>
<ContentView Padding="2">
<Frame BorderColor="Black"
HasShadow="False"
Padding="2"
BackgroundColor="{Binding BindingContext.ButtonBackColor,
Source={x:Reference GruposList},
Converter={StaticResource ColorConverter}}">
<StackLayout>
<Label Margin="10"
Text="{Binding nombre}"
TextColor="{Binding BindingContext.TextColor,
Source={x:Reference GruposList},
Converter={StaticResource ColorConverter}}"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
FontSize="Small"
VerticalOptions="CenterAndExpand">
</Label>
</StackLayout>
</Frame>
</ContentView>
</DataTemplate>
As you can see we are now accessing them through the CollectionView Binding, we do this when we specify the Source and use a Reference. More about bindings here
Hope this helps.-
Side Note:
In your converter watch for nulls.
var valor = value.ToString();
The above can make your application crash if value is null.
Use this instead:
var valor = value?.ToString();

Windows 10 Mobile AppBar Button - Badge count

is there any chance to put badge count to the AppBarButton control on Windows 10, as you can do it on Android - e.g. How to display count of notifications in app launcher icon
If not, any idea what is a good practice to inform user about some new information (like new message)?
thanks!
http://i.stack.imgur.com/WjHNt.png
If you just want to create a control in an UWP app like your second picture, you can do it like below:
<Button Background="Transparent" Click="OnClick" HorizontalAlignment="Center">
<RelativePanel>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="30" Text=""/>
<Border Background="Red" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignRightWithPanel="True">
<TextBlock x:Name="count" Foreground="White" Text="{x:Bind tb.Text,Mode=OneWay}" FontSize="12" />
</Border>
</RelativePanel>
</Button>
<TextBox VerticalAlignment="Bottom" x:Name="tb" />
In this sample, I bind the Text of the TextBlock named "count" to a TextBox, so we can change this value.
But we can create it as an UserControl, so that we can use it repeatable. And we can use a DependencyProperty to expose the property we want to use. For example here:
<UserControl
x:Class="BadgeCountApp.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BadgeCountApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Button Background="Transparent" HorizontalAlignment="Center">
<RelativePanel>
<TextBlock FontFamily="Segoe MDL2 Assets" FontSize="30" x:Name="text" Text="{x:Bind SymbText,Mode=OneWay}"/>
<Border Background="Red" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignRightWithPanel="True">
<TextBlock x:Name="count" Foreground="White" FontSize="12" Text="{x:Bind SymbCount,Mode=OneWay}" Visibility="Collapsed"/>
</Border>
</RelativePanel>
</Button>
</UserControl>
code behind:
public sealed partial class MyUserControl : UserControl
{
public MyUserControl()
{
this.InitializeComponent();
}
public static readonly DependencyProperty SymbTextProperty = DependencyProperty.Register("SymbText", typeof(string), typeof(MyUserControl), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty SymbCountProperty = DependencyProperty.Register("SymbCount", typeof(int), typeof(MyUserControl), new PropertyMetadata(0, new PropertyChangedCallback(ChangedCallback)));
private static void ChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyUserControl muc = (MyUserControl)d;
int value = (int)e.NewValue;
if (value == 0)
{
muc.count.Visibility = Visibility.Collapsed;
}
else
{
muc.count.Visibility = Visibility.Visible;
}
}
public string SymbText
{
get { return (string)GetValue(SymbTextProperty); }
set { SetValue(SymbTextProperty, value); }
}
public int SymbCount
{
get{ return (int)GetValue(SymbCountProperty);}
set{ SetValue(SymbCountProperty, value);}
}
}
Now you can use this control directly in other place like this:
<local:MyUserControl x:Name="user" SymbText="" Tapped="OnTapped"/>
code behind:
private void OnTapped(object sender, TappedRoutedEventArgs e)
{
if (user.SymbCount == 0)
user.SymbCount = 3;
else
user.SymbCount = 0;
}
The following is a screenshot of this UserControl:

this.DataContext is NULL? Use to be filled - Switched to Autofac

I am using MVVM Light, Autofac for windows phone 7 and Autofac locator.
With autofac
http://www.nuget.org/packages/Autofac.Wp7
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using MvvmLight1.Model;
using Autofac;
namespace MvvmLight1.ViewModel
{
public class ViewModelLocator
{
static ViewModelLocator()
{
var builder = new ContainerBuilder();
builder.RegisterType<MainViewModel>();
var container = builder.Build();
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}
}
using Microsoft.Phone.Controls;
namespace MvvmLight1
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
var main = this.DataContext as MainPage; // will be null
}
}
}
<phone:PhoneApplicationPage x:Class="MvvmLight1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait"
Orientation="Portrait"
d:DesignWidth="480"
d:DesignHeight="768"
shell:SystemTray.IsVisible="True"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<!--LayoutRoot contains the root grid where all other page content is placed-->
<Grid x:Name="LayoutRoot"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel"
Grid.Row="0"
Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"
Text="{Binding ApplicationTitle}"
Style="{StaticResource PhoneTextNormalStyle}" />
<TextBlock x:Name="PageTitle"
Text="{Binding PageName}"
Margin="-3,-8,0,0"
Style="{StaticResource PhoneTextTitle1Style}" />
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentGrid"
Grid.Row="1">
<TextBlock Text="{Binding WelcomeTitle}"
Style="{StaticResource PhoneTextNormalStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="40"
TextWrapping="Wrap"
TextAlignment="Center" />
</Grid>
</Grid>
</phone:PhoneApplicationPage>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Microsoft.Practices.ServiceLocation;
namespace MvvmLight1
{
public sealed class AutofacServiceLocator : ServiceLocatorImplBase
{
readonly IComponentContext _container;
public AutofacServiceLocator(IComponentContext container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
protected override object DoGetInstance(Type serviceType, string key)
{
return key != null ? _container.ResolveNamed(key, serviceType) : _container.Resolve(serviceType);
}
protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
{
var enumerableType = typeof(IEnumerable<>).MakeGenericType(serviceType);
object instance = _container.Resolve(enumerableType);
return ((IEnumerable)instance).Cast<object>();
}
}
}
using GalaSoft.MvvmLight;
using MvvmLight1.Model;
namespace MvvmLight1.ViewModel
{
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
}
}
}
now the viewModel in my constructor of MainPage.cs will always be null.
When I just used SimpleIoc it was filled with the Main Object.

Build an UI like option menu

I think the question says it all: I want to build an Windows 8 Store app but how can I build an UI like this:
I think left is a normal ListView. The important thing is that I want an own AppBar for each ListViewEntry. And how can I load different pages (with different AppBars) in the right content area?
You can put a ContentControl in the main panel and another one in the AppBar, then bind their Content properties to the SelectedItem property of the ListBox on the left and use ContentTemplateSelector to display the right UI for the selected page.
*EDIT - Sample
XAML
<Page
x:Class="App17.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App17"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<local:PropertyPageTemplateSelector
x:Key="PropertyPageTemplateSelector"/>
</Page.Resources>
<Grid
Background="LemonChiffon">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition
Width="2*" />
</Grid.ColumnDefinitions>
<ListBox
x:Name="listBox"
DisplayMemberPath="Label"/>
<ContentControl
Grid.Column="1"
Content="{Binding SelectedItem, ElementName=listBox}"
ContentTemplateSelector="{StaticResource PropertyPageTemplateSelector}">
<ContentControl.Resources>
<DataTemplate
x:Key="Options">
<StackPanel>
<TextBlock
Text="{Binding Label}"
FontSize="32"
Foreground="SlateGray" />
<Rectangle
Width="400"
Height="400"
Fill="Aquamarine" />
</StackPanel>
</DataTemplate>
<DataTemplate
x:Key="Preferences">
<StackPanel>
<TextBlock
Text="{Binding Label}"
FontSize="32"
Foreground="SlateGray" />
<Rectangle
Width="400"
Height="400"
Fill="Khaki" />
</StackPanel>
</DataTemplate>
<DataTemplate
x:Key="Properties">
<StackPanel>
<TextBlock
Text="{Binding Label}"
FontSize="32"
Foreground="SlateGray" />
<Rectangle
Width="400"
Height="400"
Fill="LawnGreen" />
</StackPanel>
</DataTemplate>
<DataTemplate
x:Key="Settings">
<StackPanel>
<TextBlock
Text="{Binding Label}"
FontSize="32"
Foreground="SlateGray" />
<Rectangle
Width="400"
Height="400"
Fill="Violet" />
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Grid>
</Page>
C#
using System.Collections.Generic;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace App17
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
listBox.ItemsSource =
new List<PropertyPageViewModel>(
new PropertyPageViewModel[]
{
new OptionsPropertyPageViewModel(),
new PreferencesPropertyPageViewModel(),
new PropertiesPropertyPageViewModel(),
new SettingsPropertyPageViewModel(),
});
}
}
public abstract class PropertyPageViewModel
{
public abstract string Label { get; }
}
public class OptionsPropertyPageViewModel : PropertyPageViewModel
{
public override string Label { get { return "Options"; } }
}
public class PreferencesPropertyPageViewModel : PropertyPageViewModel
{
public override string Label { get { return "Preferences"; } }
}
public class PropertiesPropertyPageViewModel : PropertyPageViewModel
{
public override string Label { get { return "Properties"; } }
}
public class SettingsPropertyPageViewModel : PropertyPageViewModel
{
public override string Label { get { return "Settings"; } }
}
public class PropertyPageTemplateSelector : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
if (item == null) return base.SelectTemplateCore(item, container);
var contentControl = (ContentControl)container;
var viewModel = (PropertyPageViewModel)item;
var templateKey = viewModel.Label;
return (DataTemplate)contentControl.Resources[templateKey];
}
}
}

How can I get control in DataTemplate?

So, I have a code:
<tool:LongListSelector x:Name="citiesListGropus" Background="Transparent"
ItemTemplate="{StaticResource citiesItemTemplate}"
GroupHeaderTemplate="{StaticResource groupHeaderTemplate}"
GroupItemTemplate="{StaticResource groupItemTemplate}" Height="468" Margin="0,68,0,0">
<tool:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<tool:WrapPanel/>
</ItemsPanelTemplate>
</tool:LongListSelector.GroupItemsPanel>
</tool:LongListSelector>
And have a DataTemplate:
<DataTemplate x:Key="groupHeaderTemplate" x:Name="groupHeaderTemplateName">
<Border Background="{StaticResource PhoneAccentBrush}" Width="75" Height="75" Margin="-333, 15, 0, 15" x:Name="groupHeaderName">
<TextBlock Text="{Binding Title}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
How can I change a property Visibility of Border in DataTemplate ? I want to hide DataTemplate. But I can't bind my data to a property such as TextBlock Text="{Binding Title}", because I make binding data once, then I need to change some properties after data binding.
Any Ideas?
UPDATE 1
So, my main goal is filter the list of cities. I want to filter them by name.
My algorithm:
1) I get data from WebService.
2) Load my ViewModel
if (!App.CitiesViewModel.IsDataLoaded)
{
App.CitiesViewModel.LoadData(serviceResponse.Result);
}
3) Group the cities by name. My code like this code.
This is important, especially for LongListSeletstor I have to use templates.
Ok, my data ready. Now I do not need a web service.
<!-- The template for city items -->
<DataTemplate x:Key="citiesItemTemplate">
<StackPanel Name="PlacePanel"
Orientation="Horizontal" Margin="0,0,0,17"
Tag="{Binding Id}" Visibility="{Binding IsVisibility}">
<Image Height="75" Width="75" HorizontalAlignment="Left" Margin="12,0,9,0" Name="Image" Stretch="Fill" VerticalAlignment="Top" Source="{Binding Image}"/>
<StackPanel Width="311">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
I have TextBox, when I type name of a city - unnecessary cities hide. I can use data binding and INotifyPropertyChanged, so I can hide cities.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox name = (TextBox)sender;
foreach(var place in App.CitiesViewModel.Items
.Where(city => (city.Name.Contains(name.Text)) && (city.IsShow == true)))
{
city.IsVisibility = Visibility.Visible;
}
foreach (var city in App.CitiesViewModel.Items
.Where(city => !city.Name.Contains(name.Text)))
{
city.IsVisibility = Visibility.Collapsed;
}
}
But I have some problems, I can't hide this DataTemplate when I search cities:
<DataTemplate x:Key="groupHeaderTemplate" x:Name="groupHeaderTemplateName">
<Border Background="{StaticResource PhoneAccentBrush}" Width="75" Height="75" Margin="-333, 15, 0, 15" x:Name="groupHeaderName">
<TextBlock Text="{Binding Title}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
When I type name of a cities I want hide GroupHeaderTemplate. When TextBox lost focus show GroupHeaderTemplate.
I borrowed this picture here.
Update 2
My mistake was that I did not use PropertyChangedEventHandler. After adding this to GroupCity property and implementing an interface INotifyPropertyChanged I can change property Data Template after data binding.
private IList<Group<City>> citiesCollectionGroup;
var cityByName = from city in App.ViewModel.Items
group city by Convert.ToString(City.Name[0]).ToLower()
into c orderby c.Key select new
GroupCity<CitiesViewModel>(Convert.ToString(c.Key[0]).ToLower(), c);
citiesCollectionGroup = cityByName.ToList();
this.citiesListGropus.ItemsSource = citiesCollectionGroup;
public class GroupCity<T> : IEnumerable<T>, INotifyPropertyChanged
{
public GroupCity(string name, IEnumerable<T> items)
{
this.Title = name;
this.IsVisibility = Visibility.Visible;
this.Items = new List<T>(items);
}
public override bool Equals(object obj)
{
GroupCity<T> that = obj as GroupCity<T>;
return (that != null) && (this.Title.Equals(that.Title));
}
public string Title
{
get;
set;
}
private Visibility _isVisibility;
public Visibility IsVisibility
{
get
{
return _isVisibility;
}
set
{
_isVisibility = value;
NotifyPropertyChanged("IsVisibility");
}
}
public IList<T> Items
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return this.Items.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.Items.GetEnumerator();
}
#endregion
}
Xaml code:
<DataTemplate x:Key="groupHeaderTemplate" x:Name="groupHeaderTemplateName">
<Border Background="{StaticResource PhoneAccentBrush}" Width="75" Height="75" Margin="-333, 15, 0, 15" x:Name="groupHeaderName" Visibility="{Binding IsVisibility}">
<TextBlock Text="{Binding Title}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
Now we can change Visibility groupHeaderTemplate.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
foreach (GroupCity<CitiesViewModel> city in citiesCollectionGroup)
{
city.IsVisibility = Visibility.Collapsed;
}
//
}
private void SearchText_LostFocus(object sender, RoutedEventArgs e)
{
foreach (GroupCity<CitiesViewModel> city in citiesCollectionGroup)
{
city.IsVisibility = Visibility.Visible;
}
//
}
You can write your own simple DataTemplateSelector to do this. Check this out for more information.
With "How can I change a property Visibility of Border in DataTemplate ? I want to hide DataTemplate. " I understand that you want to change the visibility of an item based on a property, see example below.
(If the code below isn't quite the solution you are looking for please provide some more information about what you are trying to achieve. Re-reading your question and the comments I got on this example I doubt this is what you want to do, but I don't want to guess so I'm simply answering my interpretation of your question).
With bindings you can:
Bind the visibility property directly to a a property of type Visibility (example with listbox and Person1)
Bind the Visibility property to a boolean property, and use a converter to convert that to the Visibility type (listbox2 and Person2 + BoolToVis class).
There are more ways, but this are the two most simple to implement in my opinion.¨
result of code below:
View:
<phone:PhoneApplicationPage
x:Class="VisibilityWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
xmlns:VisibilityWP="clr-namespace:VisibilityWP"
shell:SystemTray.IsVisible="True">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.Resources>
<VisibilityWP:BoolToVis x:Key="BooleanToVisibilityConverter" />
</Grid.Resources>
<StackPanel>
<ListBox x:Name="listBox" Height="300">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="200" Visibility="{Binding Visibility}" Background="Blue">
<TextBlock Text="{Binding Name}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="listBox2" Height="300">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="200" Visibility="{Binding ShowBorder, Converter={StaticResource BooleanToVisibilityConverter}}" Background="Red">
<TextBlock Text="{Binding Name}" FontSize="40" Foreground="White" Margin="15, 15, 0, 0"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Grid>
Code behind:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
namespace VisibilityWP
{
public partial class MainPage
{
public MainPage()
{
InitializeComponent();
DataContext = this;
listBox.ItemsSource = new List<Person1>
{
new Person1 {Name = "Iris", Visibility = Visibility.Visible},
new Person1 {Name = "Somebody", Visibility = Visibility.Collapsed},
new Person1 {Name = "Peter", Visibility = Visibility.Visible},
};
listBox2.ItemsSource = new List<Person2>
{
new Person2 {Name = "Iris", ShowBorder = true},
new Person2 {Name = "Mia", ShowBorder = true},
new Person2 {Name = "Somebody", ShowBorder = false}
};
}
}
public class Person1
{
public string Name { get; set; }
public Visibility Visibility { get; set; }
}
public class Person2
{
public string Name { get; set; }
public bool ShowBorder { get; set; }
}
public sealed class BoolToVis : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value is Visibility && (Visibility)value == Visibility.Visible;
}
}
}

Resources