Selected ListboxItem template using Template Selector in UWP/WinRT - xaml

I have a set of Listbox items that are used to display the different fingers of a palm. I am using TemplateSelector to display the templates, each template for a single finger.
Now my problem is, when the Listbox item is selected, a different colorful image needs to be displayed which would be different for each item, and othewise the image should be a gray one as set in the template.
The question is, how do I set a different selected image for each selected item in the listbox.
The Template Selector :-
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
DataTemplate dataTemplate = DefaultTemplate;
if (container is FrameworkElement && item is ILivescanFingerprintReviewItem)
{
var fingerPrintReviewItem = item as ILivescanFingerprintReviewItem;
// Right Rolled.
if (fingerPrintReviewItem.Header == "R. Thumb")
dataTemplate = RolledRightThumbTemplate;
else if (fingerPrintReviewItem.Header == "R. Index")
dataTemplate = RolledRightIndexTemplate;
else if (fingerPrintReviewItem.Header == "R. Middle")
dataTemplate = RolledRightMiddleTemplate;
else if (fingerPrintReviewItem.Header == "R. Little")
dataTemplate = RolledRightLittleTemplate;
else if (fingerPrintReviewItem.Header == "R. Ring")
dataTemplate = RolledRightRingTemplate;
// Left Rolled.
else if (fingerPrintReviewItem.Header == "L. Thumb")
dataTemplate = RolledLeftThumbTemplate;
else if (fingerPrintReviewItem.Header == "L. Index")
dataTemplate = RolledLeftIndexTemplate;
else if (fingerPrintReviewItem.Header == "L. Middle")
dataTemplate = RolledLeftMiddleTemplate;
else if (fingerPrintReviewItem.Header == "L. Ring")
dataTemplate = RolledLeftRingTemplate;
else if (fingerPrintReviewItem.Header == "L. Little")
dataTemplate = RolledLeftLittleTemplate;
// Slaps.
else if (fingerPrintReviewItem.Header == "Slap Thumbs")
dataTemplate = SlapThumbsTemplate;
else if (fingerPrintReviewItem.Header == "R. Slap")
dataTemplate = SlapRightTemplate;
else if (fingerPrintReviewItem.Header == "L. Slap")
dataTemplate = SlapLeftTemplate;
else dataTemplate = DefaultTemplate;
}
return dataTemplate;
}
The template selector in XAML :-
<controls:LivescanFingerprintIconTemplateSelector x:Key="LivescanFingerprintIconTemplateSelector"
RolledRightIndexTemplate="{StaticResource RolledRightIndexTemplate}"
RolledRightThumbTemplate="{StaticResource RolledRightThumbTemplate}"
RolledRightMiddleTemplate="{StaticResource RolledRightMiddleTemplate}"
RolledRightRingTemplate="{StaticResource RolledRightRingTemplate}"
RolledRightLittleTemplate="{StaticResource RolledRightLittleTemplate}"
RolledLeftIndexTemplate="{StaticResource RolledLeftIndexTemplate}"
RolledLeftMiddleTemplate="{StaticResource RolledLeftMiddleTemplate}"
RolledLeftThumbTemplate="{StaticResource RolledLeftThumbTemplate}"
RolledLeftRingTemplate="{StaticResource RolledLeftRingTemplate}"
RolledLeftLittleTemplate="{StaticResource RolledLeftLittleTemplate}"
SlapLeftTemplate="{StaticResource SlapLeftTemplate}"
SlapRightTemplate="{StaticResource SlapRightTemplate}"
SlapThumbsTemplate="{StaticResource SlapThumbsTemplate}"
DefaultTemplate="{StaticResource TenprintFingerItemTemplate}"/>
I tried to use Visual States in the ItemContainer Style but even there I am not able to set dynamic content for selected items in the listbox.
Any suggestions on how to achieve this?
THANKS IN ADVANCE.

