I am doing a project wherein I can change the filter of the image. I am using skiasharp to change the filter of the image. It is like that of CamScanner Application. But when I change the filter to grayscale first and then Lighten and then Sepia and then again back to grayscale I hit save I get Sepia's Image. I understand that the last data being generated is that of sepia's hence it is saving that data. But if I want to change more than 3 times it is not working. Please help me out. Here is my coding.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
BackgroundColor="Black"
x:Class="JC.EditPage">
<ContentPage.Content>
<StackLayout Padding="10,10,10,10" Orientation="Vertical">
<Image x:Name="imageView" HeightRequest="450"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand" IsVisible="True"/>
<StackLayout x:Name="canvasStackView" IsVisible="False">
<skia:SKCanvasView HeightRequest="450" PaintSurface="OnCanvasViewPaintSurface" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand"/>
</StackLayout>
<StackLayout x:Name="canvasLightenStackView" IsVisible="False">
<skia:SKCanvasView HeightRequest="450" PaintSurface="OnCanvasViewPaintSurfaceLighten" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand"/>
</StackLayout>
<StackLayout x:Name="canvasSepiaStackView" IsVisible="False">
<skia:SKCanvasView HeightRequest="450" PaintSurface="OnCanvasViewPaintSurfaceSepia" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand"/>
</StackLayout>
<ScrollView Orientation="Horizontal" HorizontalScrollBarVisibility="Never">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="EndAndExpand" x:Name="filterStack" IsVisible="True">
<StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White">
<Label Text="Original" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="Original_Tapped">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
<StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White" >
<Label Text="Grayscale" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="Grayscale_Tapped">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
<StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White">
<Label Text="Lighten" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="Lighten_Tapped">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
<StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White" >
<Label Text="Sepia" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="Speia_Tapped">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</StackLayout>
</ScrollView>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="EndAndExpand" BackgroundColor="White">
<Image Source="goback.png" HorizontalOptions="StartAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="goback_Tapped"/>
</Image.GestureRecognizers>
</Image>
<Image Source="tick.png" HorizontalOptions="EndAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Save_Tapped"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
and here is my XAML.CS file for that -
private async void Grayscale_Tapped(object sender, EventArgs e)
{
DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
adjust = false;
canvasEditStackView.IsVisible = false;
canvasSepiaStackView.IsVisible = false;
canvasLightenStackView.IsVisible = false;
imageView.IsVisible = false;
canvasStackView.IsVisible = true;
filterStack.IsVisible = true;
original = false;
byte[] tempArray = await StorageHelper.LoadImage(image, path);
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
using (Stream stream = new MemoryStream(tempArray))
{
if (stream != null)
{
libraryBitmap = SKBitmap.Decode(stream);
canvasView.InvalidateSurface();
}
}
DependencyService.Get<IProgressInterface>().DismissLoader();
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
Console.WriteLine("Hits");
DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
paint.ColorFilter =
SKColorFilter.CreateColorMatrix(new float[]
{
0.21f, 0.72f, 0.07f, 0, 0,
0.21f, 0.72f, 0.07f, 0, 0,
0.21f, 0.72f, 0.07f, 0, 0,
0, 0, 0, 1, 0
});
canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
DependencyService.Get<IProgressInterface>().DismissLoader();
}
var snap = surface.Snapshot();
SKData data = snap.Encode();
saveData = data;
}
private async void Lighten_Tapped(object sender, EventArgs e)
{
DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
adjust = false;
imageView.IsVisible = false;
canvasEditStackView.IsVisible = false;
canvasStackView.IsVisible = false;
canvasSepiaStackView.IsVisible = false;
canvasLightenStackView.IsVisible = true;
filterStack.IsVisible = true;
original = false;
byte[] tempArray = await StorageHelper.LoadImage(image, path);
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurfaceLighten;
using (Stream stream = new MemoryStream(tempArray))
{
if (stream != null)
{
libraryBitmap = SKBitmap.Decode(stream);
canvasView.InvalidateSurface();
}
}
DependencyService.Get<IProgressInterface>().DismissLoader();
}
void OnCanvasViewPaintSurfaceLighten(object sender, SKPaintSurfaceEventArgs args)
{
DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
paint.ColorFilter =
SKColorFilter.CreateColorMatrix(new float[]
{
0.75f, 0.25f, 0.25f, 0, 0,
0.25f, 0.75f, 0.25f, 0, 0,
0.25f, 0.25f, 0.75f, 0, 0,
0, 0, 0, 1, 0
});
canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
DependencyService.Get<IProgressInterface>().DismissLoader();
}
var snap = surface.Snapshot();
SKData data = snap.Encode();
saveData = data;
}
public async void Speia_Tapped(object sender, EventArgs e)
{
DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
adjust = false;
imageView.IsVisible = false;
canvasEditStackView.IsVisible = false;
canvasStackView.IsVisible = false;
canvasLightenStackView.IsVisible = false;
canvasSepiaStackView.IsVisible = true;
filterStack.IsVisible = true;
original = false;
byte[] tempArray = await StorageHelper.LoadImage(image, path);
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurfaceSepia;
using (Stream stream = new MemoryStream(tempArray))
{
if (stream != null)
{
libraryBitmap = SKBitmap.Decode(stream);
canvasView.InvalidateSurface();
}
}
DependencyService.Get<IProgressInterface>().DismissLoader();
}
void OnCanvasViewPaintSurfaceSepia(object sender, SKPaintSurfaceEventArgs args)
{
DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
paint.ColorFilter =
SKColorFilter.CreateColorMatrix(new float[]
{
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 0.8f, 0, 0,
0, 0, 0, 1, 0
});
canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
DependencyService.Get<IProgressInterface>().DismissLoader();
}
var snap = surface.Snapshot();
SKData data = snap.Encode();
saveData = data;
}
and this is my save command.
if (original == true)
{
var editPref = DependencyService.Get<IUserPreferences>();
editPref.SaveString("edit", "false");
await Navigation.PushModalAsync(new desiredLocationStoragePage(path));
}
else
{
var editPref = DependencyService.Get<IUserPreferences>();
editPref.SaveString("edit", "true");
string saveName = fileName;
using (var stream = File.OpenWrite(saveName))
{
saveData.SaveTo(stream);
}
await Navigation.PushModalAsync(new desiredLocationStoragePage(fileName));
}
please help me out guys I am quite stuck after this phase
I hope I got it right, you are using several SKCanvasViews and depending on what "mode" the user chooses in your app, you activate the corresponding surface?
I wouldn't recommend that. Even though it ~kinda~ works, it might become confusing very fast.
My approach to your problem would be to rewrite the view in the following way:
Create an enum containing the names of your filters and another entry for "none", e.g.
public enum Filters
{
None = 0,
Grayscale = 1,
Lighten = 2,
Sepia = 4
}
Then create a property of the type of this enum in your page.
Filters currentFilter = Filters.None;
Now instead of copying your render code 4 times, you could change the main PaintSurface method to something like:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
Console.WriteLine("Hits");
DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
// check if currentFilter is set to Filters.None
if( (currentFilter & Filters.None) == Filters.None )
{
paint.ColorFilter =
SKColorFilter.CreateColorMatrix(new float[]
{
0.21f, 0.72f, 0.07f, 0, 0,
0.21f, 0.72f, 0.07f, 0, 0,
0.21f, 0.72f, 0.07f, 0, 0,
0, 0, 0, 1, 0
});
}
// check if currentFilter is set to Filters.Lighten
else if ( (currentFilter & Filters.Lighten) == Filters.Lighten)
{
paint.ColorFilter =
SKColorFilter.CreateColorMatrix(new float[]
{
0.75f, 0.25f, 0.25f, 0, 0,
0.25f, 0.75f, 0.25f, 0, 0,
0.25f, 0.25f, 0.75f, 0, 0,
0, 0, 0, 1, 0
});
}
/*
... proceed with other filters accordingly ....
*/
canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
DependencyService.Get<IProgressInterface>().DismissLoader();
}
var snap = surface.Snapshot();
SKData data = snap.Encode();
saveData = data;
}
So when tapping your SetFilterButton all you need to do is setting the customFilter Property of your page to the corresponding filter and calling
canvasView.InvalidateSurface();
so the surface will be redrawn and then saving the image.
Related
I'm trying to upload images in Xamarin to Server via API.
.xaml
<Grid x:Name="pickimg" Grid.Row="0" Grid.Column="1" HorizontalOptions="End" VerticalOptions="Center">
<StackLayout Orientation="Horizontal">
<Image Margin="0">
<Image.Source>
<FontImageSource Color="#ddd" Size="22" FontFamily="MaterIcon" Glyph="{x:Static local:FontIconsClass.Camera}"/>
</Image.Source>
</Image>
</StackLayout>
<Grid.GestureRecognizers>
<TapGestureRecognizer Tapped="pickimg_Tapped" />
</Grid.GestureRecognizers>
</Grid>
<StackLayout HorizontalOptions="FillAndExpand">
<StackLayout x:Name="listImg" Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Frame HasShadow="False" Padding="0" IsClippedToBounds="True" CornerRadius="4">
<Image HeightRequest="70" WidthRequest="70" Aspect="AspectFill" Source="{Binding .}"/>
</Frame>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
.xaml.cs
This is how I display the list of selected photos:
async void pickimg_Tapped(System.Object sender, EventArgs e)
{
var pickResult = await MediaGallery.PickAsync(5, MediaFileType.Image);
if(pickResult?.Files == null)
{
return;
}
else
{
var imgList = new List<ImageSource>();
foreach (var img in pickResult?.Files)
{
var stream = await img.OpenReadAsync();
imgList.Add(ImageSource.FromStream(() => stream));
}
BindableLayout.SetItemsSource(listImg, imgList);
}
}
Everything seems fine. And I have 1 button to post the image to the Server:
private async void bt_addfeed_Clicked(object sender, EventArgs e)
{
var getResult = listImg;//How can I check and get the list of images in listImg?
if(getResult == null)
{
return;
}
else
{
var content = new MultipartFormDataContent();
content.Add(new StreamContent(await getResult.OpenReadAsync()), "file", getResult.FileName);
var httpClient = new HttpClient();
var response = await httpClient.PostAsync("", content);......
}
}
How can I check and get the list of images in listImg? Please solutions, Thanks
Update...
List<ImageSource> imgList = new List<ImageSource>();
async void pickimg_Tapped(System.Object sender, EventArgs e)
{
var pickResult = await MediaGallery.PickAsync(5, MediaFileType.Image);
if(pickResult?.Files == null)
{
return;
}
else
{
foreach (var img in pickResult?.Files)
{
var stream = await img.OpenReadAsync();
imgList.Add(ImageSource.FromStream(() => stream));
}
BindableLayout.SetItemsSource(listImg, imgList);
}
}
private async void bt_addfeed_Clicked(object sender, EventArgs e)
{
var getResult = imgList;
if(getResult == null)
{
return;
}
else
{
var content = new MultipartFormDataContent();
content.Add(new StreamContent(await getResult.OpenReadAsync()), "file", getResult.FileName);
var httpClient = new HttpClient();
var response = await httpClient.PostAsync("", content);......
}
}
How can getResult get .FileName and .OpenReadAsync()?
content.Add(new StreamContent(await getResult.OpenReadAsync()), "file", getResult.FileName);
you are declaring imgList as a local variable, so it only has scope inside the method where you declare it
var imgList = new List<ImageSource>();
instead, declare it as a class level variable so it will be accessible throughout the page
// do this inside the class body, but NOT within a specific method
List<ImageSource> imgList = new List<ImageSource>();
I got Exception of System.Windows.Markup.XamlParseException occurred in System.Windows.ni.dll,
System.ArgumentException occurred in mscorlib.ni.dll and wasn't handled before a managed/native boundary
my MainPage.xaml:
<Slider Name="timelineSlider" Margin="0,185,0,376" ValueChanged="SeekToMediaPosition"/>
<TextBlock Height="51" HorizontalAlignment="Left" Margin="27,334,0,0" x:Name="TitleTextBlock" Text="Title:" VerticalAlignment="Top" FontSize="28" Foreground="{StaticResource PhoneAccentBrush}" Width="400" />
<TextBlock Height="39" HorizontalAlignment="Left" Margin="27,383,0,0" x:Name="ArtistTextBlock" Text="Artist:" VerticalAlignment="Top" FontSize="24" FontStyle="Italic" Foreground="White" Width="400" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="37,559,0,0" x:Name="StartTextBlock" Text="00:00:00" VerticalAlignment="Top" Width="100" />
<TextBlock Height="30" HorizontalAlignment="Left" TextAlignment="Right" Margin="327,559,0,0" x:Name="EndTextBlock" Text="00:00:00" VerticalAlignment="Top" Width="88" />
<Slider HorizontalAlignment="Left" Margin="43,200,0,0" VerticalAlignment="Top" Width="395" Name="SongSlider" ManipulationCompleted="SoundSlider_ManipulationCompleted"/>
My MainPage.xaml.cs file is:
private void NotProvided()
{
if (BackgroundAudioPlayer.Instance.Track != null)
{
// show soung info
TitleTextBlock.Text = BackgroundAudioPlayer.Instance.Track.Title
ArtistTextBlock.Text = BackgroundAudioPlayer.Instance.Track.Artist;
// handle slider and texts
SongSlider.Minimum = 0;
SongSlider.Maximum = BackgroundAudioPlayer.Instance.Track.Duration.TotalMilliseconds;
string text = BackgroundAudioPlayer.Instance.Track.Duration.ToString();
EndTextBlock.Text = text.Substring(0, 8);
}
if (null != BackgroundAudioPlayer.Instance.Track)
{
txtCurrentTrack.Text = BackgroundAudioPlayer.Instance.Track.Title +
" by " +
BackgroundAudioPlayer.Instance.Track.Artist;
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
{
playButton.Content = "pause";
txtCurrentTrack.Text = BackgroundAudioPlayer.Instance.Track.Title +
" by " +
BackgroundAudioPlayer.Instance.Track.Artist;
}
else
{
playButton.Content = "play";
txtCurrentTrack.Text = "";
}
}
private DispatcherTimer dispatcherTimer = new DispatcherTimer();
private void startTimer()
{
// start timer to check position of the song
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
// song is playing
if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
{
// handle slider
SongSlider.Minimum = 0;
SongSlider.Value = BackgroundAudioPlayer.Instance.Position.TotalMilliseconds;
SongSlider.Maximum = BackgroundAudioPlayer.Instance.Track.Duration.TotalMilliseconds;
// display text
string text = BackgroundAudioPlayer.Instance.Position.ToString();
StartTextBlock.Text = text.Substring(0, 8);
text = BackgroundAudioPlayer.Instance.Track.Duration.ToString();
EndTextBlock.Text = text.Substring(0, 8);
}
}
private void SoundSlider_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
// get slider value
int sliderValue = (int)SongSlider.Value;
// create timespan object with milliseconds (from slider value)
TimeSpan timeSpan = new TimeSpan(0, 0, 0, 0, sliderValue);
// set a new position of the song
BackgroundAudioPlayer.Instance.Position = timeSpan;
}
private void PrevButton_Click(object sender, RoutedEventArgs e)
{
// skip to previous song
BackgroundAudioPlayer.Instance.SkipPrevious();
// handle text and slider
playButton.Content = "Pause";
SongSlider.Value = 0;
}
private void NextButton_Click(object sender, RoutedEventArgs e)
{
// skip to next song
BackgroundAudioPlayer.Instance.SkipNext();
// handle text and slider
playButton.Content = "Pause";
SongSlider.Value = 0;
}
How can I add many Button to the grid for the first Item and and textbox to another grid in the second item dynamically?
NOT XAML
Ican't find name GridItem - name not exist in code behind :(
I tried to find Visual Tree Helper :(
PivotItem pivotVHT = (PivotItem)mainSecondPivot.SelectedItem;
foreach (var element in VisualTreeHelper.FindElementsInHostCoordinates(new Rect(20, 0, 480, 700), pivotVHT))
{
if (element is TextBlock)
{
Debug.WriteLine("{0}", ((TextBlock)element).Text);
TextBlock test = ((TextBlock)element);
test.Text = "TEST";
}
}
VisualTreeHelper changing the text only mainFirstPivot, visual tree helper does not see mainSecondPivot
XAML:
<controls:Pivot Title="Photo Gallery" Name="mainSecondPivot" >
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<Grid
x:Name="PivitGrid"
>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Image
Name="PivotImageGalery"
Source="{Binding imgSrc}"
>
</Image>
<TextBlock
x:Name="TextBlockPivot"
Text="{Binding textBlockPivotName}"
>
</TextBlock>
</Grid>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<ScrollViewer
Name="SVName"
Width="Auto"
VerticalScrollBarVisibility ="Hidden"
HorizontalScrollBarVisibility="Disabled"
>
<Grid
x:Name="GridItem"
>
**HERE**
</Grid>
</ScrollViewer>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
C#
public static class SelectedIndex
{
public static int SelectedIndexInt = 0;// OR SOME NUMBER
}
public class IListPivot
{
public ImageSource imgSrc { get; set; }
public String textBlockPivotName { get; set; }
}
public secondPage()
{
InitializeComponent();
IList<IListPivot> PivotList = new List<IListPivot>();
for (z = 0; z <= 7; z++)
{
PivotList.Add(new IListPivot()
{
imgSrc = new System.Windows.Media.Imaging.BitmapImage(new Uri("URI", UriKind.Relative)),
textBlockPivotName = "TEXT"
});
}
mainSecondPivot.ItemsSource = PivotList;
mainSecondPivot.Loaded += new RoutedEventHandler (PivotLoaded);
mainSecondPivot.SelectedIndex = SelectedIndex.SelectedIndexInt
}
public void PivotLoaded(object sender, EventArgs e)
{
PivotItem pivotItemVHT = (PivotItem)mainSecondPivot.ItemContainerGenerator.ContainerFromIndex(SelectedIndex.SelectedIndexInt);
var root = VisualTreeHelper.GetChild(((VisualTreeHelper.GetChild(pivotItemVHT, 0) as Grid).Children[0] as ContentPresenter), 0) as FrameworkElement;
Debug.WriteLine(" root " + root);
Debug.WriteLine(" root Name " + root.Name);
ScrollViewer scr = (ScrollViewer)root;
TextBox BoxText1 = new TextBox();
BoxText1.Text = a.ToString();
scr.Content = BoxText1;
}
add only to one from everyone items
HELP
Here is how to retrieve a named element from inside a PivotItem:
public FrameworkElement GetPivotElement(int pivotIndex, string name)
{
var pivot = mainSecondPivot.ItemContainerGenerator.ContainerFromIndex(pivotIndex);
var root = VisualTreeHelper.GetChild(((VisualTreeHelper.GetChild(pivot, 0) as Grid).Children[0] as ContentPresenter), 0) as FrameworkElement;
return root.FindName(name);
}
I'm trying to display the movie dates for movies than are going to screen today. I have been reading different threads the whole day, buy I can´t get the webRequest to work.
Basically I had working code with webClient, but I wanted the UI to be responsive so I decided to use httpWebRequest to keep the xml parsing off the UI thread.
public partial class MainPage : PhoneApplicationPage {
public MainPage() {
InitializeComponent();
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) {
DoHttpWebRequest();
}
private void DoHttpWebRequest() {
string url = "http://www.cinamon.ee/rss/schedule/1001.xml";
var request = HttpWebRequest.Create(url);
var result = (IAsyncResult)request.BeginGetResponse(ResponseCallback, request);
}
private void ResponseCallback(IAsyncResult result) {
var request = (HttpWebRequest)result.AsyncState;
var response = request.EndGetResponse(result);
using (var stream = response.GetResponseStream()) {
XDocument scheduleXml = XDocument.Load(stream);
var todayMovies = from query in scheduleXml.Descendants("schedule").Descendants("shows").Descendants("show")
where DateTime.Parse(query.Element("showDateTime").Value).Date.Equals(DateTime.Now.Date) &&
DateTime.Parse(query.Element("showDateTime").Value).TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0
select new Movie() {
MoviePicture = new BitmapImage(new Uri((string)query.Element("images").Element("imageType2").Value, UriKind.RelativeOrAbsolute)),
MovieName = (string)query.Element("title"),
MovieId = (string)query.Element("movieId"),
MovieSoonest = DateTime.Parse(query.Element("showDateTime").Value).ToString("H:mm")
};
// Removing duplicate movies from list.
List<Movie> todayList = todayMovies.ToList();
IEnumerable<Movie> noDuplicates3 = todayList.Distinct(new MovieComparer());
// Adding to the UI
Dispatcher.BeginInvoke(() => {
todayBox.ItemsSource = noDuplicates.ToList();
});
}
}
}
Does anyone have an idea as to what is wrong by looking at this code?
Thank you in advance
EDIT. This is the link I based my solution on - http://social.msdn.microsoft.com/Forums/en-US/windowsphone7series/thread/594e1422-3b69-4cd2-a09b-fb500d5eb1d8
EDIT2. My Mainpage.xaml
<StackPanel x:Name="TodayPanel" Grid.Row="1" Margin="10,5,10,10" Orientation="Horizontal" Height="580" Background="#90000000" >
<ListBox x:Name="todayBox">
<ListBox.ItemTemplate>
<DataTemplate>
<HyperlinkButton x:Name="hyperLinkButton" Style="{StaticResource HyperlinkButtonStyle1}" CommandParameter="{Binding MovieId}" Tap="hyperLinkButton_Tap">
<HyperlinkButton.Content>
<StackPanel Margin="10" Grid.Row="1" Orientation="Horizontal">
<Image Source="{Binding MoviePicture}" />
<StackPanel Margin="10" Grid.Row="1" Orientation="Vertical">
<TextBlock TextWrapping="Wrap" Margin="10, 5, 10, 5" Width="200" FontFamily="Trebuchet MS" Foreground="Orange" VerticalAlignment="Top">
<Run Text="{Binding MovieName}"/>
<LineBreak></LineBreak>
</TextBlock>
<TextBlock TextWrapping="Wrap" Width="200" FontFamily="Trebuchet MS" Foreground="White" VerticalAlignment="Bottom">
<Run Text="Järgmine seanss: "/>
<LineBreak></LineBreak>
<Run Text="{Binding MovieSoonest}"/>
</TextBlock>
</StackPanel>
</StackPanel>
</HyperlinkButton.Content>
</HyperlinkButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
And my edited code behind.
private void DoHttpWebRequest() {
string url = "http://www.cinamon.ee/rss/schedule/1001.xml";
var request = HttpWebRequest.Create(url);
var result = (IAsyncResult)request.BeginGetResponse(ResponseCallback, request);
}
private void ResponseCallback(IAsyncResult result) {
var request = (HttpWebRequest)result.AsyncState;
var response = request.EndGetResponse(result);
// Adding to the UI
Dispatcher.BeginInvoke(() => {
IEnumerable<Movie> todayMovies;
using (var stream = response.GetResponseStream()) {
XDocument scheduleXml = XDocument.Load(stream);
todayMovies = from query in scheduleXml.Descendants("schedule").Descendants("shows").Descendants("show")
where DateTime.Parse(query.Element("showDateTime").Value).Date.Equals(DateTime.Now.Date) &&
DateTime.Parse(query.Element("showDateTime").Value).TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0
select new Movie() {
MoviePicture = new BitmapImage(new Uri((string)query.Element("images").Element("imageType2").Value, UriKind.RelativeOrAbsolute)),
MovieName = (string)query.Element("title"),
MovieId = (string)query.Element("movieId"),
MovieSoonest = DateTime.Parse(query.Element("showDateTime").Value).ToString("H:mm")
};
}
var todayList = todayMovies.ToList();
//IEnumerable<Movie> noDuplicates = movieList.Distinct(new MovieComparer());
todayBox.ItemsSource = todayList.ToList();
});
I tried out your code and getting UnauthorizedAccessException. By changing Dispactcher.Begininvoke delegate's scope it works as follow:
private void ResponseCallback(IAsyncResult result){
var request = (HttpWebRequest) result.AsyncState;
var response = request.EndGetResponse(result);
// Adding to the UI
Dispatcher.BeginInvoke(() =>
{
IEnumerable<Movie> todayMovies;
using (var stream = response.GetResponseStream())
{
XDocument scheduleXml = XDocument.Load(stream);
todayMovies =
from query in scheduleXml.Descendants("schedule").Descendants("shows").Descendants("show")
where DateTime.Parse(query.Element("showDateTime").Value).Date.Equals(DateTime.Now.Date) &&
DateTime.Parse(query.Element("showDateTime").Value).TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) >
0
select new Movie()
{
MoviePicture =
new BitmapImage(
new Uri((string) query.Element("images").Element("imageType2").Value,
UriKind.RelativeOrAbsolute)),
MovieName = (string) query.Element("title"),
MovieId = (string) query.Element("movieId"),
MovieSoonest = DateTime.Parse(query.Element("showDateTime").Value).ToString("H:mm")
};
}
// Removing duplicate movies from list.
var todayList = todayMovies.ToList();
//IEnumerable<Movie> noDuplicates3 = todayList.Distinct(new MovieComparer());
todayBox.ItemsSource = todayList.ToList();
});
}
However you may use RestSharp library (you may find it in Nuget) in order to make it easier. Check following code:
public void RestSample(){
var client = new RestClient
{
BaseUrl = "http://www.cinamon.ee/"
};
var request = new RestRequest
{
Resource = "rss/schedule/1001.xml"
};
client.ExecuteAsync(request, (a) =>
{
if (a.StatusCode == HttpStatusCode.OK)
{
var scheduleXml = XDocument.Parse(a.Content);
var todayMovies = from query in scheduleXml.Descendants("schedule").Descendants("shows").Descendants("show")
where DateTime.Parse(query.Element("showDateTime").Value).Date.Equals(DateTime.Now.Date) &&
DateTime.Parse(query.Element("showDateTime").Value).TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0
select new Movie()
{
MoviePicture = new BitmapImage(new Uri((string)query.Element("images").Element("imageType2").Value, UriKind.RelativeOrAbsolute)),
MovieName = (string)query.Element("title"),
MovieId = (string)query.Element("movieId"),
MovieSoonest = DateTime.Parse(query.Element("showDateTime").Value).ToString("H:mm")
};
// Removing duplicate movies from list.
List<Movie> todayList = todayMovies.ToList();
//IEnumerable<Movie> noDuplicates = todayList.Distinct(new MovieComparer());
// Adding to the UI
Dispatcher.BeginInvoke(() =>
{
todayBox.ItemsSource = todayList.ToList();
});
}
else
{
//error
}
});
}
Try it out and let us know...
EDITED: xaml.cs datatemplate:
<StackPanel x:Name="TodayPanel" Grid.Row="1" Margin="10,5,0,10" Orientation="Horizontal" Height="580" Background="#90000000" >
<ListBox x:Name="todayBox" Width="468">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10" Orientation="Horizontal">
<Image Source="{Binding MoviePicture, FallbackValue=http://www.cinamon.ee/visinternetticketing/images/movies/NowShowingComingSoon/HungerGames.jpg}" />
<StackPanel Margin="10" Grid.Row="1" Orientation="Vertical">
<TextBlock TextWrapping="Wrap" Margin="10, 5, 10, 5" FontFamily="Trebuchet MS" Foreground="Orange" VerticalAlignment="Top" Text="{Binding MovieName}"/>
<TextBlock TextWrapping="Wrap" FontFamily="Trebuchet MS" Foreground="White" VerticalAlignment="Bottom" Text="{Binding MovieSoonest}"/>
</StackPanel>
<HyperlinkButton x:Name="hyperLinkButton" CommandParameter="{Binding MovieId}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
RECALL Change MovePicture Property from BitmapImage to string.
<ListBox Name="listBoxButtons"
Height="700">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Background="{StaticResource PhoneAccentBrush}"
Name="border"
Width="432" Height="62"
Margin="6" Padding="12,0,0,6">
<TextBlock Text="{Binding}"
Foreground="#FFFFFF" FontSize="26.667"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
FontFamily="{StaticResource PhoneFontFamilySemiBold}"/>
<Border.Projection>
<PlaneProjection RotationX="-60"/>
</Border.Projection>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code:
private void ShowAnim()
{
IEasingFunction quadraticEase = new QuadraticEase { EasingMode = EasingMode.EaseOut };
Storyboard _swivelShow = new Storyboard();
foreach (var item in this.listBoxButtons.Items)
{
UIElement container = listBoxButtons.ItemContainerGenerator.ContainerFromItem(item) as UIElement;
if (container != null)
{
Border content = VisualTreeHelper.GetChild(container, 0) as Border;
if (content != null)
{
DoubleAnimationUsingKeyFrames showAnimation = new DoubleAnimationUsingKeyFrames();
EasingDoubleKeyFrame showKeyFrame1 = new EasingDoubleKeyFrame();
showKeyFrame1.KeyTime = TimeSpan.FromMilliseconds(0);
showKeyFrame1.Value = -60;
showKeyFrame1.EasingFunction = quadraticEase;
EasingDoubleKeyFrame showKeyFrame2 = new EasingDoubleKeyFrame();
showKeyFrame2.KeyTime = TimeSpan.FromMilliseconds(85);
showKeyFrame2.Value = 0;
showKeyFrame2.EasingFunction = quadraticEase;
showAnimation.KeyFrames.Add(showKeyFrame1);
showAnimation.KeyFrames.Add(showKeyFrame2);
Storyboard.SetTargetProperty(showAnimation, new PropertyPath(PlaneProjection.RotationXProperty));
Storyboard.SetTarget(showAnimation, content.Projection);
_swivelShow.Children.Add(showAnimation);
}
}
}
_swivelShow.Begin();
}
But: Storyboard.SetTarget(showAnimation, content.Projection) throws an Exception. The content.Projection is null. How could that happen?
You are looking at the wrong Border element. The hierarchy of the item container in your case is like Border -> ContentControl -> ContentPresenter -> Border (this is yours). So you have to go deeper down the child hierarchy of your container to find the border you want.
The following code searches the children of an UIElement recursively and gives some debug output so you can see how deep it goes. It will stop when it finds a control named "border":
private UIElement GetMyBorder(UIElement container)
{
if (container is FrameworkElement && ((FrameworkElement)container).Name == "border")
return container;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(container); i++)
{
var child = (FrameworkElement)VisualTreeHelper.GetChild(container, i);
System.Diagnostics.Debug.WriteLine("Found child "+ child.ToString());
System.Diagnostics.Debug.WriteLine("Going one level deeper...");
UIElement foundElement = GetMyBorder(child);
if (foundElement != null)
return foundElement;
}
return null;
}
To use it:
Border content = (Border)GetMyBorder(container);