Refresh UI after new Language Xamarin - user-interface

Re-evaluate all values in xaml page calculated by a markup-extension
I try to implement this solution, but I Have a ObservableCollection which contains Title to binding in my listview in my MasterDetails page and it doesn't work. I have really no idea how implement this, but for only one label I did it successful. If someone can help me. Thanks
My list of items :
public ObservableCollection<MainMenuViewItem> MenuItems {
get {
return new ObservableCollection<MainMenuViewItem>(new[]
{
new MainMenuViewItem { Id = 0, Title = Translator.TranslatorInstance["lblHome"], TargetType=typeof(HybridWebView),ViewModelType=HybridViewTypeEnum.Home },
new MainMenuViewItem { Id = 1, Title = Translator.TranslatorInstance["lblListOfDeliverySlip"], TargetType=typeof(HybridWebView),ViewModelType=HybridViewTypeEnum.ListDeliverySlip },
new MainMenuViewItem { Id = 2, Title = Translator.TranslatorInstance["lblSettings"], TargetType=typeof(ParametersView)}
});
}
}
My view
<ListView Grid.Row="1" x:Name="MenuListPage" SeparatorVisibility="None"
HasUnevenRows="true" ItemsSource="{Binding MenuItems}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,10" HorizontalOptions="FillAndExpand">
<Label VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center"
Text="{Binding Title, StringFormat='{0}',Source={x:Static translate:Translator.TranslatorInstance}}"
FontSize="24"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The translationExtension class
/// <summary>
/// Current culture info
/// </summary>
public static CultureInfo CultureInfoApp { get; private set; }
// Path of folder where is store each file language + Name of file without .en ( language code )
private const string ResourceId = "Landauer.Mobile.Ressources.Language.LanguageRessource";
// Instanciation differed of Ressourcemanager
public static readonly Lazy<ResourceManager> RessourceManagerLanguage = new Lazy<ResourceManager>(() => new ResourceManager(ResourceId, IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly));
/// <summary>
/// Match to the name of the label into .resx file
/// </summary>
public string Text { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="text"></param>
public TranslateExtension()
{
if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
{
// Get dependency in each specific platform
CultureInfoApp = DependencyService.Get<ILanguage>().GetCurrentCultureInfo();
}
//Text = text;
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return ProvideValue(serviceProvider);
}
public BindingBase ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Mode = BindingMode.OneWay,
Path = $"[{Text}]",
Source = Translator.TranslatorInstance,
};
return binding;
}
And finally my translator class:
public static Translator TranslatorInstance => _uniqueInstance;
/// <summary>
/// When TranslateExtension you create new Binding(), call this "Callback"
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public string this[string text]
{
get
{
return TranslateExtension.RessourceManagerLanguage.Value.GetString(text, TranslateExtension.CultureInfoApp);
}
}
/// <summary>
/// Implementation of notifications
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// At each time you set language use this method to refresh UI
/// </summary>
public void Invalidate()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}

You need to set the culture of the resource when you change the language.
Your language instance class should also invoke the property change handler when you set the culture.
so create a method in the instance class like below and call when you change the language settings..
public void SetCultureInfo(CultureInfo cultureInfo)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}
At the time of language change, the code should be like below
var ci = CultureInfo.CreateSpecificCulture("ar");
NativeLangUtil.SetLocale(ci); // updating Native
Resx.Lang.Strings.Culture = ci; //For .net Resources to work
Application.Current.Properties["Lang"] = ci.TwoLetterISOLanguageName;//
LangResourceLoader.Instance.SetCultureInfo(ci); //for our use
You can find the sample implementation here

Related

Xamarin Forms: Add Clear Entry