Now my problem is, when the Listbox item is selected, a different colorful image needs to be displayed which would be different for each item, and othewise the image should be a gray one as set in the template.
From your code I think your ItemTemplateSelector is for showing images of different fingers, it is not related to the "selected" or "unselected" state of each items. And you have two kinds of images, the images of one kind are with colors, the other kind has the gray images. So you can use INotifyPropertyChanged to do this.
For example here:
<ListBox x:Name="listBox" ItemsSource="{x:Bind list}" SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding ImageAddress}" Width="150" Height="150" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
code behind:
private ObservableCollection<MyListBoxItem> list = new ObservableCollection<MyListBoxItem>();
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
list.Clear();
list.Add(new MyListBoxItem { ImageAddressUnselected = "Assets/2.jpeg", ImageAddressSelected = "Assets/1.jpeg" });
list.Add(new MyListBoxItem { ImageAddressUnselected = "Assets/2.jpeg", ImageAddressSelected = "Assets/1.jpeg" });
list.Add(new MyListBoxItem { ImageAddressUnselected = "Assets/2.jpeg", ImageAddressSelected = "Assets/1.jpeg" });
list.Add(new MyListBoxItem { ImageAddressUnselected = "Assets/2.jpeg", ImageAddressSelected = "Assets/1.jpeg" });
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var items in listBox.Items)
{
var eachitem = items as MyListBoxItem;
eachitem.IsSelected = false;
eachitem.ImageAddress = eachitem.ImageAddressUnselected;
}
MyListBoxItem selectedItem = listBox.SelectedItem as MyListBoxItem;
selectedItem.IsSelected = true;
selectedItem.ImageAddress = selectedItem.ImageAddressSelected;
}
And my MyListBoxItem is like this:
public class MyListBoxItem : INotifyPropertyChanged
{
private string _imageaddressunselected;
public string ImageAddressUnselected
{
get { return _imageaddressunselected; }
set { _imageaddressunselected = value; }
}
private string _imageaddressselected;
public string ImageAddressSelected
{
get { return _imageaddressselected; }
set { _imageaddressselected = value; }
}
private bool _isselected;
public bool IsSelected
{
get { return _isselected; }
set
{
_isselected = value;
OnPropertyChanged();
}
}
private string _imageAddress;
public string ImageAddress
{
get
{
if (_isselected == true)
{
_imageAddress = _imageaddressselected;
}
else
{
_imageAddress = _imageaddressunselected;
}
return _imageAddress;
}
set
{
if (value != _imageAddress)
{
_imageAddress = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
This sample changes the image source when the item is selected.

Related

How to focus on one Entry when Using TextChange for multiple entries

I have 2 entries. When I tap anything on entry 1 I would like to get "Yess" on entry 2 and when I type anything on entry 2 I would like to get "Noo"
The problem:
When I tap on entry 1, entry 2 change and get the value "Noo" but entry 1 change too and get the value "yess".
Question :
How can make entry 2 change when tapping on entry 1 without changing entry 1. And the same for entry 2
Here is Xaml code :
<Entry ClassId="1" x:Name="myWord1"TextChanged="OnEntryTextChange"/>
<Entry ClassId="2" x:Name="myWord2" TextChanged="OnEntryTextChange"/>
Code :
private async void OnEntryTextChange(object sender, TextChangedEventArgs e)
{
var EntryTapped = (Xamarin.Forms.Entry)sender;
Device.BeginInvokeOnMainThread(() => {
if (EntryTapped.ClassId == "1")
{
myWord2.Text="Noo";
}
else if (EntryTapped.ClassId == "2")
{
myWord1.Text="yess";
}
});
}
Thanks for your help
You could use the Focused event instead of TextChanged event.
<StackLayout>
<Entry ClassId="1" x:Name="myWord1" Focused="EntryFocused"/>
<Entry ClassId="2" x:Name="myWord2" Focused="EntryFocused"/>
</StackLayout>
private void EntryFocused(object sender, FocusEventArgs e)
{
var EntryTapped = (Xamarin.Forms.Entry)sender;
if (EntryTapped.ClassId == "1")
{
myWord2.Text = "Noo";
}
else if (EntryTapped.ClassId == "2")
{
myWord1.Text = "yess";
}
}
There are several ways of doing this:
Using bindings
In this case you would have 2 private variables and 2 public variables, and the entries binded to each one. Check this link how to implement INotifyPropertyChanged
private string entry1String;
private string entry2String;
public string Entry1String {
get => entry1String;
set
{
entry2String = "Noo";
entry1String = value;
OnPropertyChanged(Entry1String);
OnPropertyChanged(Entry2String);
}
}
public string Entry2String {
get => entry2String;
set
{
entry1String = "Yees";
entry2String = value;
OnPropertyChanged(Entry1String);
OnPropertyChanged(Entry2String);
}
}
Another way could be using a variable as a Semaphore. While the variable is True, the method cannot be fired at the same time by another.
private bool semaphoreFlag=false;
private async void OnEntryTextChange(object sender, TextChangedEventArgs e)
{
if(semaphoreFlag) return;
semaphoreFlag=true;
var EntryTapped = (Xamarin.Forms.Entry)sender;
Device.BeginInvokeOnMainThread(() => {
if (EntryTapped.ClassId == "1")
{
myWord2.Text="Noo";
}
else if (EntryTapped.ClassId == "2")
{
myWord1.Text="yess";
}
});
semaphoreFlag=false;
}

Adjust the text size in a ListView according to a parameter

My Xamarin.Forms app displays the name of multiple items in a Listview. The name of the article is displayed by a Binding to the name field in the table that contains these articles (Panier).
I would like the user to be able to change the text size of the article name (when the screen resolution is low, the name is truncated).
To do this, I have provided a Parameters table which contains the size of the text chosen by the user.
But how do you indicate this in the xaml code?
Here's some of the xaml code:
<Label Text="{Binding Name}"
Margin="10,-4,0,0" FontSize="Medium" TextColor="Black"
FontAttributes="None"
VerticalOptions="Start"
Grid.Column="0"/>
So I would like to replace
FontSize="Medium"
With an instruction that would look like this:
FontSize="{Binding ???}"
The binding would fetch the value from the Parameters table.
But to find the name, I have in the code behind the instruction
BindingContext = new Panier();
Panier() contains the Name field, but obviously does not contain the text size.
You might need to change the BindingContext to go to the Parameters table, but in XAML code, FontSize is in the same place as Text.
To sum up: the user should be able to adjust the size of the text of the name of the articles displayed in the Listview himself.
Edit for to all those who answered me :
Excuse me, I am not an experienced developer, and I did not understand what you are offering me;
I believe I will add a NameFontSize field in the Panier table. I can therefore in my xaml code have the following code:
FontSize="{Binding NameFontSize}";
The disadvantage of this solution is this additional field which means that each record will have a data concerning the size of the text, which will be the same for all the records of the table. It doesn't make much sense to repeat the same information for all records.
If I am wrong and the solution you are proposing makes more sense, please explain it to me in more detail.
Thank you very much.
You could add MyFontSize and MySizeName peoperty inside the ViewModel, then you can use MySizeName to set NamedSize.Value for MyFontSize. And you also can set doulbe value for MyFontSize directly.
The Xaml code :
<Label Text="Hello Label!" FontSize="{Binding MyFontSize}"/>
The ViewModel :
public class ContactViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private double myFontSize;
public double MyFontSize
{
set
{
if (myFontSize != value)
{
myFontSize = value;
OnPropertyChanged("MyFontSize");
}
}
get
{
return myFontSize;
}
}
private string mySizeName;
public string MySizeName
{
set
{
if (mySizeName != value)
{
mySizeName = value;
OnPropertyChanged("MySizeName");
ConvertNameToSize();
OnPropertyChanged("MyFontSize");
}
}
get
{
return mySizeName;
}
}
// convert SizeName to FontSize
private void ConvertNameToSize()
{
if (mySizeName == "Default")
{
myFontSize = Device.GetNamedSize(NamedSize.Header, typeof(Label));
}
else if (mySizeName == "Micro")
{
myFontSize = Device.GetNamedSize(NamedSize.Micro, typeof(Label));
}
else if (mySizeName == "Small")
{
myFontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label));
}
else if (mySizeName == "Medium")
{
myFontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label));
}
else if (mySizeName == "Large")
{
myFontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label));
}
else if (mySizeName == "Body")
{
myFontSize = Device.GetNamedSize(NamedSize.Body, typeof(Label));
}
else if (mySizeName == "Header")
{
myFontSize = Device.GetNamedSize(NamedSize.Header, typeof(Label));
}
else if (mySizeName == "Title")
{
myFontSize = Device.GetNamedSize(NamedSize.Title, typeof(Label));
}
else if (mySizeName == "Subtitle")
{
myFontSize = Device.GetNamedSize(NamedSize.Subtitle, typeof(Label));
}
else if (mySizeName == "Caption")
{
myFontSize = Device.GetNamedSize(NamedSize.Caption, typeof(Label));
}else
{
myFontSize = Device.GetNamedSize(NamedSize.Header, typeof(Label));
}
}
public ContactViewModel()
{
// set value for test
mySizeName = "Large";
ConvertNameToSize();
}
}
Here adding INotifyPropertyChanged for ViewModel, if the binded value be changed on runtime. The view will update automatically.
The effect:

