Mapping View Property to ViewModel using Catel - view

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.

Related

Xamarin Forms: How to handle a subcribe event from view to viewmodel (ListView - Search Bar)

All,
I'm building a custom SearchableListView that binds the SearchText property.
public class SearchableListView : SfListView
{
#region Field
/// <summary>
/// Gets or sets the text value used to search.
/// </summary>
public static readonly BindableProperty SearchTextProperty =
BindableProperty.Create(nameof(SearchText), typeof(string), typeof(SearchableListView), null, BindingMode.Default, null, OnSearchTextChanged);
/// <summary>
/// Gets or sets the text value used to search.
/// </summary>
private string searchText;
#endregion
#region Property
/// <summary>
/// Gets or sets the text value used to search.
/// </summary>
public string SearchText
{
get
{
return (string)this.GetValue(SearchTextProperty);
}
set
{
this.SetValue(SearchTextProperty, value);
}
}
#endregion
#region Method
/// <summary>
/// Filtering the list view items based on the search text.
/// </summary>
/// <param name="obj">The list view item</param>
/// <returns>Returns the filtered item</returns>
public virtual bool FilterData(object obj)
{
if (this.SearchText == null)
{
return false;
}
return true;
}
/// <summary>
/// Invoked when the search text is changed.
/// </summary>
/// <param name="bindable">The SfListView</param>
/// <param name="oldValue">The old value</param>
/// <param name="newValue">The new value</param>
private static void OnSearchTextChanged(BindableObject bindable, object oldValue, object newValue)
{
var listView = bindable as SearchableListView;
if (newValue != null && listView.DataSource != null)
{
listView.searchText = (string)newValue;
listView.DataSource.Filter = listView.FilterData;
listView.DataSource.RefreshFilter();
}
listView.RefreshView();
}
#endregion
}
This view is binding to a Generic List Items, so the object on FilterData can be any type.
IDK how to subscribe an event to the FilterData which executes the method on the view model where I can cast my object to my known type.
This is my ViewModel.
public abstract class ListPageViewModel<T> : BaseViewModel where T : class, IEntity
{
private T _selectedItem;
private string searchText;
private ObservableCollection<T> _items;
public ListPageViewModel()
{
this.NewCommand = new Command(NewItem);
this.ItemSelectedCommand = new Command(ItemSelected);
}
public ObservableCollection<T> Items
{
get => _items;
set
{
this.SetProperty(ref this._items, value);
}
}
public T SelectedItem
{
get => _selectedItem;
set
{
this.SetProperty(ref this._selectedItem, value);
}
}
public string SearchText
{
get => searchText;
set
{
this.SetProperty(ref this.searchText, value);
}
}
public ICommand NewCommand { get; set; }
public ICommand ItemSelectedCommand { get; set; }
public async virtual void LoadItemsAsync()
{
Items = new ObservableCollection<T>(await localDataService.GetAllAsync<T>());
}
public async virtual void NewItem(object obj)
{
}
public async virtual void ItemSelected(object obj)
{
var eventArgs = obj as Syncfusion.ListView.XForms.ItemTappedEventArgs;
navigationService.NavigateTo(EditViewModel, "editEntity", eventArgs.ItemData, false);
await MtTaskExtensions.CompletedTask;
}
}
Since it's a virtual method, can't you just override the method in the ViewModel like this?
public class MyListPageViewModel : ListPageViewModel<MyClass>
{
public override bool FilterData(object obj)
{
if(obj is MyClass myObj)
{
// Do something
}
return base
.FilterData(obj);
}
}

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).

Show / Hide checkbox in Xamarin Forms