Can you point me into the right direction: How can I achieve in Xamarin.Forms a clear entry button with behavior.
The behavior would be: When tapping to clear icon the entry's content on the android and iOS side the content will be deleted.
By default the entry control does't have this.
The result would be:
After some research I managed to do this with effects.
The downsize is that you must do it on the Android project and on iOS project separately.
Like Jason suggested it can be done with custom renderers too. But still you must implement it on each Android/iOS project.
On the android project side you can do this by adding an effect that looks like this:
Note: Before sharing the code I must inform you that you must have an icon into the Resources/drawable with the name of ic_clear_icon.png.
/// <summary>
/// Adding a clear entry effect.
/// </summary>
public class ClearEntryEffect : PlatformEffect
{
/// <summary>
/// Attach the effect to the control.
/// </summary>
protected override void OnAttached()
{
ConfigureControl();
}
protected override void OnDetached()
{
}
private void ConfigureControl()
{
EditText editText = ((EditText)Control);
editText.AddTextChangedListener(new OnTextChangedListener(editText));
editText.FocusChange += EditText_FocusChange;
}
/// <summary>
/// If the entry looses focus, delete the x icon.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EditText_FocusChange(object sender, Android.Views.View.FocusChangeEventArgs e)
{
var editText = (EditText)sender;
if (e.HasFocus == false)
editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0);
}
}
/// <summary>
/// Adding an OnTextChangedListener to my entry.
/// </summary>
public class OnTextChangedListener : Java.Lang.Object, Android.Text.ITextWatcher
{
private EditText _editText;
public OnTextChangedListener(EditText editText)
{
_editText = editText;
}
public void AfterTextChanged(IEditable s)
{
}
public void BeforeTextChanged(ICharSequence s, int start, int count, int after)
{
}
public void OnTextChanged(ICharSequence s, int start, int before, int count)
{
if (count != 0)
{
_editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.ic_clear_icon, 0);
_editText.SetOnTouchListener(new OnDrawableTouchListener());
}
else
_editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0);
}
}
/// <summary>
/// Adding a Touch listener so it can be clicked in order to remove the text.
/// </summary>
public class OnDrawableTouchListener : Java.Lang.Object, Android.Views.View.IOnTouchListener
{
public bool OnTouch(Android.Views.View v, MotionEvent e)
{
if (v is EditText && e.Action == MotionEventActions.Up)
{
EditText editText = (EditText)v;
if (editText.Text != null)
editText.SetCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, Resource.Drawable.ic_clear_icon, 0);
if (editText.GetCompoundDrawables()[2] != null)
{
//If the region on which i tapped is the region with the X the text will be cleaned
if (e.RawX >= (editText.Right - editText.GetCompoundDrawables()[2].Bounds.Width()))
{
editText.Text = string.Empty;
return true;
}
}
}
return false;
}
}
On the iOS project side is more simple. Because it has it natively:
public class ClearEntryEffect : PlatformEffect
{
protected override void OnAttached()
{
ConfigureControl();
}
protected override void OnDetached()
{
}
private void ConfigureControl()
{
((UITextField)Control).ClearButtonMode = UITextFieldViewMode.WhileEditing;
}
}
Now you create an effect class on the PCL project in witch you reference the two ClearEntryEffect classes(from Android/iOS projects).
This effect class is needed so can it be refferenced from the XAML file where you declare your Entry.
public class ClearEntryEffect : RoutingEffect
{
public ClearEntryEffect() : base("Effects.ClearEntryEffect")
{
}
}
Now you just refference it on the shared forms project(PCL in my case) into the xaml:
1) Refferencing the namespace where the effect is located:
xmlns:effects="clr-namespace:YourNamespace.Common.Effects"
2) Adding the effect to the entry:
<Entry x:Name="OrderNo"
Text="{Binding OrderNo, Mode=TwoWay}"
<Entry.Effects>
<effects:ClearEntryEffect/>
</Entry.Effects>
</Entry>
This works on both Android and iOS.
Here is my xaml.
<Grid>
<Entry x:Name="search" TextChanged="SearchChanged" Placeholder="Search"/>
<Image x:Name="clearSearch" Source="delete.png" HeightRequest="16" WidthRequest="16" HorizontalOptions="End">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="OnSearchTap" NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
</Grid>
Here is my c#
private void OnSearchTap(object sender, EventArgs args)
{
search.Text = "";
}
The ClearButtonVisibility property has been added in a new Xamarin.Forms, so there is no need for custom renderers right now. For example:
<Entry Text="Xamarin.Forms"
ClearButtonVisibility="WhileEditing" />
See Display a clear button in Xamarin.Forms documentation.
I think u need renderer for this and for example in android platform set android:drawableRight. On iOS platform set RightView property of UITextview.
Another option is wrap your Entry in Grid with Image.
<Grid>
<Entry></Entry>
<Image Source="your image"
HeightRequest="24" // some height
WidthRequest="24" //some width
HorizontalOptions="End"
.... some margins>
</Image>
</Grid>

