pass data from viewmodel to code behind windows phone - viewmodel

I was trying to use the MVVM pattern on my first (very simple) WP7 app but I got seriously stuck and now I am just trying to get it working without caring about MVVM.
I have a MainViewModel for my MainPage, which works fine. I have a button that passes some data and navigates to a "details page." I had setup a navigation service to navigate to the details page and pass parameters, which works fine. I just couldn't get the databinding to the view working. Since it is a simple app, I decided I would pass the data from the DetailsPageVieModel.cs to the DetailsPage.xaml.cs code behind and do the work there. Here is what that veiw model portion looks like.
public override void Initialize(IDictionary<string, string> parameters)
{
DetailsPage dp = new DetailsPage();
//DetailsPage dp = Application.Current.RootVisual as DetailsPage;
base.Initialize(parameters);
parameters.TryGetValue("url", out vidUrl);
dp.LoadVideoData(vidUrl);
}
In my DetailsPage.xaml.cs I have the following:
public void LoadVideoData(string url)
{
HtmlWeb doc = new HtmlWeb();
doc.LoadAsync("http://mydomain.com/video.php?url=" + url);
doc.LoadCompleted += doc_LoadCompleted;
}
private void doc_LoadCompleted(object sender, HtmlDocumentLoadCompleted e)
{
this.vidTitle.Text = e.Document.GetElementbyId("title").InnerText;
vidId = e.Document.GetElementbyId("youtubeId").InnerText;
this.vidUrl.Source = new Uri("http://mydomain.com/video.php?url=" + vidUrl, UriKind.Absolute);
BitmapImage bi = new BitmapImage();
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("temp.jpg", FileMode.Open, FileAccess.Read))
{
bi.SetSource(fileStream);
this.vidImg.Height = bi.PixelHeight;
this.vidImg.Width = bi.PixelWidth;
}
}
this.vidImg.Source = bi;
}
And here is the relevant DetailsPage.xaml code
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<TextBlock x:Name="vidTitle" Canvas.ZIndex="99" />
<TextBlock Canvas.ZIndex="99" Text="Tap on the image to view the video." FontSize="14" Margin="0"/>
<Button Margin="0 -50" Padding="0" BorderThickness="0">
<Image x:Name="vidImg" Height="225" />
</Button>
<StackPanel Canvas.ZIndex="99" Height="516">
<phone:WebBrowser x:Name="vidUrl" IsScriptEnabled="True" Height="516" Margin="0"/>
</StackPanel>
</StackPanel>
</Grid>
I am guessing the problem lies with the following
DetailsPage dp = new DetailsPage();
//DetailsPage dp = Application.Current.RootVisual as DetailsPage;
Neither of these lines of code works. The first line executes properly but the page doesn't get updated with the proper data. And the second line gives me a runtime error message when it gets to the dp.LoadVideoData(vidUrl); line.
This is my first Windows Phone app and I would appreciate any help anyone can provide.
Kamal

After digging around some more, I found the following solution.
DetailsPage currentPage = (App.Current as App).RootFrame.Content as DetailsPage;
I put this code in DetailsPageViewModel.cs. But for other newbies like me, there is nothing special about the name of the file. It could have very well been Monkey.cs. The above code just gives you access to the code behind of the current page being displayed.

Related

Best way to retrieve multiple images from .net Web API and populate in Xamarin Form

This is the code I am using to fetch single image. This code runs in loop to populate the image and is working. But sometimes if there is a delay in fetching the image. The application gets stuck in populating data
var resp = await Client.GetAsync(imageUrl);
if (resp.IsSuccessStatusCode)
{
imageData = await resp.Content.ReadAsByteArrayAsync();
}
This is the loop which is calling the download of individual products images:
List<Task> tasks = new List<Task>();
foreach (var product in productsList)
{
var task = DownloadImage(eImageType.Brand, product);
tasks.Add(task);
}
code to build the image object dynamically
foreach(var brand in brands)
{
brand.ImageSource = ImageSource.FromStream(() =>
{
if (brand.ImageData != null)
return new MemoryStream(brand.ImageData);
else
return null;
});
}
Code to show image view in XAMLS
<AbsoluteLayout>
<ffimage:CachedImage Source="blugegb" HorizontalOptions="Fill"
DownsampleWidth="180"
DownsampleUseDipUnits="True"
AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"
VerticalOptions="Fill"
Aspect="AspectFill"/>
<ffimage:CachedImage Source="{Binding ImageSource}" HorizontalOptions="Fill"
DownsampleWidth="100"
DownsampleUseDipUnits="True"
AbsoluteLayout.LayoutBounds=".5,.5,.8,.8" AbsoluteLayout.LayoutFlags="All"
VerticalOptions="Fill"
Aspect="AspectFit"/>
</AbsoluteLayout>
In my opinion the best way is to return the Files as URLs and not as a stream.
Example:
Upload your images to let's say azure blob storage
Create a table with the information about the files (or save metadata with the file)
In your .NET web api build and action that queries all your files.
Make sure that the query returns a JSON that has a result at least like this:
{ name: 'test', url: 'http://yourpathtoyourimage.com/test.png' }
In your Xamarin Application use a plugin or custom logic to show the images by using their URL:
<Image Height="100" Width="100" Margin="12,0,9,0">
<Image.Source>
<BitmapImage UriSource="{Binding Url}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
if you are using FFImageLoading then its very simple all you have to do is :
<ffimage:CachedImage Source="{Binding ImageSource}" HorizontalOptions="Fill"
DownsampleWidth="100"
DownsampleUseDipUnits="True"
AbsoluteLayout.LayoutBounds=".5,.5,.8,.8" AbsoluteLayout.LayoutFlags="All"
VerticalOptions="Fill"
Aspect="AspectFit"/>
Provide a binding to CachedImage in its source, then directly pass the URL as the binding to the source eg:
public string ImageSource {get; set;}
//SomeWhere in your code
ImageSource="https://images.pexels.com/photos/807598/pexels-photo-807598.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940/abcd.jpg";

