filling an ImageSource with a selector - c#

i'm trying to fill up an image from a selector based on this https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/photo-picker
the selector works fine and the stream fills up. however i do not get the picture on my screen.
public Command SelectPictureCommand { get; }
public ImageSource ItemPic { get; set; }
SelectPictureCommand = new Command(execute: async () =>
{
if (IsBusy)
{
return;
}
IsBusy = true;
try
{
Stream stream = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
if (stream != null)
{
ItemPic = ImageSource.FromStream(() => stream);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
});
xaml
<StackLayout Orientation="Vertical" HorizontalOptions="End">
<Button Text="Select Picture" Command="{Binding SelectPictureCommand}"/>
<Image Source="{Binding ItemPic}" WidthRequest="300" HeightRequest="300"/>
</StackLayout>

You should implement the INotifyPropertyChanged interface in your ViewModel or Model:
ViewModels generally implement the INotifyPropertyChanged interface,
which means that the class fires a PropertyChanged event whenever one
of its properties changes. The data binding mechanism in Xamarin.Forms
attaches a handler to this PropertyChanged event so it can be notified
when a property changes and keep the target updated with the new
value.
public class myViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
public Command SelectPictureCommand { get; }
public ImageSource itemPic { get; set; }
public ImageSource ItemPic
{
set
{
if (itemPic != value)
{
itemPic = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ItemPic"));
}
}
}
get
{
return itemPic;
}
}
public myViewModel() {
SelectPictureCommand = new Command(execute: async () =>
{
//if (IsBusy)
//{
// return;
//}
//IsBusy = true;
try
{
Stream stream = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();
if (stream != null)
{
ItemPic = ImageSource.FromStream(() => stream);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
//IsBusy = false;
}
});
}
}
I uploaded a sample here and you can check. Feel free to ask me any problem if you have.

You can use CrossMedia Plugin, example:
await CrossMedia.Current.Initialize();
var file = await CrossMedia.Current.PickPhotoAsync();
var filestream = file.GetStream();
byte[] buff = ConverteStreamToByteArray(filestream);
image.Source = ImageSource.FromStream(buff);
filestream.Dispose();

Related

CollectionView not loading Xamarin.Forms on load

Need help regarding CollectionView not loading data from API upon loading. I need to pull-down refresh first before the data will show. I'm doing it MVVM.
Below is my XAML:
<RefreshView x:DataType="local:MainPageViewModel" Command="{Binding LoadReleaseDocuments}"
IsRefreshing="{Binding IsRefreshing ,Mode=OneWay}"
RefreshColor="#FFFF7F50">
<CollectionView x:Name="SuccessList"
ItemsSource="{Binding ReleasedDocuments}"
SelectionMode="Single" >
...
</CollectionView>
</RefreshView>
And this is my code behind:
public ObservableCollection<Release> ReleasedDocuments { get; }
public MainPageViewModel()
{
// collection
ReleasedDocuments = new ObservableCollection<Release>();
DeliveredDocuments = new ObservableCollection<Deliver>();
CallNow = new Command<Deliver>(Call_Now);
//Load
LoadDocuments = new Command(ExecuteLoadItemsCommand);
LoadReleaseDocuments = new Command(ExecuteCommand);
}
And below code is where I get my data thru API calls
void ExecuteCommand()
{
bool forceRefresh = true;
if (IsRefreshing)
return;
IsRefreshing = true;
Device.BeginInvokeOnMainThread(async () =>
{
try
{
ReleasedDocuments.Clear();
switch (Application.Current.Properties["Position"])
{
case string a when a.Contains("Courier"):
var items = await DataStore.GetItemsAsync(forceRefresh, Application.Current.Properties["Position"].ToString(), "tmdm");
items = items.Where(ab => ab.TMNo != null).Where(ac => ac.TMNo.Contains("DM"));
var sortedItems = items.OrderByDescending(c => c.OrderDate);
CourierDMData(sortedItems);
break;
}
}
catch (Exception ex)
{
IsBusy = false;
IsRefreshing = false;
...
}
finally
{
IsBusy = false;
IsRefreshing = false;
}
});
IsRefreshing = false;
}
And inserting it to ObservableCollection
void CourierDMData(IOrderedEnumerable<Summary> sortedItems)
{
ReleasedDocuments.Clear();
foreach (var itemx in sortedItems)
{
if (itemx.statusId == 0)
{
ReleasedDocuments.Add(new Release()
{
Id = itemx.Id,
....
});
}
}
CountRelease = ReleasedDocuments.Count;
}
When debugging, I can get the CountRelease = ReleasedDocuments.Count; value (count) it is displaying correctly the value, but the CollectionView is not showing anything until I refresh.
I'm usually doing a work around and call refresh with the PageAppearingEvent and use Xamarin Community Toolkit EventToCommandBehavior to call a function which calls the refresh function with a small delay if necessary. This way I don't have to manually refresh each time I open the page.
XAML example:
<ContentPage.Behaviors>
<xct:EventToCommandBehavior
EventName="Appearing"
Command="{Binding AppearingCommand}"/>
</ContentPage.Behaviors>
MVVM example:
public MyViewModel() //constructor
{
AppearingCommand = new Command(OnAppearing);
}
public ICommand AppearingCommand { get; }
private void OnAppearing()
{
await System.Threading.Tasks.Task.Delay(int delay); //only if necessary because of initialization
Refresh(); //Or else set your public properties
}

Trying to update an image source in an imagebutton with data binding using a command in the viewmodel - not working

Please forgive the newbie question but I am struggling to understand where I have gone wrong...
I am trying to change an imagebutton (in a grid) by binding the image source in xaml:
<ImageButton x:Name="playButton"
Source="{Binding PlayImage}"
Command="{Binding PlayCommand}"
Grid.Row="1"
Grid.Column="0"
BorderColor="#fafafa"
BackgroundColor="#fafafa"
/>
The ImageButton loads up with the correct 'play.png' initially.
The Command 'PlayCommand' is working with the binding. This should change the value of the PlayImage to show the 'pause.png' image when the user clicks the imagebutton. Although the value of the PlayImage variable is changed, the image will not update. Please can someone tell me what I am missing? Here is my ViewModel:
public class SermonDetailViewModel : BaseViewModel
{
public Sermon Sermon { get; set; }
public ICommand PlayCommand { private set; get; }
private ImageSource _playImage;
public ImageSource PlayImage
{
get { return _playImage; }
set
{
_playImage = value;
SetProperty(ref _playImage, value);
}
}
public SermonDetailViewModel(Sermon sermon = null)
{
if (sermon != null)
{
Title = sermon.STitle;
MP3Filepath = sermon.SLink;
PlayCommand = new Command(async () => await StartPlayer());
_playImage = "play.png";
}
Sermon = sermon;
}
async Task StartPlayer()
{
await CrossMediaManager.Current.Play(MP3Filepath);
_playImage = "pause.png";
Console.WriteLine(_playImage);
Console.WriteLine(PlayImage);
}
and this is my baseViewModel code which uses the class INotifyPropertyChanged and sets up the setProperty method:
public class BaseViewModel : INotifyPropertyChanged
{
public IDataStore<Item> DataStore => DependencyService.Get<IDataStore<Item>>();
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
string mp3filepath = string.Empty;
public string MP3Filepath
{
get { return mp3filepath; }
set { SetProperty(ref mp3filepath, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName]string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
I would really appreciate some help here.....thanks!
I try your code and do one sample to test, and I agree with Jason's opinion, please try to set PlayImage value, don't set _playImage, I find that although the value of PlayImage has been updated, it is not bound to ImageButton.
Please change the code like following code:
public SermonDetailViewModel(Sermon sermon = null)
{
if (sermon != null)
{
Title = sermon.STitle;
MP3Filepath = sermon.SLink;
PlayCommand = new Command(async () => await StartPlayer());
PlayImage= "play.png";
}
Sermon = sermon;
}
async Task StartPlayer()
{
await CrossMediaManager.Current.Play(MP3Filepath);
PlayImage= "pause.png";
Console.WriteLine(_playImage);
Console.WriteLine(PlayImage);
}
I also do one sample that you can take a look:
<ImageButton
BackgroundColor="#fafafa"
BorderColor="#fafafa"
Command="{Binding PlayCommand}"
HeightRequest="50"
Source="{Binding PlayImage}"
WidthRequest="50" />
public partial class Page4 : ContentPage
{
public Page4()
{
InitializeComponent();
this.BindingContext = new SermonDetailViewModel();
}
}
public class SermonDetailViewModel:ViewModelBase
{
public ICommand PlayCommand { private set; get; }
private ImageSource _playImage;
public ImageSource PlayImage
{
get { return _playImage; }
set
{
_playImage = value;
RaisePropertyChanged("PlayImage");
}
}
public SermonDetailViewModel()
{
PlayCommand = new Command(method1);
_playImage = "check.png";
}
private void method1()
{
PlayImage = "plu3.png";
}
}
Try
Source="{Binding PlayImage, Mode=TwoWay }"
This can also help you with binding
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/binding-mode
you are setting the private backing field, not the public property. This means that the PropertyChanged event will not be raised
async Task StartPlayer()
{
await CrossMediaManager.Current.Play(MP3Filepath);
// should be PlayImage = "pause.png";
_playImage = "pause.png";
Console.WriteLine(_playImage);
Console.WriteLine(PlayImage);
}
It works with the code:
private ImageSource _playImage;
public ImageSource PlayImage
{
get { return _playImage; }
set
{
_playImage = value;
Notify("PlayImage");
}
}
protected void Notify(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Property not updating after service completes

I'm trying to get my head around data binding in Xamarin.Forms. I've read lots of the guides and played with some examples and I am now trying to implement some of my own basic binding.
I've got a Strings file in which I've declared an empty variable:
public static class Strings
{
public static string UserDisplayName;
}
On load of my View, it runs an async function to grab data from a Azure SQL DB which then populates the string
Strings.UserDisplayName = user.FirstName;
In my view page I've bound a label to a variable userDisplayNm
<Label Text="{Binding UserDisplayNm}"></Label>
In my ViewModel I have the following to set UserDisplayNm, however it only ever returns "Welcome, ". How do i get it to fire this again after the sync service has completed & the Strings.UserDisplayname value changes? I think I'm missing a link to an PropertyChanged event or something?
namespace Travel_Comp.ViewModels
{
public sealed class MenuViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MenuViewModel()
{
this.UserDisplayNm = Strings.UserDisplayName;
}
public string UserDisplayNm
{
set
{
if (Strings.UserDisplayName != value)
{
value = Strings.UserDisplayName;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("UserDisplayNm"));
}
}
}
get
{
return "Welcome, " + Strings.UserDisplayName;
}
}
}
}
EDIT:
Thanks for your replies. I think I'm getting closer based on the replies below, here is what I've now got, although The MenuViewModel.LoadAsync() is throwing an error "Inaccessible due to its protection level", so i can't compile to check it yet. Is this what you were suggesting & any ideas on the Protection level issue??
Strings file:
public static class Strings
{
public static string UserDisplayName;
}
ViewModel:
namespace Travel_Comp.ViewModels
{
public sealed class MenuViewModel : INotifyPropertyChanged
{
//Azure sync process
ServerManager manager;
public event PropertyChangedEventHandler PropertyChanged;
public MenuViewModel()
{
//Initial set of UserDisplayNm
this.UserDisplayNm = Strings.UserDisplayName;
}
async void LoadAsync()
{
try
{
//Run process to populate Strings.UserDisplayNm, set Syncitems to true to sync with Server
foreach (var user in await manager.GetUsersAsync(syncItems: true))
{
Strings.UserDisplayName = user.FirstName;
}
}
catch (Exception e)
{
Console.WriteLine($"Error while retrieving user name: {e}");
}
}
public string UserDisplayNm
{
set
{
if (Strings.UserDisplayName != value)
{
value = Strings.UserDisplayName;
if (PropertyChanged != null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UserDisplayNm)));
}
}
}
get
{
return "Welcome, " + Strings.UserDisplayName;
}
}
}
}
View:
protected override async void OnAppearing()
{
base.OnAppearing();
ViewModels.MenuViewModel.LoadAsync();
}
So if you're looking some guidance for MVVM, you should know that usually you put your dependencies in your view model constructor, here your Azure service.
Also you could use a existing MVVM framework that will make things easy for you, like Prism or FreshMVVM.
But if you want to go for full vanilla you can also call your vm code from the view code behind.
So I'm suggesting this modification to your MenuViewModel:
private IAzureService _azureService;
private string _userDisplayNm;
public MenuViewModel(IAzureService azureService)
{
_azureService = azureService;
}
public string UserDisplayNm
{
get
{
return _userDisplayNm;
}
set
{
if (_userDisplayNm != value)
{
_userDisplayNm = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(UserDisplayNm)));
}
}
}
public async void LoadAsync()
{
try
{
UserDisplayNm = await _azureService.GetUserName();
}
catch (Exception exception)
{
Debug.WriteLine($"Error while retrieving user name: {exception}")
}
}
Then in you view code behind:
void OnAppearing()
{
_menuViewModel.LoadAsync();
}
To resolve the question: Inaccessible due to its protection level, you can try to add the public access modifier before the function of LoadAsync.
public async void LoadAsync(){
//....
}
And I have created a simple demo to simulate your code.
The main code is:
public sealed class TestModel: INotifyPropertyChanged
{
//*******************************************
string _userDisplayName;
public string UserDisplayName {
set { SetProperty(ref _userDisplayName, value); }
get { return _userDisplayName; }
}
public async void LoadAsync()
{
try
{
UserDisplayName = "updated value: Angela";
Strings.UserDisplayName = UserDisplayName;
}
catch (Exception exception)
{
Debug.WriteLine($"Error while retrieving user name: {exception}");
}
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
xaml
<Label Text="{Binding UserDisplayName }" BackgroundColor="Yellow"
VerticalOptions="Center" HorizontalOptions="Fill" HeightRequest="50" />
<Button Text="update the Label value" Clicked="Button_Clicked"/>
And use like this:
public partial class MyPage1 : ContentPage
{
TestModel model;
public MyPage1 ()
{
InitializeComponent ();
model = new TestModel();
BindingContext = model;
}
private void Button_Clicked(object sender, EventArgs e)
{
model.LoadAsync();
}
}
The effect is:

Image edit and save Out of Memory Exception C#

I'm working in a WPF application where I show my images in two places which means the same image gets loaded in two places. In one of the place the image will be shown along with other few images in a slider where it will be able to edit and save. If there is no image available in the location I should be showing a separate image Image not found which is not editable.
When I started working on the functionality I got the Used by another process exception during edit and save. So after searching I came up with a solution and now at a rare time I get the Out of memory exception when I click the Next or Previous or First or Last in slider. The slider is just an Image control with 4 buttons. When the buttons are clicked the below method is called. I'm not sure if there is any memory leaks.
bool NoImage = true;
private static readonly object _syncRoot = new object();
private BitmapSource LoadImage(string path)
{
lock (_syncRoot) //lock the object so it doesn't get executed more than once at a time.
{
BitmapDecoder decoder = null;
try
{
//If the image is not found in the folder, then show the image not found.
if (!File.Exists(path) && (path != null))
{
System.Drawing.Bitmap ss = XXXX.Resources.ImageNotFound;
var stream = new System.IO.MemoryStream();
if (!File.Exists(Path.GetTempPath() + "ImageNotFound.jpg"))
{
FileStream file = new FileStream(Path.GetTempPath() + "ImageNotFound.jpg", FileMode.Create, FileAccess.Write);
ss.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
stream.WriteTo(file);
file.Close();
stream.Close();
}
path = Path.Combine(Path.GetTempPath(), "ImageNotFound.jpg");
NoImage = false;
}
else
{
if (!EnableForEdit)
NoImage = false;
else
NoImage = true;
}
if (!string.IsNullOrEmpty(path) && (!NoImage || File.Exists(path)))
{
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
return decoder.Frames.FirstOrDefault();
}
else
return null;
}
catch (OutOfMemoryException ex)
{
MessageBox.Show("Insufficient memory to handle the process. Please try again later.", "Application alert");
return null;
}
catch (Exception ex)
{
// Error handling.
throw new ApplicationException(ex.Message);
}
finally
{
decoder = null;
GC.WaitForFullGCComplete(1000);
GC.Collect(0, GCCollectionMode.Forced);
}
}
}
<Image x:Name="viewImage" Grid.Row="2" Height="100" Width="135" Source="{Binding DisplayImage, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" />
If my approach is wrong, let me know where should I do the change or if there is any simpler way to do. Kindly help.
Note: The images which are loaded is above 5Mb
Firstly when ever you create a stream you need to dispose of it once you are finished with it (Note Close does not Dispose, but Dispose does close), if not then the stream stays in memory consuming resources
so your code should look as follows
using(var stream = new System.IO.MemoryStream())
{
if (!File.Exists(Path.GetTempPath() + "ImageNotFound.jpg"))
{
using(FileStream file = new FileStream(Path.GetTempPath() + "ImageNotFound.jpg", FileMode.Create, FileAccess.Write))
{
ss.Save(stream, ImageFormat.Jpeg);
stream.Position = 0;
stream.WriteTo(file);
}
}
}
Second you need to reduce your apps memory impact
to do that i would suggest leveraging the functionality already in WPF here is a quick example of how you should do this
Your Model
public class ImageItem
{
public Uri URI{ get; set; }
private BitmapSource _Source;
public BitmapSource Source
{
get
{
try
{
if (_Source == null) _Source = new BitmapImage(URI);//lazy loading
}
catch (Exception)
{
_Source = null;
}
return _Source;
}
}
public void Save(string filename)
{
var img = BitmapFrame.Create(Source);
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(img);
using(var saveStream = System.IO.File.OpenWrite(filename))
encoder.Save(saveStream)
}
}
Your View Model
public class ImageList : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ImageItem> Images { get; } = new ObservableCollection<ImageItem>();
private int _SelectedIndex;
// c# >= 6
public static readonly PropertyChangedEventArgs SelectedIndexProperty = new PropertyChangedEventArgs(nameof(SelectedIndex));
// c# < 6
// public static readonly PropertyChangedEventArgs SelectedIndexProperty = new PropertyChangedEventArgs("SelectedIndex");
public int SelectedIndex
{
get { return _SelectedIndex; }
set
{
_SelectedIndex = value;
// c# >= 6
PropertyChanged?.Invoke(this, SelectedIndexProperty);
PropertyChanged?.Invoke(this, CurrentImageProperty);
// c# < 6
// var handler = PropertyChanged;
// if(handler !=null)
// {
// handler (this, SelectedIndexProperty);
// handler (this, CurrentImageProperty);
// }
}
}
// c# >= 6
public static readonly PropertyChangedEventArgs CurrentImageProperty = new PropertyChangedEventArgs(nameof(CurrentImage));
// c# < 6
// public static readonly PropertyChangedEventArgs CurrentImageProperty = new PropertyChangedEventArgs("CurrentImage");
public ImageItem CurrentImage => Images.Count>0 ? Images[SelectedIndex] : null;
public void Next()
{
if (SelectedIndex < Images.Count - 1)
SelectedIndex++;
else
SelectedIndex = 0;
}
public void Back()
{
if (SelectedIndex == 0)
SelectedIndex = Images.Count - 1;
else
SelectedIndex--;
}
public void Add(string Filename)
{
Images.Add(new ImageItem() { URI= new Uri(Filename) });
// c# >= 6
PropertyChanged?.Invoke(this, CurrentImageProperty);
// c# < 6
// var handler = PropertyChanged;
// if(handler !=null)
// {
// handler (this, CurrentImageProperty);
// }
}
}
and Finally your View
<Window x:Class="ImageDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ImageDemo"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BitmapImage x:Key="NotFound" UriSource="C:\...\NotFound.png"/>
</Window.Resources>
<Window.DataContext>
<local:ImageList/>
</Window.DataContext>
<DockPanel>
<Button Content="<" Click="Back_Click"/>
<Button DockPanel.Dock="Right" Content=">" Click="Next_Click"/>
<Image Source="{Binding CurrentImage.Source, Mode=OneWay,
TargetNullValue={StaticResource NotFound},
FallbackValue={StaticResource NotFound}}"/>
</DockPanel>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
//c# >= 6
private ImageList list => DataContext as ImageList;
//c# < 6
//private ImageList list {get{ return DataContext as ImageList;}}
private void Next_Click(object sender, RoutedEventArgs e)
{
list.Next();
}
private void Back_Click(object sender, RoutedEventArgs e)
{
list.Back();
}
}
note:
because the Model is separate to the View you can show the same image in several places with no issue at all
also System.Drawing.Bitmap is not WPF compatible so you should use the WPF classes in System.Windows.Media.Imaging