How to bind a ListView.ItemTapped event to a ViewModel command in Xamarin Forms?

I'm using Prism to implement MVVM.
And I have a situation where I have a ListView and have to handle the ItemTapped event and also get the tapped item.
I tried using EventToCommandBehavior.
But I couldn't get it to work cause it was not recognising the references that were added.
The EventToCommandBehavior does not currently exist in the pre1 package available on NuGet. This should be available when pre2 is released.
My recommendation would be that you either copy the EventToCommandBehavior to your project for now, or you could add one that I use:
/// <summary>
/// ListView Item Tapped Behavior.
/// </summary>
public class ItemTappedBehavior : BehaviorBase<ListView>
{
/// <summary>
/// Gets or sets the command.
/// </summary>
/// <value>The command.</value>
public ICommand Command { get; set; }
/// <inheritDoc />
protected override void OnAttachedTo( ListView bindable )
{
base.OnAttachedTo( bindable );
AssociatedObject.ItemTapped += OnItemTapped;
}
/// <inheritDoc />
protected override void OnDetachingFrom( ListView bindable )
{
base.OnDetachingFrom( bindable );
AssociatedObject.ItemTapped -= OnItemTapped;
}
void OnItemTapped( object sender, ItemTappedEventArgs e )
{
if ( Command == null || e.Item == null ) return;
if ( Command.CanExecute( e.Item ) )
Command.Execute( e.Item );
}
}
Then in your Xaml
<ListView.Behaviors>
<behaviors:ItemTappedBehavior Command="{Binding SelectedItemCommand}" />
</ListView.Behaviors>
I would suggest a different approach.
public class AppListView: ListView{
public AppListView(): base(ListViewCachingStrategy.RecycleElement){
this.ItemSelected += (s,e)=>{
this.TapCommand?.Invoke(e.Item);
}
}
#region Property TapCommand
/// <summary>
/// Bindable Property TapCommand
/// </summary>
public static readonly BindableProperty TapCommandProperty = BindableProperty.Create(
nameof(TapCommand),
typeof(System.Windows.Input.ICommand),
typeof(AppListView),
null,
BindingMode.OneWay,
null,
null,
null,
null,
null
);
/// <summary>
/// Property TapCommand
/// </summary>
public System.Windows.Input.ICommand TapCommand
{
get
{
return (System.Windows.Input.ICommand)GetValue(TapCommandProperty);
}
set
{
SetValue(TapCommandProperty, value);
}
}
#endregion
}
Now use AppListView instead of ListView and use TapCommand="{Binding ...}". In order for intellisense to work correctly, I suggest keep this class in a separate library project (one for android, one for iOS and keep this file in shared project between all library projects).

Mapping View Property to ViewModel using Catel