Xamarin Forms Switch XAML

I'm new in Xamarin and i'm trying to create a simple page with some components.
One of these component is a Switch it works fine by itself but i would like to change the basic text "inactive/active" by "male/female"
I've seen that in Xaml for windows phone there is a ToggleSwitch Component with a On/OffContent property but i can't seems to find an equivalent in XAML for Xamarin Forms
any idea ?
Thank you!
The lack of built in switch options, or at least the lack of being able to rename the switch options, has been asked a few times.
You could go with custom renders, modify the text at the OS level or do like I chose to do, just build your own switch.
This switch is two buttons laid out horizontally with the text Yes and No. The selected button gets a red border, and the unselected a transparent border.
class CustomSwitch : Grid
{
public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;
private Button negative;
private Button positive;
public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create<CustomSwitch, Object>(t => t.SelectedItem, null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public CustomSwitch()
{
try
{
this.HorizontalOptions = LayoutOptions.Center;
this.VerticalOptions = LayoutOptions.Center;
negative = new Button();
negative.Text = "No";
negative.Style = <YourNameSpace>.AppStyling.Style_Button_Switch;
negative.Clicked += (o,s) => OnSelectedItemChanged(this, ItemSelected, (int)Classes.Collections.Enums.SelectionStatus.False);
positive = new Button();
positive.Text = "Yes";
positive.Style = <YourNameSpace>.AppStyling.Style_Button_Switch;
positive.Clicked += (o, s) => OnSelectedItemChanged(this, ItemSelected, (int)Classes.Collections.Enums.SelectionStatus.True);
this.Children.Add(negative, 0,0);
this.Children.Add(positive, 1,0);
}
catch(System.Exception ex)
{
<YourNameSpace>.Classes.Helpers.Helper_ErrorHandling.SendErrorToServer(ex, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name);
}
}
public Object SelectedItem
{
get
{
return base.GetValue(SelectedItemProperty);
}
set
{
if (SelectedItem != value)
{
base.SetValue(SelectedItemProperty, value);
InternalUpdateSelected();
}
}
}
private void InternalUpdateSelected()
{
if((int)SelectedItem == (int)Classes.Collections.Enums.SelectionStatus.False)
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_Selected;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
positive.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
}
else if ((int)SelectedItem == (int)Classes.Collections.Enums.SelectionStatus.True)
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
negative.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_Selected;
}
else
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
negative.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
positive.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
}
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
CustomSwitch boundSwitch = (CustomSwitch)bindable;
if((int)newValue != (int)Classes.Collections.Enums.SelectionStatus.Unselected)
{
boundSwitch.SelectedItem = (int)newValue == (int)Classes.Collections.Enums.SelectionStatus.False ? (int)Classes.Collections.Enums.SelectionStatus.False : (int)Classes.Collections.Enums.SelectionStatus.True;
}
if (boundSwitch.ItemSelected != null)
{
boundSwitch.ItemSelected(boundSwitch, new SelectedItemChangedEventArgs(newValue));
}
boundSwitch.InternalUpdateSelected();
}
}