ListBox with multiple captured images windows phone

Does anyone know how to make a listbox with multiple images. I want to be able to capture an image and then display on the screen, then capture another and display after the first one and so on. It is basically images gallery page that I want to create. I would like to store them somewhere on the phone, so they can be retrieved when the application runs again.
So it should be something like in the picture: http://blog.xamarin.com/wp-content/uploads/2012/02/wp2.png
Thank you in advance, I have been doing researches about it but can't find anything.
Well, that is fairly easy. You use a ListBox set the ItemsPanel to a WrapPanel, and either bind ItemsSource to a ObservableCollection (or List/Array, but ObservableCollection is better suited for Bindings).
There are multible ways to do it
Lets take the easiest approach. In xaml you define your ListBox:
<ListBox x:Name="listbox">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="5"
Background="{StaticResource PhoneChromeBrush}"
Height="180"
Width="180">
<Image Source="{Binding}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In your code behind, you can load the images with something like this:
ObservableCollection<BitmapImage> images = new ObservableCollection<BitmapImage>();
List<String> bitmapuris = ....
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
foreach(var bitmapuri in bitmapuris)
{
System.Windows.Media.Imaging.BitmapImage bitmap = new System.Windows.Media.Imaging.BitmapImage();
if (isoStore.FileExists(bitmapuri))
{
using (IsolatedStorageFileStream stream = isoStore.OpenFile(bitmapuri, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
bitmap.CreateOptions = System.Windows.Media.Imaging.BitmapCreateOptions.BackgroundCreation;
bitmap.SetSource(stream);
}
}
images.Add(bitmap);
}
}
listbox.ItemsSource = images;
With bitmapuris being a List with all of your saved images urls.
Thats basicly what I'm using in some of my apps (though I use ViewModels and Bindings and don't set ItemsSource manually)
Hope this helps
edit:
On how to capture and save images you can read this article:
http://www.c-sharpcorner.com/UploadFile/mahakgupta/capture-save-and-edit-image-in-windows-phone-7/
I would save the Images in a specific folder i.e. "/Images/". That way you can load all images you previously captured on you app start with the code I posted above with List<String> bitmapuris set with this method:
List<String> getFiles(String folderpath)
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
return storage.GetFileNames(folderpath).ToList();
}
like this List<String> bitmapuris = getFiles("/Images/*");
and when you captured an image you can simple add your image to your ListBox this way:
System.Windows.Media.Imaging.BitmapImage bitmap = new System.Windows.Media.Imaging.BitmapImage();
bitmap.CreateOptions = System.Windows.Media.Imaging.BitmapCreateOptions.BackgroundCreation;
bitmap.SetSource(myimagestream);
images.Add(bitmap);
providing images is the ObservableCollection<BitmapImage> you set as an ItemsSource to your ListBox.
This is now almost your fully working app, when compined with the link from above.

Loading image from projects files