I'm doing a login view. Problem is that the PasswordBox cant be binded to the view model so im mapping a property of the view to the viewmodel.
This is the View
public partial class LoginView : MetroDataWindow
{
/// <summary>
/// Initializes a new instance of the <see cref="LoginView"/> class.
/// </summary>
public LoginView()
: this(null) { }
/// <summary>
/// Initializes a new instance of the <see cref="LoginView"/> class.
/// </summary>
/// <param name="viewModel">The view model to inject.</param>
/// <remarks>
/// This constructor can be used to use view-model injection.
/// </remarks>
public LoginView(LoginViewModel viewModel)
: base(viewModel)
{
InitializeComponent();
}
[ViewToViewModel(MappingType = ViewToViewModelMappingType.ViewToViewModel)]
public SecureString Contrasena
{
get { return (SecureString)GetValue(ContrasenaPropiedad); }
set { SetValue(ContrasenaPropiedad, value); }
}
// Using a DependencyProperty as the backing store for MapCenter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContrasenaPropiedad = DependencyProperty.Register("Contrasena", typeof(SecureString),
typeof(LoginView), new PropertyMetadata(null, (sender, e) => ((LoginView)sender).UpdateContrasena()));
private void UpdateContrasena()
{
MessageBox.Show("VIEW: FirstName changed to " + ContrasenaPropiedad.ToString());
}
private void tbPassword_PasswordChanged(object sender, RoutedEventArgs e)
{
Contrasena = tbPassword.SecurePassword;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == ContrasenaPropiedad)
{
int i = 0;
}
}
}
this is the viewmodel part with the property
public static readonly PropertyData ContrasenaPropiedad = RegisterProperty("Contrasena", typeof(SecureString), null, (sender, e) => ((LoginViewModel)sender).OnContrasenaChange());
public void OnContrasenaChange()
{
_messageService.Show("VIEW MODEL: FirstName changed to " + Contrasena.ToString());
}
public SecureString Contrasena
{
get
{
return GetValue<SecureString >(ContrasenaPropiedad);
}
set
{
SetValue(ContrasenaPropiedad, value);
}
}
the onChange function of the viewmodel never triggers.
I based this code on the example given in the last comment in this question
Catel ViewToViewModel attribute
But it does not work. Am I missing something or was the bug commented there never fixed?
Also since the view is the only one changing the property should i use the ViewToViewModelMappingType.ViewToViewModel type instead? does it change the implementation of the mapping in any way?
Passwords are a special kind of breed. But Catel has a solution for that problem, the UpdateBindingOnPasswordChanged behavior:
<PasswordBox>
<i:Interaction.Behaviors>
<catel:UpdateBindingOnPasswordChanged Password="{Binding Password, Mode=TwoWay}" />
</i:Interaction.Behaviors>
</PasswordBox>
ps. are you aware of Catel.Fody? It makes your code more readable and easier to write.

windows phone 8 longlistselector selectmore adding more