What is the correct property name to notify when binding to an element in an Observable collection directly?

I have a binding of the following form in XAML,
Title="{Binding SelectedNewsItems[0].Title}"
Note that it refers to a particular element in the SelectedNewsItems which is an ObservableCollection. (I have a collection of nine buttons of various sizes, each styled, and sized differently and so a more standard ListView is not appropriate.)
When I reassign SelectedNewsItems I raise a PropertyChanged event for SelectedNewsItems, however, this does not appear to cause the bindings to update for the individual bound elements and their properties. I have tried the following,
public ObservableCollection<NewsItem> _selectedNewsItems;
public ObservableCollection<NewsItem> SelectedNewsItems
{
get
{
return this._selectedNewsItems;
}
set
{
if (this._selectedNewsItems != value)
{
this._selectedNewsItems = value;
this.NotifyPropertyChanged();
for (int i = 0; i < this._selectedNewsItems.Count; i++)
{
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Content", i));
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Title", i));
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Id", i));
this.NotifyPropertyChanged(String.Format("SelectedNewsItems[{0}].Image", i));
}
}
}
}
Hmm, I cannot exacly say where your code is wrong (as I see only part of it), but maybe you haven't set your DataContex or something else. For the purpose of research I've made simple example, which works quite fine. Take a look at it and maybe it will help you:
In Xaml:
<Button x:Name="first" VerticalAlignment="Top" Content="{Binding SelectedNewsItems[0].Name}" Grid.Row="0"/>
<Button x:Name="second" VerticalAlignment="Center" Content="{Binding SelectedNewsItems[1].Name}" Grid.Row="1"/>
In code behind (I put all the code - yeah quite a lot of, but I cannot guess what is wrong with your code):
public class NewsItem
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseProperty(string property = null)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(property));
}
private ObservableCollection<NewsItem> _selectedNewsItems = new ObservableCollection<NewsItem>();
public ObservableCollection<NewsItem> SelectedNewsItems
{
get
{
return this._selectedNewsItems;
}
set
{
if (this._selectedNewsItems != value)
{
this._selectedNewsItems = value;
this.RaiseProperty();
for (int i = 0; i < this._selectedNewsItems.Count; i++)
{
this.RaiseProperty(String.Format("SelectedNewsItems[{0}].Name", i));
}
}
}
}
public MainPage()
{
NewsItem firstT = new NewsItem() { Name = "First" };
NewsItem secondT = new NewsItem() { Name = "Second" };
SelectedNewsItems.Add(firstT);
SelectedNewsItems.Add(secondT);
InitializeComponent();
this.DataContext = this;
first.Click += first_Click;
second.Click += second_Click;
}
private void first_Click(object sender, RoutedEventArgs e)
{
NewsItem change = new NewsItem() { Name = "Changed by First" };
SelectedNewsItems[1] = change;
}
private void second_Click(object sender, RoutedEventArgs e)
{
NewsItem change = new NewsItem() { Name = "Changed by Second" };
SelectedNewsItems[0] = change;
}
}
As I click on buttons the bindigs work, so maybe it will help you.