I'm trying to get png image which is my Resource folder. I tested solution that was written here :Add images to ListBox (c#, windows phone 7). For start I wanted to get the same image for every item in my ListBox. But I can't achive that. The picture doesn't show.
It's how my list in xaml look like:
<ListBox x:Name="ProductList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<Image Source="{Binding ImagePath}" Stretch="None"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is how I populate Items:
List<ImageData1> productsList = new List<ImageData1>();
foreach (ProductItem item in ProductsTable)
{
if (item.Category == chosenCategory.TrId)
{
ImageData1 img = new ImageData1();
img.Name = item.Name;
img.ImagePath = new Uri("Resources/img.png", UriKind.RelativeOrAbsolute);
productsList.Add(img);
}
}
ProductList.ItemsSource = productsList;
Here is my class to hold image data:
public class ImageData1
{
public Uri ImagePath
{
get;
set;
}
public string Name
{
get;
set;
}
}
Try putting / before your image path. Like /Resources/img.png. And try to change UriKind.RelativeOrAbsolute to UriKind.Relative. And make sure your images are added as Content (Build Action property of image). That way it works for me.
Probably, You can also use the following assembled code to read the image from the current application.
StreamResourceInfo info =Application.GetResourceStream(new Uri("Resources/img.png", UriKind.RelativeOrAbsolute));
var bitmap = new BitmapImage();
bitmap.SetSource(info.Stream);
img.Soure = bitmap;

Reading from local file WP7

I am trying to read a text file that I have included with the project folder itself in a separate folder. I am trying to read this text file and then add each line to a list, each line as a separate item in the list, then I am looking to bind it to a listbox and each listbox item (each line previously) would be a hyperlink in the listbox. It's been very frustrating since the app just freezes every single time as soon as the code starts executing at runtime. What could be the problem?
I tried searching here a lot. I tried several of the similar problems' solutions but no use.
Code:
public partial class Page2 : PhoneApplicationPage
{
public Page2()
{
InitializeComponent();
// Will contain the names of malls added through a text file
List<string> Mall_List = new List<string>();
using(StreamReader reader = new StreamReader("/Mall_List/Mall_List.txt"))
{
while(reader.Peek() >= 0)
{
Mall_List.Add(reader.ReadLine());
}
reader.Close();
}
Malllist.ItemsSource = Mall_List;
}
}
XAML:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Height="426" HorizontalAlignment="Left" Margin="6,6,0,0" Name="Malllist" VerticalAlignment="Top" Width="444">
<ListBox.ItemTemplate>
<DataTemplate>
<HyperlinkButton Name="MallNameLinkButton"
Content="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
Instead of just reading from "local file",
using(StreamReader reader = new StreamReader("/Mall_List/Mall_List.txt"))
you should know WP7 has Isolated Storage, for every app.
Please make sure you are familiar with it by reading following article:
http://www.windowsphonegeek.com/tips/all-about-wp7-isolated-storage--intro-to-isolated-storage
More precisely, reading files is described in following article:
http://www.windowsphonegeek.com/tips/all-about-wp7-isolated-storage-read-and-save-text-files

Windows Phone 7 Back button and application Tombstone?

In my application i had done this to map my uri in app.xaml.cs, now the thing is if my application deactivates my application exits on MainPage.xaml rather than Eula.xaml. Else the app exits on the same page on which it starts.
In App.xaml
<UriMapper:UriMapper x:Name="mapper">
<UriMapper:UriMapping Uri="/MainPageOrEULA.xaml"/>
</UriMapper:UriMapper>
and in App.xaml.cs
// Get the UriMapper from the app.xaml resources, and assign it to the root frame
UriMapper mapper = Resources["mapper"] as UriMapper;
RootFrame.UriMapper = mapper;
// Update the mapper as appropriate
IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication();
if (isoStorage.FileExists("DataBase/MyPhoneNumber.txt"))
{
mapper.UriMappings[0].MappedUri = new Uri("/MainPage.xaml", UriKind.Relative);
}
else
{
mapper.UriMappings[0].MappedUri = new Uri("/EULA.xaml", UriKind.Relative);
}
Please guide me for the same.
Regards,
Panache.
I suggest that rather than having a whole separate page (which interrupts navigation as you've noticed), just put a grid or usercontrol containing the EULA on the front page that isn't visible. When the user first opens the page, you show the grid/usercontrol, but on subsequent runs, you don't.
<Grid x:Name="LayoutRoot">
<Grid Name="EULA" Visibility="Collapsed" >
<TextBlock Text = "You agree ...." />
<Button Grid.Row="1" Content="I Agree" Click="AgreeClick" />
</Grid>
<Grid Name="MainGrid" >
....
Then in your code behind you can add your test to the loaded event
private void MainPageLoaded()
{
IsolatedStorageFile isoStorage = IsolatedStorageFile.GetUserStoreForApplication();
if (!isoStorage.FileExists("DataBase/MyPhoneNumber.txt"))
{
EULA.Visibility = Visibility.Visible;
MainGrid.Visibility = Visibility.Collapsed;
}
}
Then when the "I agree" button is clicked you can store the file and show the main grid
private void AgreeClick(....)
{
// Create isolated storage file
....
// Hide eula control
EULA.Visibility = Visibility.Collapsed;
MainGrid.Visibility = Visibility.Visible;
}

Resources