i am following the sample in the phonetoolkit longlistselector and msdn. I am trying to add the showmore functionality to my application page. Typically like in longlistselector i have authors displayed alphabetical wise and with show more button for each group.
problem:
the problem here is that i am not able to add a new author by pressing show more button, and also i am not able to update this in my longlistselector. I am finding problem adding an author in the Alphakeygroup class(found in the link i mentioned above). how can i do this?
this is my AlphaKeyGroup class
public class AlphaKeyGroup<T> : List<T>
{
/// <summary>
/// The delegate that is used to get the key information.
/// </summary>
/// <param name="item">An object of type T</param>
/// <returns>The key value to use for this object</returns>
public delegate string GetKeyDelegate(T item);
/// <summary>
/// The Key of this group.
/// </summary>
public string Key { get; private set; }
/// <summary>
/// Public constructor.
/// </summary>
/// <param name="key">The key for this group.</param>
public AlphaKeyGroup(string key)
{
Key = key;
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="slg">The </param>
/// <returns>Theitems source for a LongListSelector</returns>
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;
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="items">The items to place in the groups.</param>
/// <param name="ci">The CultureInfo to group and sort by.</param>
/// <param name="getKey">A delegate to get the key from an item.</param>
/// <param name="sort">Will sort the data if true.</param>
/// <returns>An items source for a LongListSelector</returns>
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;
if (slg.SupportsPhonetics)
{
//check if your database has yomi string for item
//if it does not, then do you want to generate Yomi or ask the user for this item.
//index = slg.GetGroupIndex(getKey(Yomiof(item)));
}
else
{
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;
}
}
this is my xaml page. when clicking the showmorebutton here i am sucessfully taken to the execute function in the morecommandclass . how can i add a author in the function and then update it in my longlistselector? basically i am finding it difficult to work with the AlphaKeyGroup class.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="AuthorsList" IsGroupingEnabled="true" HideEmptyGroups="True" LayoutMode="List"
ItemsSource="{Binding Authors}"
ListHeaderTemplate="{StaticResource movieListHeader}"
GroupHeaderTemplate="{StaticResource movieGroupHeader}"
ItemTemplate="{StaticResource movieItemTemplate}"
JumpListStyle="{StaticResource MoviesJumpListStyle}">
<!-- The group footer template, for groups in the main list -->
<phone:LongListSelector.GroupFooterTemplate>
<DataTemplate>
<Button DataContext="{Binding}" Content="Show More Records"
Command="{StaticResource moreCommand}" CommandParameter="{Binding}"/>
</DataTemplate>
</phone:LongListSelector.GroupFooterTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
my xaml.cs file
public CategoryFilter()
{
InitializeComponent();
authorsviewmodel = new AuthorsViewModel();
LoadAuthors();
}
private void LoadAuthors()
{
List<Author> movies = new List<Author>();
authorsviewmodel.GetAllAuthors();
var Authorsgroup = AlphaKeyGroup<Author>.CreateGroups(authorsviewmodel.AuthorsList, System.Threading.Thread.CurrentThread.CurrentUICulture, (Author s) => { return s.AuthorName; }, true);
AuthorsList.ItemsSource = Authorsgroup;
}
Morecommands class
public class MoreCommand : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
AlphaKeyGroup<Author> list = parameter as AlphaKeyGroup<Author>;
Author item = new Author();
item.AuthorName = "BAIG123";
list.Add(item);
AuthorsViewModel authorviewmodel=new AuthorsViewModel();
authorviewmodel.Authors = parameter as List<AlphaKeyGroup<Author>>;
authorviewmodel.Authors.Add(list);
}
#endregion
}
The problem is that when you modify a List your view will not get notified of the change.
You can just change class AlphaKeyGroup<T> : List<T> to class AlphaKeyGroup<T> : ObservableCollection<T> and that should fix this problem.

Pivot Itemssource not updating