Unable to use Autocompletebox in windows 8

I installed nudget autocomplete toolkit but unfortunately I found it wierd that this control doesn't have enough property to serve as autocomplete. It has ItemsSource but it doesn't show the list of items filtered when you type something. I am also looking for something like textChanged so that I can invoke my service and get the result again and bind the itemsource.
Here's my implementation used in Group Contacts:
XAML:
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:behaviors="using:MyNamespace.Behaviors"
.
.
<TextBox x:Name="Searchbox" PlaceholderText="contact's name" Width="250"
IsTextPredictionEnabled="False"
IsSpellCheckEnabled="False"
VerticalAlignment="Center">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="KeyUp">
<behaviors:FilterContactAction />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBox>
Code:
public class FilterContactAction : DependencyObject, IAction
{
string _previousResult = null;
public object Execute(object sender, object parameter)
{
var textbox = sender as TextBox;
var keyEventArgs = parameter as KeyRoutedEventArgs;
var noChanges = textbox.Text == _previousResult;
var deletionOccurred = keyEventArgs.Key == VirtualKey.Back ||
keyEventArgs.Key == VirtualKey.Delete;
if (noChanges || deletionOccurred)
{
return null;
}
var viewModel = ResourceLocator.Instance[typeof(HomeViewModel)] as HomeViewModel;
viewModel.CanSearch = FindMatch(textbox, viewModel.Contacts);
return null;
}
private bool FindMatch(TextBox textbox, ObservableCollection<Contact> contacts)
{
foreach (var contact in contacts)
{
var suggestionDisplayed = DisplaySuggestion(textbox, contact);
if (suggestionDisplayed)
{
return true;
}
}
return false;
}
private bool DisplaySuggestion(TextBox textbox, Windows.ApplicationModel.Contacts.Contact contact)
{
var characterCount = textbox.Text.Count();
var suggestionDisplayed = false;
var isMatch = contact.DisplayName.ToUpper().StartsWith(textbox.Text.ToUpper());
if (isMatch)
{
textbox.Text = contact.DisplayName;
textbox.SelectionStart = characterCount;
textbox.SelectionLength = textbox.Text.Length - textbox.SelectionStart;
_previousResult = textbox.Text;
suggestionDisplayed = true;
}
return suggestionDisplayed;
}
}
TextBoxExt control from Syncfusion WinRT Studio has enough features to work as an AutoComplete. It has more than 15 suggestion modes including custom filter option. Hope this helps.
http://www.syncfusion.com/products/winrt/controls
Not sure what you used. Can't tell you why it doesn't work either. however last year I wanted AutoCompleteTextBox and ended up writing it myself.
you can find it here.
https://github.com/hermitdave/HermitDaveWinRTControls