I am trying to figure out a way to make checkbox appear on button click on a page.
It's invisible by default, because I've set checkBox.Visibility = Android.Views.ViewStates.Invisible; in my custom renderer.
I have a button in the page content and a checkbox in the template which resides in pages resources.
From my ViewModel I am able to invoke PropertyChanged in CheckBox control where I can see the old and new value correctly set.
But I need a way to set it on the ViewRenderer. I'm guessing that it needs to handle some kind of event similar to CheckedChanged.
ViewModel
CheckBox c = new CheckBox { IsCheckBoxVisible=true,IsVisible=true };
CheckBox control
public class CheckBox : View
{
/// <summary>
/// The checked state property.
/// </summary>
public static readonly BindableProperty CheckedProperty =
BindableProperty.Create<CheckBox, bool>(
p => p.Checked, false, BindingMode.TwoWay, propertyChanged: OnCheckedPropertyChanged);
**public static readonly BindableProperty IsCheckBoxVisibleProperty =
BindableProperty.Create<CheckBox, bool>(
p => p.IsCheckBoxVisible, false, BindingMode.OneWay, propertyChanged: OnVisibilityPropertyChanged);**
/// <summary>
/// The checked text property.
/// </summary>
public static readonly BindableProperty CheckedTextProperty =
BindableProperty.Create<CheckBox, string>(
p => p.CheckedText, string.Empty, BindingMode.TwoWay);
/// <summary>
/// The unchecked text property.
/// </summary>
public static readonly BindableProperty UncheckedTextProperty =
BindableProperty.Create<CheckBox, string>(
p => p.UncheckedText, string.Empty);
/// <summary>
/// The default text property.
/// </summary>
public static readonly BindableProperty DefaultTextProperty =
BindableProperty.Create<CheckBox, string>(
p => p.Text, string.Empty);
/// <summary>
/// Identifies the TextColor bindable property.
/// </summary>
///
/// <remarks/>
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create<CheckBox, Color>(
p => p.TextColor, Color.Default);
/// <summary>
/// The font size property
/// </summary>
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create<CheckBox, double>(
p => p.FontSize, -1);
/// <summary>
/// The font name property.
/// </summary>
public static readonly BindableProperty FontNameProperty =
BindableProperty.Create<CheckBox, string>(
p => p.FontName, string.Empty);
/// <summary>
/// The checked changed event.
/// </summary>
public event EventHandler<EventArgs<bool>> CheckedChanged;
**public event EventHandler<EventArgs<bool>> VisibilityChanged;**
/// <summary>
/// Gets or sets a value indicating whether the control is checked.
/// </summary>
/// <value>The checked state.</value>
public bool Checked
{
get
{
return this.GetValue<bool>(CheckedProperty);
}
set
{
if (this.Checked != value)
{
this.SetValue(CheckedProperty, value);
this.CheckedChanged.Invoke(this, value);
}
}
}
**public bool IsCheckBoxVisible
{
get
{
return this.GetValue<bool>(IsCheckBoxVisibleProperty);
}
set
{
if (this.IsCheckBoxVisible != value)
{
this.SetValue(IsCheckBoxVisibleProperty, value);
this.VisibilityChanged.Invoke(this, value);
//OnPropertyChanged("IsCheckBoxVisible");
}
}
}**
/// <summary>
/// Gets or sets a value indicating the checked text.
/// </summary>
/// <value>The checked state.</value>
/// <remarks>
/// Overwrites the default text property if set when checkbox is checked.
/// </remarks>
public string CheckedText
{
get
{
return this.GetValue<string>(CheckedTextProperty);
}
set
{
this.SetValue(CheckedTextProperty, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether the control is checked.
/// </summary>
/// <value>The checked state.</value>
/// <remarks>
/// Overwrites the default text property if set when checkbox is checked.
/// </remarks>
public string UncheckedText
{
get
{
return this.GetValue<string>(UncheckedTextProperty);
}
set
{
this.SetValue(UncheckedTextProperty, value);
}
}
/// <summary>
/// Gets or sets the text.
/// </summary>
public string DefaultText
{
get
{
return this.GetValue<string>(DefaultTextProperty);
}
set
{
this.SetValue(DefaultTextProperty, value);
}
}
/// <summary>
/// Gets or sets the color of the text.
/// </summary>
/// <value>The color of the text.</value>
public Color TextColor
{
get
{
return this.GetValue<Color>(TextColorProperty);
}
set
{
this.SetValue(TextColorProperty, value);
}
}
/// <summary>
/// Gets or sets the size of the font.
/// </summary>
/// <value>The size of the font.</value>
public double FontSize
{
get
{
return (double)GetValue(FontSizeProperty);
}
set
{
SetValue(FontSizeProperty, value);
}
}
/// <summary>
/// Gets or sets the name of the font.
/// </summary>
/// <value>The name of the font.</value>
public string FontName
{
get
{
return (string)GetValue(FontNameProperty);
}
set
{
SetValue(FontNameProperty, value);
}
}
/// <summary>
/// Gets the text.
/// </summary>
/// <value>The text.</value>
public string Text
{
get
{
return this.Checked
? (string.IsNullOrEmpty(this.CheckedText) ? this.DefaultText : this.CheckedText)
: (string.IsNullOrEmpty(this.UncheckedText) ? this.DefaultText : this.UncheckedText);
}
}
/// <summary>
/// Called when [checked property changed].
/// </summary>
/// <param name="bindable">The bindable.</param>
/// <param name="oldvalue">if set to <c>true</c> [oldvalue].</param>
/// <param name="newvalue">if set to <c>true</c> [newvalue].</param>
private static void OnCheckedPropertyChanged(BindableObject bindable, bool oldvalue, bool newvalue)
{
var checkBox = (CheckBox)bindable;
checkBox.Checked = newvalue;
}
**private static void OnVisibilityPropertyChanged(BindableObject bindable, bool oldvalue, bool newvalue)
{
var checkBox = (CheckBox)bindable;
checkBox.IsCheckBoxVisible = newvalue;
}**
}
CheckBoxRenderer
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (this.Control == null)
{
var checkBox = new Android.Widget.CheckBox(this.Context);
checkBox.Visibility = Android.Views.ViewStates.Invisible;
checkBox.CheckedChange += CheckBoxCheckedChange;
defaultTextColor = checkBox.TextColors;
this.SetNativeControl(checkBox);
}
Control.Text = e.NewElement.Text;
Control.Checked = e.NewElement.Checked;
UpdateTextColor();
if (e.NewElement.FontSize > 0)
{
Control.TextSize = (float)e.NewElement.FontSize;
}
if (!string.IsNullOrEmpty(e.NewElement.FontName))
{
Control.Typeface = TrySetFont(e.NewElement.FontName);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
switch (e.PropertyName)
{
case "Checked":
Control.Text = Element.Text;
Control.Checked = Element.Checked;
break;
case "TextColor":
UpdateTextColor();
break;
case "FontName":
if (!string.IsNullOrEmpty(Element.FontName))
{
Control.Typeface = TrySetFont(Element.FontName);
}
break;
case "FontSize":
if (Element.FontSize > 0)
{
Control.TextSize = (float)Element.FontSize;
}
break;
case "CheckedText":
case "UncheckedText":
Control.Text = Element.Text;
break;
** case "IsCheckBoxVisible":
if(Element.IsCheckBoxVisible==true)
{
Control.Visibility = Android.Views.ViewStates.Visible;
}
else
{
Control.Visibility = Android.Views.ViewStates.Invisible;
}
break;**
default:
System.Diagnostics.Debug.WriteLine("Property change for {0} has not been implemented.", e.PropertyName);
break;
}
}
So this should actually be really simple. right now you have IsCheckBoxVisibleProperty, and you can get rid of it all together. The Xamarin.Forms.View already has an IsVisible property, and each platform specific renderer (VisualElementRenderer) knows how to handle visibility.
Therefore you can do this without issue.
var checkbox = new Checkbox();
checkbox .SetBinding (Checkbox.IsVisibleProperty, "IsCheckboxVisible");
Or in your XAML
<controls:Checkbox IsVisible="{Binding IsCheckboxVisible}" />
Of course this assumes you have a ViewModel similar to.
public class MyViewModel : BaseViewModel
{
private bool _isCheckboxVisible;
public bool IsCheckboxVisible
{
get { return _isCheckboxVisible; }
set { SetField(ref _isCheckboxVisible, value); }
}
}

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}

NavigationService.GoBack() unauthorized expcetion

void CallBackVerifiedResponse(OAuthAccessToken at, TwitterResponse response)
{
if (at != null)
{
SerializeHelper.SaveSetting<TwitterAccess>("TwitterAccess", new TwitterAccess
{
AccessToken = at.Token,
AccessTokenSecret = at.TokenSecret,
ScreenName = at.ScreenName,
UserId = at.UserId.ToString()
});
}
}
private void ok_Click_1(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(pinText.Text))
MessageBox.Show("Please enter PIN");
else
{
try
{
var cb = new Action<OAuthAccessToken, TwitterResponse>(CallBackVerifiedResponse);
service.GetAccessToken(_requestToken, pinText.Text, CallBackVerifiedResponse);
}
catch
{
MessageBox.Show("Something is wrong with the PIN. Try again please.", "Error", MessageBoxButton.OK);
}
}
}
My problem in is here when I use NavigationService.GoBack() inside the CallBackVerifiedResponse method i'm getting unauthorized access exception, and if i use it inside of the click event, I CallBackVerifiedResponse is not triggered. Any ideas?
It's been solved by using UIThread
public static class UIThread
{
private static readonly Dispatcher Dispatcher;
static UIThread()
{
// Store a reference to the current Dispatcher once per application
Dispatcher = Deployment.Current.Dispatcher;
}
/// <summary>
/// Invokes the given action on the UI thread - if the current thread is the UI thread this will just invoke the action directly on
/// the current thread so it can be safely called without the calling method being aware of which thread it is on.
/// </summary>
public static void Invoke(Action action)
{
if (Dispatcher.CheckAccess())
action.Invoke();
else
Dispatcher.BeginInvoke(action);
}
}
After this static class
I have called it inside of
CallBackVerifiedResponse
like this
UIThread.Invoke(()=>NavigationService.GoBack());
You can use Dispatcher.BeginInvoke to access the UIThread
Dispatcher.BeginInvoke(() =>
{
NavigationService.GoBack();
});
Or you could use your own smart dispatcher, used like this:
SmartDispatcher.BeginInvoke(() =>
{
MissionAccomplished();
});
Coded something as the following:
{
using System.ComponentModel;
using System.Windows.Threading;
using System.Windows;
using System;
public static class SmartDispatcher
{
/// <summary>
/// A single Dispatcher instance to marshall actions to the user
/// interface thread.
/// </summary>
private static Dispatcher _instance;
/// <summary>
/// Backing field for a value indicating whether this is a design-time
/// environment.
/// </summary>
private static bool? _designer;
/// <summary>
/// Requires an instance and attempts to find a Dispatcher if one has
/// not yet been set.
/// </summary>
private static void RequireInstance()
{
if (_designer == null)
{
_designer = DesignerProperties.IsInDesignTool;
}
// Design-time is more of a no-op, won't be able to resolve the
// dispatcher if it isn't already set in these situations.
if (_designer == true)
{
return;
}
// Attempt to use the RootVisual of the plugin to retrieve a
// dispatcher instance. This call will only succeed if the current
// thread is the UI thread.
try
{
_instance = Application.Current.RootVisual.Dispatcher;
}
catch (Exception e)
{
throw new InvalidOperationException("The first time SmartDispatcher is used must be from a user interface thread. Consider having the application call Initialize, with or without an instance.", e);
}
if (_instance == null)
{
throw new InvalidOperationException("Unable to find a suitable Dispatcher instance.");
}
}
/// <summary>
/// Initializes the SmartDispatcher system, attempting to use the
/// RootVisual of the plugin to retrieve a Dispatcher instance.
/// </summary>
public static void Initialize()
{
if (_instance == null)
{
RequireInstance();
}
}
/// <summary>
/// Initializes the SmartDispatcher system with the dispatcher
/// instance.
/// </summary>
/// <param name="dispatcher">The dispatcher instance.</param>
public static void Initialize(Dispatcher dispatcher)
{
if (dispatcher == null)
{
throw new ArgumentNullException("dispatcher");
}
_instance = dispatcher;
if (_designer == null)
{
_designer = DesignerProperties.IsInDesignTool;
}
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static bool CheckAccess()
{
if (_instance == null)
{
RequireInstance();
}
return _instance.CheckAccess();
}
/// <summary>
/// Executes the specified delegate asynchronously on the user interface
/// thread. If the current thread is the user interface thread, the
/// dispatcher if not used and the operation happens immediately.
/// </summary>
/// <param name="a">A delegate to a method that takes no arguments and
/// does not return a value, which is either pushed onto the Dispatcher
/// event queue or immediately run, depending on the current thread.</param>
public static void BeginInvoke(Action a)
{
if (_instance == null)
{
RequireInstance();
}
// If the current thread is the user interface thread, skip the
// dispatcher and directly invoke the Action.
if (_instance.CheckAccess() || _designer == true)
{
a();
}
else
{
_instance.BeginInvoke(a);
}
}
}
}

Resources