Hi I have a Category class where I am downloading data from API and displaying in Pivot, now for index 0 of Pivot the data loads, I have added a Pivot selection changed event when user flips to other PivotItems and data get loaded. But the issue is the ItemsSource is not updating. If I do like this pivot.itemssource=""; and pivot.itemssource=mylist; I have to change the pivot.selectedIndex to current index also, in this case the flip is not smooth, it first goes to 0 index because of pivot.itemssource=""; and then come to actual place. Please help me getting a solution for this so that it binds and update automatically. My classes are below:
Category.xaml
<Grid x:Name="LayoutRoot" >
<controls:Pivot Margin="0,53,0,28" x:Name="CategoryList" Foreground="White" SelectionChanged="Pivot_SelectionChanged" ItemsSource="{Binding Constants.categoryDetails}" >
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock x:Name="PivotTitle" Text="{Binding name}"></TextBlock>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<!--Panorama item one-->
<controls:Pivot.ItemTemplate>
<DataTemplate>
<Grid>
<ListBox x:Name="subCatList" ItemsSource="{Binding subcategories}" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="2" BorderBrush="White">
<Grid Width="420" Height="70" Background="#85000000">
<TextBlock Text="{Binding name}" FontFamily="Verdana" FontSize="35" Margin="10,10,64,5" TextWrapping="Wrap" ></TextBlock>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
</Grid>
<!--Panorama-based applications should not show an ApplicationBar-->
</phone:PhoneApplicationPage>
Category.cs
namespace MyApp.Views
{
public partial class Category : PhoneApplicationPage
{
List<WebClient> webclientsList = new List<WebClient>();
private int selectedIndex=0;
private ListBox subCatList;
public readonly DependencyProperty ListVerticalOffsetProperty;
public Category()
{
InitializeComponent();
for (int i = 0; i < Constants.catList.Length; i++)
{
WebClient wb = new WebClient();
CategoriesClass ct = new CategoriesClass();
ct.name = Constants.catList[i];
webclientsList.Add(wb);
Constants.categoryDetails.Add(ct);
}
loadCategory();
}
private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
selectedIndex = CategoryList.SelectedIndex;
if (Constants.categoryDetails[selectedIndex].subcategories==null) {
loadCategory();
}
else{
}
}
private void loadCategory()
{
try
{
String Url = Constants.BASE_URL + "/get-category-data/?client_key=" + Constants.CLIENT_KEY;
webclientsList[selectedIndex].DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClientCategoryDownload);
webclientsList[selectedIndex].DownloadStringAsync(new Uri(Url));
}
catch (Exception e)
{
Console.WriteLine("Error Occured"+e.StackTrace);
}
}
void webClientCategoryDownload(object sender, DownloadStringCompletedEventArgs e)
{
try
{
if (e.Error != null)
{
Console.WriteLine("Error geting category");
return;
}
CategoryClass ctClass = new CategoryClass();
ctClass = JsonConvert.DeserializeObject<CategoryClass>(e.Result);
if (ctClass.name!=null)
{
Console.WriteLine("Category Loaded");
Constants.categoryDetails[selectedIndex].categoryDetails = ctClass;
Constants.categoryDetails[selectedIndex].subcategories = new ObservableCollection<SubCategories>();
foreach (var its in ctClass.categories)
{
foreach(var chi in its.children){
Constants.categoryDetails[selectedIndex].subcategories.Add(chi);
}
}
CategoryList.ItemsSource = "";
CategoryList.SelectedIndex = selectedIndex;
CategoryList.ItemsSource = Constants.categoryDetails;
for(int i=0;i<Constants.categoryDetails.Count;i++){
foreach (var x2 in Constants.categoryDetails[selectedIndex].subcategories)
{
Console.WriteLine("SubCategory is :"+x2.name);
}
}
}
else {
Console.WriteLine("Categories Doesnt Exists ");
}
}
catch (Exception e1)
{
Console.WriteLine("Exception Occured:"+e1.StackTrace);
}
}
private void Facebook_login(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/Views/Login.xaml", UriKind.Relative));
}
}
}
First of all try to set
pivot.itemssource=null;
And then
pivot.itemssource=myList;
But it's wrong way.
If you want to become a good Windows Phone developer, you must to know what is MVVM.
First of all, you must read and UNDERSTAND this article
Then try to understand how to use existing mvvm toolkit, for example MVVM Light or Caliburn.Micro.
You should have a good understanding of how to work with MVVM and then you can solve your problem yourself.
Hope it's help.
Also check this useful question.
And this,this, this and this
Below are the steps I followed for MVVM use in my project.
Install MVVM from silverlight
http://www.galasoft.ch/mvvm/installing/ Dont know the exact link but I think its available here.
Now restart your visual studio.
Go to Right click on your project and add new Items to your project.
Now add Model View Locator inside ViewModel folder. (It will be good practice to keep these file
into a new folder like ViewModel, View, Model)
Now you have created a viewlocator which handles all the process like cleaning for a viewmodel.
Now in the same folder create a modelview for your requirement edit like below, and also you are
free to add more parameters acc to your requirement.
using GalaSoft.MvvmLight;
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using MyProject.Model;
namespace MyProject.ViewModel
{
public class ProductViewModel : INotifyPropertyChanged
{
private ObservableCollection<ProductsClass> productData;
public ObservableCollection<ProductsClass> ProductData
{
get
{
return productData;
}
set {
productData = value;
RaisePropertyChanged("ProductData");
}
}
public ProductViewModel(ObservableCollection<ProductsClass> productData)
{
ProductData = productData;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
/// <summary>
/// Initializes a new instance of the ProductViewModel class.
/// </summary>
public ProductViewModel()
{
////if (IsInDesignMode)
////{
//// // Code runs in Blend --> create design time data.
////}
////else
////{
//// // Code runs "for real": Connect to service, etc...
////}
}
////public override void Cleanup()
////{
//// // Clean own resources if needed
//// base.Cleanup();
////}
}
}
Now we have created our modelview, we have to mention something for this in our locator as
follows(Make the necessary changes only):
namespace Myproject.ViewModel
{
public class ViewModelLocator
{
private static MainViewModel _main;
/// <summary>
/// Initializes a new instance of the ViewModelLocator class.
/// </summary>
private static ProductViewModel _viewModelProduct;
public ViewModelLocator()
{
CreateMain();
CreateViewModelProduct();
}
/// <summary>
/// Gets the Main property.
/// </summary>
public static MainViewModel MainStatic
{
get
{
if (_main == null)
{
CreateMain();
}
return _main;
}
}
/// <summary>
/// Gets the Main property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return MainStatic;
}
}
/// <summary>
/// Provides a deterministic way to delete the Main property.
/// </summary>
public static void ClearMain()
{
_main.Cleanup();
_main = null;
}
/// <summary>
/// Provides a deterministic way to create the Main property.
/// </summary>
public static void CreateMain()
{
if (_main == null)
{
_main = new MainViewModel();
}
}
/// <summary>
/// Cleans up all the resources.
/// </summary>
public static void Cleanup()
{
ClearMain();
ClearViewModelProduct();
}
//Product model declaration
/// <summary>
/// Gets the ViewModelPropertyName property.
/// </summary>
public static ProductViewModel ProductViewModelStatic
{
get
{
if (_viewModelProduct == null)
{
CreateViewModelProduct();
}
return _viewModelProduct;
}
}
/// <summary>
/// Gets the ViewModelPropertyName property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public ProductViewModel ViewModelProduct
{
get
{
return ProductViewModelStatic;
}
}
/// <summary>
/// Provides a deterministic way to create the ViewModelPropertyName property.
/// </summary>
public static void CreateViewModelProduct()
{
if (_viewModelProduct == null)
{
_viewModelProduct = new ProductViewModel();
}
}
/// <summary>
/// Provides a deterministic way to delete the ViewModelPropertyName property.
/// </summary>
public static void ClearViewModelProduct()
{
//_main.Cleanup();
_viewModelProduct = null;
}
}
}
Now inside your VIew create a variable like
private ProductViewModel pvm;
inside constructor add this:
pvm = (ProductViewModel)Resources["pviewModel"];
Add this in your loaded method:
Binding binding = new Binding("ProductData") { Source = pvm };
Like
private void Product_Loaded(object sender, RoutedEventArgs e)
{
//Additional Code
pvm.ProductData = Constants.productDet;
//Additional Code
Binding binding = new Binding("ProductData") { Source = pvm };
}
Now after adding some more code in your xaml file whenever you update anything in .cs it will
automatically reflect in your view.
Make following in your xaml file:
DataContext="{Binding ViewModelProduct, Source={StaticResource Locator}}"
Loaded="Product_Loaded"> at the top declaration
<phone:PhoneApplicationPage.Resources>
<viewModel:ProductViewModel x:Key="pviewModel" />
</phone:PhoneApplicationPage.Resources>
Now the productsclass will be similar like this(its on u how u add parameters acc to ur requirement)
namespace Myproject.Model
{
public class ProductsClass : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
// NotifyPropertyChanged("Name");
}
}
}
private ProductClass productDetailsOverview;
public ProductClass ProductDetailsOverview
{
get { return productDetailsOverview; }
set
{
if (productDetailsOverview != value)
{
productDetailsOverview = value;
NotifyPropertyChanged("ProductDetailsOverview");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class ProductClass
{
public long product_start_offset { get; set; }
public ObservableCollection<FiltersData> filters_data { get; set; }
public long product_end_offset { get; set; }
public long product_count { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
and you can use ProductDetailsOverview in the itemssource to access any parameter like
ItemsSource="{Binding ProductDetailsOverview.product_list}

Resources