wpf UI not updating on data context change

I am developing and wpf app and in which I need to update data on basis of click on button. I tried to update in code behind but it did not work so I used datacontext but still no use. I saw various solutions and have used mode=TwoWay, UpdateSourceTrigger but it does not work.
<Grid DataContext="{Binding Dashboard, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
//Content
</Grid>
In cs file
public ViewModels.DashboardVM _DashVM = new ViewModels.DashboardVM();
async private void DashboardPage_Loaded(object sender, RoutedEventArgs e)
{
try
{
await _DashVM.GetDashboardData();
this.DataContext = _DashVM;
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex.Message);
}
}
and changing data context here
async private void StoresList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
var item = (sender as ListView).SelectedItem as Models.StoresLM;
if(item!=null)
{
Properties.Settings.Default.StoreId = item.id;
Properties.Settings.Default.Save();
await _DashVM.GetDashboardData();
this.DataContext = _DashVM;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex.Message);
}
}
my View Model is
public class DashboardVM : INotifyPropertyChanged
{
private Models.DashboardM _dashboard;
public Models.DashboardM Dashboard
{
get { return _dashboard; }
set { _dashboard = value; RaisePropertyChanged("Dashboard"); }
}
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public static event EventHandler<Boolean> IsLoading = delegate { };
async public Task<Boolean> GetDashboardData()
{
try
{
if (InternetTools.IsNetworkConnected())
{
IsLoading(this, true);
var storeId = Convert.ToString(Properties.Settings.Default.StoreId);
var Response = await new WebServiceUtility().PostRequest(string.Format(StringUtility.DashboardApi, Convert.ToString(Properties.Settings.Default.StoreId)), new[] { new KeyValuePair<string, string>("api_key", "dbjh") });
if (Response.IsSuccessStatusCode)
{
var DashboardData = await Response.Content.ReadAsStringAsync();
var jsonObject = Newtonsoft.Json.Linq.JObject.Parse(DashboardData);
if (Convert.ToString(jsonObject["success"]).IndexOf("True", StringComparison.OrdinalIgnoreCase) >= 0)
{
var DashObject = jsonObject.ToObject<Models.DashboardM>();
Properties.Settings.Default.Currency = DashObject.data.store.currency.StartsWith("&") ? System.Net.WebUtility.HtmlDecode(DashObject.data.store.currency) : System.Text.RegularExpressions.Regex.Unescape(DashObject.data.store.currency);
DashObject.data.store.currency = StringUtility.Currency;
Properties.Settings.Default.Save();
Dashboard = null;
Dashboard = DashObject;
}
}
}
else
NotificationUtility.ShowErrorMessage(NotificationUtility.MsgType.InternetError);
}
catch
{
}
IsLoading(this, false);
return true;
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
Can anybody help?
I was able to resolve the problem by editing the code. It was not getting notified due to reassigning of object. I don't know the reason but I just changed this code
async private void StoresList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
var item = (sender as ListView).SelectedItem as Models.StoresLM;
if(item!=null)
{
Properties.Settings.Default.StoreId = item.id;
Properties.Settings.Default.Save();
await _DashVM.GetDashboardData();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex.Message);
}
}
Hope it helps somebody like me.

Categories

Resources