I'm trying to use the MediaElement to play a video selected from the Gallery. The path to the Video is saved within the app then bound to the MediaElement Source.
<xct:MediaElement Source="{Binding VideoUri, Converter={StaticResource VideoSourceConverter}}"
AutoPlay="False"
ShowsPlaybackControls="True"
Aspect="AspectFit"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" />
I'm using a converter as described in the documentation:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return null;
if (string.IsNullOrWhiteSpace(value.ToString()))
return null;
if (value.ToString().StartsWith("http"))
return value;
return new Uri($"ms-appdata:///{value}");
}
https://learn.microsoft.com/en-gb/xamarin/community-toolkit/views/mediaelement#play-local-media
But am getting the error: Invalid UriParameter name: Source
The saved path on Android is:
"/storage/emulated/0/Android/data/[app identifier]/files/Movies/temp/[filename].mp4"
Haven't tested in iOS yet.
Any guidance will be much appreciated.
Thanks.
The Converter you used is used for the UWP. UWP could play media files that are located in the app's xxxx folder by prefixing the media file with ms-appdata:///xxxx/.
For mobile devices, when you use the CrossMedia to select the video, you could get the stream directly from the file.
I use a button to do the select operation and then use the INotifyPropertyChanged to update the binding. Here is the code for your reference.
Xaml:
<Button Clicked="Button_Clicked" Text="Select"/>
<xct:MediaElement Source="{Binding VideoUri}"
AutoPlay="False"
ShowsPlaybackControls="True"
Aspect="AspectFit"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" />
Code:
public partial class Page29 : ContentPage
{
Page29ViewModel viewModel = new Page29ViewModel();
public Page29()
{
InitializeComponent();
this.BindingContext = viewModel;
}
private async void Button_Clicked(object sender, EventArgs e)
{
string path = string.Empty;
MediaFile video = null;
if (CrossMedia.Current.IsPickVideoSupported)
{
video = await CrossMedia.Current.PickVideoAsync();
}
var fileName = "sample";
var newFile = Path.Combine(FileSystem.AppDataDirectory, fileName + ".mp4");
if (!File.Exists(newFile))
{
using (var inputStream = video.GetStream())
{
using (FileStream outputStream = File.Create(newFile))
{
await inputStream.CopyToAsync(outputStream);
}
}
}
viewModel.VideoUri = newFile;
}
}
public class Page29ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _videoUri;
public string VideoUri
{
get { return _videoUri; }
set { _videoUri = value; NotifyPropertyChanged(nameof(VideoUri)); }
}
public Page29ViewModel()
{
}
}
You dont need the converter just return the path to the mediaplayer control .
mediaFile = await this._mediaPicker.PickVideoAsync();
VideoUri = mediaFile.Path;
Related
Hey I'm new to Xamarin and I'm hoping you guys could help me. Since there isn't a default folder-picker in xamarin, I want to implement it myself. The problem is that UWP as well as Android throw me this exception:
System.UnauthorizedAccessException
HResult=0x80070005
Nachricht = Access to the path 'C:\Users\imtt\AppData\Local\Packages\3ef1aa30-7ffe-4ece-84c7-d2eaf1f8634b_wvdsmkc2tee92\LocalState\Test\199.jpg' is denied.
Quelle = System.IO.FileSystem
Stapelüberwachung:
bei System.IO.FileSystem.DeleteFile(String fullPath)
bei System.IO.File.Delete(String path)
bei MinimalReproducibleExample.ViewModel.DeleteFiles() in C:\Users\imtt\source\repos\MinimalReproducibleExample\MinimalReproducibleExample\MinimalReproducibleExample\ViewModel.cs: Zeile107
bei Xamarin.Forms.Command.<>c__DisplayClass4_0.<.ctor>b__0(Object o)
bei Xamarin.Forms.Command.Execute(Object parameter)
bei Xamarin.Forms.ButtonElement.ElementClicked(VisualElement visualElement, IButtonElement ButtonElementManager)
bei Xamarin.Forms.Button.SendClicked()
bei Xamarin.Forms.Platform.UWP.ButtonRenderer.OnButtonClick(Object sender, RoutedEventArgs e)
Here's the xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MinimalReproducibleExample.MainPage">
<StackLayout>
<Button Text="Add Image" Command="{Binding AddImage}"/>
<Button Text="Delete Images" Command="{Binding DeleteImages}"/>
<Image Source="{Binding CreatedImage}"/>
</StackLayout>
Here's the code-behind:
using Xamarin.Forms;
namespace MinimalReproducibleExample
{
public partial class MainPage : ContentPage
{
public MainPage()
{
BindingContext = new ViewModel();
InitializeComponent();
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace MinimalReproducibleExample
{
public class ViewModel : INotifyPropertyChanged
{
private ImageSource image;
private string fileFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Test");
public ICommand AddImage { get; }
public ICommand DeleteImages { get; }
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public ViewModel()
{
AddImage = new Command(ShowFilePicker);
DeleteImages = new Command(DeleteFiles);
}
public ImageSource CreatedImage
{
get => image;
set
{
image = value;
OnPropertyChanged();
}
}
public async void ShowFilePicker()
{
FilePickerFileType filePickerFileType = new FilePickerFileType(
new Dictionary<DevicePlatform, IEnumerable<string>> {
{ DevicePlatform.iOS, new [] { "jpeg", "png", "mp3", "mpeg4Movie", "plaintext", "utf8PlainText", "html" } },
{ DevicePlatform.Android, new [] { "image/jpeg", "image/png", "audio/mp3", "audio/mpeg", "video/mp4", "text/*", "text/html" } },
{ DevicePlatform.UWP, new []{ "*.jpg", "*.jpeg", "*.png", "*.mp3", "*.mp4", "*.txt", "*.html" } }
});
PickOptions pickOptions = new PickOptions
{
PickerTitle = "Wählen Sie eine oder mehrere Dateien aus",
FileTypes = filePickerFileType,
};
IEnumerable<FileResult> pickedFiles = await FilePicker.PickMultipleAsync(pickOptions);
List<FileResult> results = pickedFiles.ToList();
if (results != null && results.Count > 0)
{
foreach (FileResult fileResult in results)
{
using (Stream stream = await fileResult.OpenReadAsync())
{
DirectoryInfo directoryInfo = Directory.CreateDirectory(fileFolder);
string directoryPath = directoryInfo.FullName;
string filepath = Path.Combine(directoryPath, fileResult.FileName);
try
{
byte[] bArray = new byte[stream.Length];
using (FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate))
{
stream.Read(bArray, 0, (int)stream.Length);
int length = bArray.Length;
fs.Write(bArray, 0, length);
}
CreatedImage = ImageSource.FromFile(filepath);
}
catch (Exception exc)
{
}
}
}
}
}
public void DeleteFiles()
{
string[] filePaths = Directory.GetFiles(fileFolder);
foreach(string filePath in filePaths)
{
File.Delete(filePath);
}
}
}
}
I already gave my app the access to the filesytem via windows settings, also I gave the Android-part read and write access. I even gave the UWP-part "broadFileAccess" and even that didn't make the cut.
This intersects with another problem, where the UWP part can write files into a folder in "Environment.SpecialFolder.LocalApplicationData", but it isn't allowed to delete the files in this folder.
Does this have something to do with the sandboxes of UWP and Android?
App cannot further process disks / folder in Xamarin
I tested with you code, the problem is the file was using by image control when you delete it, if we disable CreatedImage = ImageSource.FromFile(filepath); this line. it will work as expect.
I need that image control to display the image
We suggest you render image with stream but not create source from file directly.
For example
CreatedImage = ImageSource.FromStream(() => stream);
Trying to use libvlcsharp.forms in xamarinForms project.
Need to play resource video files.
Installed libVLCsharp.Forms, VideoLan.LibVLC.Android, VideoLan.LibVLC.IOS
Copied an mp4 file to iosProject/Resources; marked as BundleResource.
Copied same file to androidProject/Resources/raw; marked as AndroidResource
iOS can play from internet
Anroid can play same online address as iOS
ios can play resource file
android can not play same resource file
Error > error with media file:////BigBuckBunny.mp4
Thought it did not like my mp4 file format or something like that.
downloaded the file which it could play from url.
tried that one instead.
same results.
Help !!!
While it(android) could play famous BigBuckBuny from url > http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4,
it can not play same video downloaded and copied to AndroidProject/Resource/raw
XAML part:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ParkinsonMobileApp.Pages.PhysicalActivitiesVideoDetail"
Padding="0"
Title="HomePage"
FlowDirection="LeftToRight"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.UseSafeArea="False"
NavigationPage.HasNavigationBar="False"
xmlns:customViews="clr-namespace:ParkinsonMobileApp.Views"
BackgroundColor="White"
xmlns:vlc="clr-namespace:LibVLCSharp.Forms.Shared;assembly=LibVLCSharp.Forms"
Appearing="ContentPage_OnAppearing"
Disappearing="ContentPage_Disappearing">
<AbsoluteLayout
Padding="0"
Margin="0"
HorizontalOptions="Fill"
VerticalOptions="Fill">
<Image
x:Name="imgViewBackground"
Source="viewBackgroundBlurred.png"
Aspect="AspectFill"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1" />
<vlc:MediaPlayerElement
x:Name="vlcPlayer"
MediaPlayer="{Binding MediaPlayer}"
LibVLC="{Binding LibVLC}"
EnableRendererDiscovery="True"
Padding="0"
Margin="0"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1" />
<customViews:CustomNavigationBar
HorizontalOptions="Fill"
VerticalOptions="Start"
Padding="0"
Margin="0"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
Theme="White"
ImgBackgroundIsVisible="False"
ButBackDisplayed="True"
ButsOnRightDisplayed="False"
TitleText="Egzersiz 001"
TitleIsDisplayed="True"
BackgroundColor="Transparent"
backClicked="CustomNavigationBar_backClicked" />
</AbsoluteLayout>
CodeBehind dataBinding:
void ContentPage_OnAppearing(object sender, System.EventArgs e)
{
base.OnAppearing();
//pageViewModel = new VieoDetailViewModel("file://android_asset/024_1.mp4");
//pageViewModel = new VieoDetailViewModel("024_1.mp4");
pageViewModel = new VieoDetailViewModel("BigBuckBunny.mp4");
BindingContext = pageViewModel;
//MessagingCenter.Send(this, "AllowLandscape");
}
DataBinding Model:
public class VieoDetailViewModel : ViewModelBase
{
/// <summary>
/// Initialize LibVLC and playback when page appears
/// </summary>
public VieoDetailViewModel(String filePath)
{
Core.Initialize();
LibVLC = new LibVLC();
var media = new Media(LibVLC,
//"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
filePath,
//FromType.FromLocation
FromType.FromPath
);
MediaPlayer = new MediaPlayer(media) { EnableHardwareDecoding = true };
//MediaPlayer = new MediaPlayer(media);
MediaPlayer.Play(media);
}
/// <summary>
/// Gets the <see cref="LibVLCSharp.Shared.LibVLC"/> instance.
/// </summary>
public LibVLC _LibVLC;
public LibVLC LibVLC
{
get
{
return _LibVLC;
}
set
{
_LibVLC = value;
OnPropertyChanged("LibVLC");
}
}
/// <summary>
/// Gets the <see cref="LibVLCSharp.Shared.MediaPlayer"/> instance.
/// </summary>
public MediaPlayer _MediaPlayer;
public MediaPlayer MediaPlayer
{
get
{
return _MediaPlayer;
}
set
{
_MediaPlayer = value;
OnPropertyChanged("MediaPlayer");
}
}
}
I have check the path of the MP4 stored in Assets folder of Resource. It always thrown the exception like below.
VLC is unable to open the MRL
You could put the mp4 file in Assets folder and then copy to the device to play.
LibVLCSharp.Platforms.Android.VideoView _videoView;
LibVLC _libVLC;
MediaPlayer _mediaPlayer;
private const string fileName = "BigBuckBunny.mp4";
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.layout1);
}
protected async override void OnResume()
{
base.OnResume();
Core.Initialize();
_libVLC = new LibVLC();
_mediaPlayer = new MediaPlayer(_libVLC)
{
EnableHardwareDecoding = true
};
//_videoView = new LibVLCSharp.Platforms.Android.VideoView(this) { MediaPlayer = _mediaPlayer };
_videoView = FindViewById<LibVLCSharp.Platforms.Android.VideoView>(Resource.Id.videoPlayer);
_videoView.MediaPlayer = _mediaPlayer;
// Android application default folder.
var dbFile = GetDefaultFolderPath();
// Check if the file already exists.
if (!File.Exists(dbFile))
{
using (FileStream writeStream = new FileStream(dbFile, FileMode.OpenOrCreate, FileAccess.Write))
{
// Assets is comming from the current context.
await Assets.Open(fileName).CopyToAsync(writeStream);
}
}
//AddContentView(_videoView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent));
var media = new Media(_libVLC, dbFile, FromType.FromPath);//"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
if (File.Exists(dbFile))
{
_videoView.MediaPlayer.Play(media);
}
}
private string GetDefaultFolderPath()
{
var appFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var dbFile = Path.Combine(appFolder, fileName);
return dbFile;
}
The Media constructor has an overload that takes a StreamMediaInput so you can add the video file to the main project as an embedded resource, read it into a Stream and create the StreamMediaInput from it. If you do it this way it will work for iOS as well so you only need the video files in the main project, remove them from Android and iOS.
using System.IO;
using System.Reflection;
...
Assembly assembly = Assembly.GetExecutingAssembly();
string assemblyName = assembly.GetName().Name;
Stream stream = assembly.GetManifestResourceStream(assemblyName + ".BigBuckBunny.mp4");
StreamMediaInput mediaStream = new StreamMediaInput(stream);
Media media = new Media(_libVLC, mediaStream, new string[] { });
MediaPlayer player = new MediaPlayer(media) { EnableHardwareDecoding = true };
player.Play();
This assumes the mp4 file is in the root of the main project. Also note that I haven't wrapped the Stream in a using() because you need to hang onto it until you're done with the video and dispose of it then, so you need to sort that out - you could create a class to handle that.
Hy, I'm working in a Xamarin PCL project with the platforms Android and UWP. As a feature the user should be able to open an pdf file.
For this I'm using Mozilla pdf.js. I have followed this link to get it done on Android and UWP.
https://developer.xamarin.com/recipes/cross-platform/xamarin-forms/controls/display-pdf/
Only for UWP I can't get it to function.
Here is my custom renderer for UWP
[assembly: ExportRenderer(typeof(PdfView),
typeof(PDF.UWP.Renderers.PdfViewRenderer))]
namespace PDF.UWP.Renderers
{
/// <summary>
/// The asset folder of the UWP app must contain the pdfjs folder and files.
/// </summary>
public class PdfViewRenderer: WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
PdfView pdfView = Element as PdfView;
string sFile = string.Format("ms-appx-web://{0}", WebUtility.UrlEncode(pdfView.Uri));
Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));
}
}
}
}
Here is my PdfView class.
public class PdfView: WebView
{
public static readonly BindableProperty DocumentInfoProperty =
BindableProperty.Create(propertyName: nameof(TheDocumentInfo), returnType: typeof(DocumentInfo),
declaringType: typeof(PdfView), defaultValue: default(DocumentInfo));
public DocumentInfo TheDocumentInfo
{
get { return (DocumentInfo)GetValue(DocumentInfoProperty); }
set { SetValue(DocumentInfoProperty, value); }
}
public string Uri { get { return TheDocumentInfo.LocalUrl; } }
public string FileName { get { return TheDocumentInfo.FileName; } }
}
The file location on uwp =
"ms-appx-web://C%3A%5CUsers%5CUser%5CAppData%5CLocal%5CPackages%5CPDFTEST.UWP_v4j5n0js0cwst%5CLocalState%5CPDFTest.pdf"
And this is correct.
But the error is:
Message: Unexpected server response (0) while retrieving PDF
"ms-appx-web://C:/Users/User/AppData/Local/Packages/PDFTest.UWP_v4j5n0js0cwst/LocalState/PDFTest.pdf/".
UPDATE
I have recreated the renderer to:
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
// TODO: testen
PdfView pdfView = Element as PdfView;
string sFile = string.Format("ms-appx-web://{0}/{1}", pdfView.Uri.Replace(pdfView.FileName, ""), WebUtility.UrlEncode(pdfView.FileName));
Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));
}
}
I don't know if this is the solution to my problem but this error is gone.
The error now is:
PDF.js v1.1.366 (build: 9e9df56)
Message: stream must have data
UPDATE (I don't know if u should add this in this question or if I should made another one).
My error is still
stream must have data
I know now why. Because I'm developing a UWP application and I want to access a file outside my instal folder. This location is
C:\Users\User\AppData\Local\Packages\PDFTest.UWP_v4j5n0js0cwst\LocalState\
Apperently I can't access files outside my instalation folder. This includes coping the file to my install folder and read it there.
UPDATE
I have 2 versions of pdf.js in my project. (1.1.366 and 1.9.426)
This is my code now
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
PdfView pdfView = Element as PdfView;
var uriString = "ms-appdata:///local/" + WebUtility.UrlEncode(pdfView.FileName);
Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", uriString));
}
}
When I try to open the file with Launcher.LaunchFileAsync and use the uriString it opens my browser and shows me the file.
In my application I get the following error's
(v1.1.366) Stream must have data.
(v1.9.426) Unexpected server response (0) while retrieving PDF "ms-appdata:///local/PDFTest.pdf".
I know that the pdf uri is correct and accessible but it still doesn't work.
(for v1.9.426 I have added in viewer.js
var HOSTED_VIEWER_ORIGINS = ['null', 'http://mozilla.github.io', 'https://mozilla.github.io', 'ms-appdata://', 'ms-appx-web://PDFTest.uwp'];)
link to the testproject
I know now why. Because I'm developing a UWP application and I want to access a file outside my instal folder. This location is
You have use ms-appx-web: uri scheme as your pdf file access path. Actually, your pdf path is C:\Users\User\AppData\Local\Packages\PDFTest.UWP_v4j5n0js0cwst\LocalState\ that stored in the app's local folder. So the file will not be accessed.
I have also tested with "ms-appdata:///local/" uri scheme to access the pdf file base on your project. Unfortunately, It can't be recognised by viewer.js.
And then, I tried to convert pdf file into Base64String then opening it by calling the openPdfAsBase64 JS function in the viewer.js.
private async Task<string> OpenAndConvert(string FileName)
{
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.GetFileAsync(FileName);
var filebuffer = await file.OpenAsync(FileAccessMode.Read);
var reader = new DataReader(filebuffer.GetInputStreamAt(0));
var bytes = new byte[filebuffer.Size];
await reader.LoadAsync((uint)filebuffer.Size);
reader.ReadBytes(bytes);
return Convert.ToBase64String(bytes);
}
Usage
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Source = new Uri("ms-appx-web:///Assets/pdfjs3/web/viewer.html");
Control.LoadCompleted += Control_LoadCompleted;
}
}
private async void Control_LoadCompleted(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
CustomWebView pdfView = Element as CustomWebView;
if (string.IsNullOrEmpty(pdfView?.Filename)) return;
var ret = await OpenAndConvert(pdfView?.Filename);
var obj = await Control.InvokeScriptAsync("openPdfAsBase64", new[] { ret });
}
You could use this viewer.js that was added openPdfAsBase64 method.
Got hints following: How to embed the PDFjs into your C# Project.
<ListView x:Name="PictureListView" HasUnevenRows="True" WidthRequest="320" HeightRequest="400" SeparatorColor="White">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Image Source="{Binding Path}" HeightRequest="80" WidthRequest="80" Aspect="AspectFill" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ObservableCollection<Image> Pictures = new ObservableCollection<Image>(new Image { Source = "file.png" });
PictureListView.ItemSource = Pictures;
private async void PictureListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
var photo = (Image)e.Item;
photo.Source = "file2.png";
}
i am trying to update an image in a listview using xamarin forms....i have the code listed above....but when the click fires, the new image ("file2.png") doesn't get repainted to the screen. Instead, i just an empty space for where the image would have been. How do i change an image out in a listview?
You are using ObservableCollection which will only update the list view when the collection is updated (add, move, remove). In your case, you are only updating the content of the item, so it will not reflect in the screen.
You should implement your code with proper data binding or MVVM. Read more about MVVM HERE.
If you do not want to implement the MVVM, you can use the following tricks.
private async void PictureListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
var photo = (Image)e.Item;
var newImage = new Image { Source = "file2.png" };
var index = Pictures.IndexOf(photo);
Pictures.Remove(photo);
Pictures.Insert(index, newImage);
}
You should implement INotifyPropertyChanged
Here a sample code
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace XamlSamples
{
class ClockViewModel : INotifyPropertyChanged
{
DateTime dateTime;
public event PropertyChangedEventHandler PropertyChanged;
public ClockViewModel()
{
this.DateTime = DateTime.Now;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
this.DateTime = DateTime.Now;
return true;
});
}
public DateTime DateTime
{
set
{
if (dateTime != value)
{
dateTime = value;
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs("DateTime"));
}
}
}
get
{
return dateTime;
}
}
}
}
Here some docs
data_bindings_to_mvvm
Im making an app for iOS and android that offers the ability to watch video's. Im currently working on the iOS implementation but each time I dismiss the viewcontroller holding an AVPlayer or MPPlayer the app throws 'System.InvalidOperationException: Sequence contains no matching element'. I have no idea why this happens. Ill share some example code.
Renderer
using AnimeViewer.iOS.CustomRenderers;
using AnimeViewer.Views.Partials;
using AVFoundation;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(VideoPlayer), typeof(VideoPlayerRenderer))]
namespace AnimeViewer.iOS.CustomRenderers
{
public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, UIView>
{
public VideoPlayer VideoPlayer { get; set; }
protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> e)
{
base.OnElementChanged(e);
if (e.NewElement == null) return;
VideoPlayer = e.NewElement;
SetNativeControl(new UIView {Frame = UIScreen.MainScreen.Bounds});
var player = new AVPlayer(new NSUrl(VideoPlayer.Source));
var playerLayer = new AVPlayerLayer
{
Player = player,
Frame = Control.Frame
};
Control.Layer.AddSublayer(playerLayer);
player.Play();
}
}
}
View
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:partials="clr-namespace:AnimeViewer.Views.Partials;assembly=AnimeViewer"
x:Class="AnimeViewer.Views.VideoPlayerPage">
<partials:VideoPlayer x:Name="Player"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" />
</ContentPage>
You don't need a custom renderer to call the video player, you can use a DependencyService:
public class VideoPLayer : IVideoPlayer
{
public void Play(string path)
{
var _player = new AVPlayer(NSUrl.FromFilename(path));
var _playerController = new AVPlayerViewController();
_playerController.Player = _player;
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
vc.PresentViewController(_playerController, true, null);
_playerController.View.Frame = vc.View.Frame;
}
}
To learn more about DependencyService you can access the following link: https://developer.xamarin.com/guides/xamarin-forms/dependency-service/