I have in my XAML the Image tag and in source a Binding SelectedImage. In the ViewModel I want to have the logic to add the image, but with my current code it does not insert the photo. Enter the gallery but when choosing the image do not show it.
This is my actual code:
MainPage.xaml:
<Image HeightRequest="50"
Source="{Binding SelectedImage}"
WidthRequest="50" />
ViewModel.cs:
string selectedimage;
public string SelectedImage
{
get => selectedimage; set
{
selectedimage = value;
OnPropertyChanged();
}
}
async void insertImage()
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsPickPhotoSupported)
{
return;
}
var mediaOptions = new PickMediaOptions()
{
PhotoSize = PhotoSize.Medium
};
var selectedImageFile = await CrossMedia.Current.PickPhotoAsync(mediaOptions);
if (SelectedImage == null)
{
return;
}
SelectedImage = Convert.ToString(ImageSource.FromStream(() => selectedImageFile.GetStream()));
}
just use the Path property of MediaFile
// this code does not do anything useful
SelectedImage = Convert.ToString(ImageSource.FromStream(() => selectedImageFile.GetStream()));
// do this instead
SelectedImage = selectedImageFile.Path;
Related
I have a requirement to implement a paging within a List View page. Here I am displaying hundreds or thousands of records in a table hence the need for paging functionality.
An infinite scrolling down approach is not viable due to the number of records. Same as attached image.
<ScrollView>
<SomeDataContentView Data={Binding SelectedData} />
</ScrollView>
<StackLayout BindableLayout.ItemSource={Binding ListOfPageNumber}
x:Name="SomeStack"
Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Button Text={Binding .}
Command={Binding Path=BindingContext.SelectPage_Command, Source={x:Reference SomeStack}
CommandParameter={Binding .}
</DataTemplate>
</BindableLayout.ItemTemplate>
ViewModel:
public SelectPage_Command = new Command((param) =>
{
var pageNo = (int)param;
SelectedData = DataDividedByPage[pageNo];
});
SomeDataContentView.cs:
SomeDataContentView : ContentView
public static readonly BindableProperty DataProperty = BindableProperty.Create(
nameof(Data), typeof(string), typeof(SomeDataContentView ), defaultValue: "", propertyChanged: DoSomethingWhenDataChanged);
public string Data
{
get => (string)GetValue(DataProperty perty);
set => SetValue(DataProperty , value);
}
And create your SomeDataContentView.xaml to show the data how you want it.
This is probably how I'd do it.
I've done it from memory and skipped one or two things. But I'll come back to it later, if you need me to.
//How to add Pagination in Xamarin Forms without using ViewModel
//Step 1-> First , we will add ListView property -> ItemAppearing
//In EmployeeTestListing.xaml page , we need to write
<ListView x:Name="lstEmployee"
IsPullToRefreshEnabled="True"
ItemTapped="lstEmployee_ItemTapped"
Refreshing="lstEmployee_Refreshing"
ItemAppearing="lstEmployee_ItemAppearing"
HasUnevenRows="True">
//Step 2-> In EmployeeTestListing.xaml.cs page , we need to write
public partial class EmployeeTestListing : ContentPage
{
ObservableCollection<EmployeeTestListingModel> employeeList;
public EmployeeTestListing()
{
InitializeComponent();
employeeList = new ObservableCollection<EmployeeTestListingModel>(); // Pagination
lstEmployee.ItemsSource = employeeList; // Pagination
}
public void LoadData()
{
var response = await httpService.Post("EmployeeTest/getemployeetests", employeeTest, false);
if (response.IsSuccessStatusCode)
{
var responseUserDataString = await response.Content.ReadAsStringAsync();
RootEmployeeTestListingModel employeeTestClass = JsonConvert.DeserializeObject<RootEmployeeTestListingModel>(responseUserDataString);
if (employeeTestClass.data.Count == 0)
{
loader.IsVisible = false;
loader.IsRunning = false;
lstEmployee.IsVisible = false;
lblNoData.IsVisible = true;
}
else
{
//For Pagination include below foreach code
foreach (var item in employeeTestClass.data)
{
employeeList.Add(item);
}
lstEmployee.IsVisible = true;
loader.IsVisible = false;
loader.IsRunning = false;
lblNoData.IsVisible = false;
}
}
}
//Pagination Scrolling Method ItemAppearing
private async void lstEmployee_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{
if (employeeList.Count == 0) return;
try
{
var item = (EmployeeTestListingModel)e.Item;
if (employeeList.Count >= pageSize)
{
if (item == employeeList.Last())
{
pageSize += pageSize;
lstEmployee.IsVisible = true;
await LoadData();
}
}
}
catch
{
}
}
}
I am trying to load data incrementally but the RemainingItemsThresholdReachedCommand is not triggered by RemainingItemsThreshold
Here the doc related to this : https://learn.microsoft.com/fr-fr/xamarin/xamarin-forms/user-interface/collectionview/populate-data
:
here my collection view page :
<ContentPage.Content>
<StackLayout BackgroundColor="#b4b4b4">
<RefreshView Command="{Binding RefreshItemsCommand}" IsRefreshing="{Binding IsRefreshing}" >
<CollectionView x:Name="CollectionViewThumbnails" SelectionMode="Multiple" Margin="13" ItemsSource="{Binding Items}"
RemainingItemsThresholdReachedCommand="{Binding ItemTresholdReachedCommand}"
RemainingItemsThreshold="{Binding ItemTreshold}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="1" VerticalItemSpacing="13" HorizontalItemSpacing="13"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:Name="data">
<Frame >
<StackLayout>
<Image Source="{Binding EmplacementThumbnails}" Aspect="AspectFill"/>
</StackLayout>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
<ActivityIndicator IsRunning="{Binding IsBusy}"
HeightRequest="30"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="30"/>
<StackLayout>
<Button Text="Go" Clicked="StartProcessConcatePages"/>
</StackLayout>
</StackLayout>
</ContentPage.Content>
My code behind :
public partial class ConcatePageThumbnails : ContentPage
{
FileEndpoint fileEndpoint = new FileEndpoint();
FileInfo fileInfo;
BitmapDataStore viewModel;
protected async override void OnAppearing()
{
base.OnAppearing();
if (viewModel.Items.Count == 0)
viewModel.LoadItemsCommand.Execute(null);
MessagingCenter.Subscribe<object, ThumbnailsModel>(this, BitmapDataStore.ScrollToPreviousLastItem, (sender, item) =>
{
CollectionViewThumbnails.ScrollTo(item, ScrollToPosition.End);
});
}
//TODO -- Gerer le retour
public ConcatePageThumbnails(FileInfo fileInfo)
{
InitializeComponent();
this.fileInfo = fileInfo;
BindingContext = viewModel = new BitmapDataStore(fileInfo);
}
}
And my view model :
public class BitmapDataStore
{
IGetThumbnails getThumbnails;
FileInfo fileInfo;
public List<ThumbnailsModel> Items { get; set; }
public Command LoadItemsCommand { get; set; }
public Command ItemTresholdReachedCommand { get; set; }
public Command RefreshItemsCommand { get; set; }
public const string ScrollToPreviousLastItem = "Scroll_ToPrevious";
private int _itemTreshold;
private bool _isRefreshing;
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { isBusy = value; }
}
public bool IsRefreshing
{
get { return _isRefreshing; }
set { _isRefreshing = value; }
}
public int ItemTreshold
{
get { return _itemTreshold; }
set { _itemTreshold = value; }
}
public BitmapDataStore(FileInfo fileInfo)
{
ItemTreshold = 2;
Items = new List<ThumbnailsModel>();
this.fileInfo = fileInfo;
getThumbnails = DependencyService.Get<IGetThumbnails>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
ItemTresholdReachedCommand = new Command(async () => await ItemsTresholdReached());
RefreshItemsCommand = new Command(async () =>
{
await ExecuteLoadItemsCommand();
IsRefreshing = false;
});
}
async Task ItemsTresholdReached()
{
if (IsBusy)
return;
IsBusy = true;
try
{
var items = await getThumbnails.GetBitmaps(fileInfo.FullName, Items.Count);
var previousLastItem = Items.Last();
foreach (var item in items)
{
Items.Add(item);
}
Debug.WriteLine($"{items.Count()} {Items.Count} ");
if (items.Count() == 0)
{
ItemTreshold = -1;
return;
}
MessagingCenter.Send<object, ThumbnailsModel>(this, ScrollToPreviousLastItem, previousLastItem);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
async Task ExecuteLoadItemsCommand()
{
if (IsBusy)
return;
IsBusy = true;
try
{
ItemTreshold = 2;
Items.Clear();
var items = await getThumbnails.GetBitmaps(fileInfo.FullName, Items.Count);
foreach (var item in items)
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
My Dependencyservice class where I get the thumbnails and The items for my Collection view :
public async Task<List<ThumbnailsModel>> GetBitmaps(string filePath, int lastIndex = 0)
{
var sw = new Stopwatch();
sw.Start();
int numberOfItemsPerPage = 6;
PdfRenderer pdfRenderer = new PdfRenderer(GetSeekableFileDescriptor(filePath));
var appDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
string directoryPath = System.IO.Path.Combine(appDirectory, "thumbnailsTemp", System.IO.Path.GetFileNameWithoutExtension(fileName));
List<ThumbnailsModel> thumbnailsModels = new List<ThumbnailsModel>();
if (!Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
}
//int pageCount = pdfRenderer.PageCount;
for (int i = lastIndex; i < lastIndex + numberOfItemsPerPage; i++)
{
PdfRenderer.Page page = pdfRenderer.OpenPage(i);
Android.Graphics.Bitmap bmp = Android.Graphics.Bitmap.CreateBitmap(page.Width, page.Height, Android.Graphics.Bitmap.Config.Argb4444);
page.Render(bmp, null, null, PdfRenderMode.ForDisplay);
try
{
using (FileStream output = new FileStream(System.IO.Path.Combine(directoryPath, fileName + "Thumbnails" + i + ".png"), FileMode.Create))
{
bmp.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 0, output);
}
page.Close();
}
catch (Exception ex)
{
//TODO -- GERER CETTE EXPEXPTION
throw new Exception();
}
}
int y = 1;
Directory.GetFiles(directoryPath).ToList<string>().Skip(lastIndex).Take(numberOfItemsPerPage).ForEach(delegate (string thumbnailsEmplacement)
{
thumbnailsModels.Add(new ThumbnailsModel(y, thumbnailsEmplacement));
y++;
});
sw.Stop();
return await Task.FromResult(thumbnailsModels);
}
I tried to change the ItemTreshold value but doesn't work... Any idea ?
Update :
With different test I saw that ItemTreshold and RemainingItemsThresholdReachedCommand are triggered but not as expected.
My collection view is loading with the number of item set but When I am going down and I am triggering RemainingItemsThresholdReachedCommand this method is triggered consecutively
For example I have 30 Pages : the first 6 pages are loading but when RemainingItemsThresholdReachedCommand is triggered for the first time, and again and again until all the pages and items are done. Then nothing happen on the ui collection view screen.
I just started from sratch with this sample and now it work : https://forums.xamarin.com/discussion/comment/402926#Comment_402926
Add "IsBusy" check in starting of "RemainingItemsThresholdReachedCommand". It will stop multi async calls.
if (IsBusy) return
In my UWP I have a ListView that is populated incrementally using the ISupportIncrementalLoading Interface for infinite scrolling.
This list is on a page PageX and as soon as I navigate to this page, the ListView gets populated.
This somethimes works and sometimes doesn't. problem is caused when I navigate to PageX, the LoadMoreItemsAsync is called more than once ( for the first time only, for further scrolling it works fine ).
Here's my code:
public class ItemsToShow : ObservableCollection<SearchResultViewModel>, ISupportIncrementalLoading
{
private SearchResponse ResponseObject { get; set; } = new SearchResponse();
private MetadataReply Metadata { get; set; } = new MetadataReply();
SearchResultViewModel viewModel = null;
public bool HasMoreItems
{
get
{
if ((string.IsNullOrEmpty(SomeStaticClass.NextPageToken) && !SomeStaticClass.IsFirstRequest) || SomeStaticClass.StopIncrementalLoading)
return false;
if(SomeStaticClass.IsFirstRequest)
{
using (var db = new DbContext())
{
var json = db.UpdateResponse.First(r => r.LanguageId == DataStore.Language).JsonResponse;
Metadata = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateApiResponse>(json).response.metadata.reply;
}
var returnObject = SomeStaticClass.SearchResponse;
ResponseObject = returnObject.response;
}
else
{
var returnObject = new SearchApiCall().CallSearchApiAsync(
SomeStaticClass.QueryString,
SomeStaticClass.NextPageToken,
SomeStaticClass.Filters).Result;
ResponseObject = returnObject.response;
}
return ResponseObject.documents.Count > 0;
}
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
CoreDispatcher coreDispatcher = Window.Current.Dispatcher;
if (SomeStaticClass.IsFirstRequest) SomeStaticClass.Facet = ResponseObject.facets;
return Task.Run<LoadMoreItemsResult>(async () =>
{
await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
foreach (var item in ResponseObject.documents)
{
this.Add(new SearchResultViewModel { .... });
}
});
SomeStaticClass.IsFirstRequest = false;
SomeStaticClass.NextPageToken = ResponseObject.pageToken;
await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
SearchResultPage.searchResultPage.FilterButton.Visibility = Visibility.Visible;
});
return new LoadMoreItemsResult() { Count = count };
}).AsAsyncOperation<LoadMoreItemsResult>();
}
}
My ListView:
<ListView Name="SearchResultListView"
SelectionMode="Single"
IsItemClickEnabled="True"
ItemClick="SearchResultListView_ItemClick">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="ViewModels:SomeViewModel">
<Grid Style="{StaticResource SomeStyle}">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="{x:Bind qqq}/>
<StackPanel Grid.Row="1">
<TextBlock Text="{x:Bind xxx}"/>
<TextBlock Text="{x:Bind yyy}"/>
</StackPanel>
<StackPanel Grid.Row="2">
<TextBlock Text="{x:Bind aaa}"/>
<TextBlock Text="{x:Bind bbb}" />
</StackPanel>
<TextBlock Text="{x:Bind EducationalLevel}"/
<StackPanel Grid.Row="4">
<TextBlock Text="{x:Bind Language}"/>
<Image Source="{x:Bind ccc}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind of the page that has this ListView:
public sealed partial class SearchResultPage
{
public static SearchResultPage searchResultPage { get; private set; }
private SearchResultParameterWrapper ReceivedParameter { get; set; } = new SearchResultParameterWrapper();
public SearchResultPage()
{
InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
searchResultPage = this;
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode != NavigationMode.Back) FilterButton.Visibility = Visibility.Collapsed;
SomeStaticClass.IsFirstRequest = true;
SomeStaticClass.Filters = new FilterParametersWrapper();
ReceivedParameter = (SearchResultParameterWrapper)e.Parameter;
if (ReceivedParameter != null)
{
SomeStaticClass.QueryString = ReceivedParameter.QueryString;
SomeStaticClass.Filters = ReceivedParameter.Filters;
SomeStaticClass.RestoreOldFilters = ReceivedParameter.RestoreOldFilters;
if(SomeStaticClass.IsFirstRequest)
await HandleNoResult(ReceivedParameter);
}
}
private async Task HandleNoResult(SearchResultParameterWrapper parameter)
{
if (!ApiStore.IsConnected())
{
Toast.ShowToast(MainPage.mainPage.ViewModel._APP_check_network, ToastRow);
return;
}
MyProgressRing.IsActive = true;
SearchResultListView.ItemsSource = null;
SearchResultListView.Items.ToList().Clear();
SearchResponse responseObject = null;
SearchApiResponse apiResponse = null;
try
{
SomeStaticClass.StopIncrementalLoading = true;
SomeStaticClass.SearchResponse = await new SearchApiCall().CallSearchApiAsync(parameter.QueryString, null, parameter.Filters);
apiResponse = SomeStaticClass.SearchResponse;
responseObject = apiResponse.response;
if (responseObject.documents.Count <= 0)
{
NoResultsTextBlock.Visibility = Visibility.Visible;
FilterButton.Visibility = Visibility.Collapsed;
return;
}
else
{
SearchResultListView.ItemsSource = new ItemsToShow();
SomeStaticClass.StopIncrementalLoading = false;
}
}
catch
{
}
finally
{
MyProgressRing.IsActive = false;
}
}
public bool Reload() { return Reload(null); }
private bool Reload(object param)
{
System.Type type = Frame.CurrentSourcePageType;
if (Frame.BackStack.Any())
{
param = ReceivedParameter;
}
try { return Frame.Navigate(type, param); }
finally { Frame.BackStack.Remove(Frame.BackStack.Last()); }
}
}
EDIT:
I've update my code. Same problem remains and another problem arises ie, The page sometimes goes blank ( after showing items for one or two seconds):
public class ItemsToShow : ObservableCollection<SearchResultViewModel>, ISupportIncrementalLoading
{
private SearchResponse ResponseObject { get; set; } = new SearchResponse();
private bool hasMoreItems { get; set; } = true;
public bool HasMoreItems
{
set
{
hasMoreItems = value;
}
get
{
if (SomeCondition) return false;
return hasMoreItems;
}
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
CoreDispatcher coreDispatcher = Window.Current.Dispatcher;
Task.Delay(10);
return Task.Run<LoadMoreItemsResult>(async () =>
{
if (IsFirstRequest)
{
HasMoreItems = string.IsNullOrEmpty(ResponseObject.someProperty) ? false : true;
IsFirstRequest = false;
}
else
{
ResponseObject = await new SomeClass().SomeMethod();
HasMoreItems = string.IsNullOrEmpty(ResponseObject.someProperty) ? false : true;
}
await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
foreach (var item in ResponseObject.documents)
{
this.Add(PrepareViewModel(item));
}
});
await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
SearchResultPage.searchResultPage.FilterButton.Visibility = Visibility.Visible;
});
return new LoadMoreItemsResult() { Count = count };
}).AsAsyncOperation<LoadMoreItemsResult>();
}
}
As long as you don't try to load the same items twice, I don't really see much issue with it. It's like having two sets of data on load, and then loading one set on scroll.
But you probably would wonder why it's doing this, and here is how I understand it.
During the initial load, ISupportIncrementalLoading.LoadMoreItemsAsync will always be called more than once unless there's no data to populate. This behavior is most likely caused by the design of ListView virtualization.
My guess is that before the ListView decides how many items to load initially, it needs to know the item height in order to calculate the number of items to virtualize. Therefore, it first loads one item to get the height, do the calculations and call LoadMoreItemsAsync again. This is why if you put a breakpoint inside LoadMoreItemsAsync, you will see the count value always gives you 1 the first time the method is called.
To avoid this behavior, you cannot simply ignore the first call 'cause incremental loading won't be triggered when there's no items in view. So you can hack around to ignore not the first but second call.
Take the source from UWP Community Toolkit for example, you can do something like this -
private bool? _firstLoadJustPassed;
private async Task<LoadMoreItemsResult> LoadMoreItemsAsync(uint count, CancellationToken cancellationToken)
{
if (_firstLoadJustPassed == true)
{
_firstLoadJustPassed = false;
return new LoadMoreItemsResult { Count = 0 };
}
uint resultCount = 0;
_cancellationToken = cancellationToken;
try
{
if (!_cancellationToken.IsCancellationRequested)
{
IEnumerable<IType> data = null;
try
{
IsLoading = true;
data = await LoadDataAsync(_cancellationToken);
}
catch (OperationCanceledException)
{
// The operation has been canceled using the Cancellation Token.
}
catch (Exception ex) when (OnError != null)
{
OnError.Invoke(ex);
}
if (data != null && data.Any() && !_cancellationToken.IsCancellationRequested)
{
resultCount = (uint)data.Count();
foreach (var item in data)
{
Add(item);
}
if (!_firstLoadJustPassed.HasValue)
{
_firstLoadJustPassed = true;
}
}
else
{
HasMoreItems = false;
}
}
}
finally
{
IsLoading = false;
if (_refreshOnLoad)
{
_refreshOnLoad = false;
await RefreshAsync();
}
}
return new LoadMoreItemsResult { Count = resultCount };
}
There might be more elegant solutions than this but again like I said, I personally don't see such a big issue with this behavior and I would use IncrementalLoadingCollection from the toolkit than writing my own implementation.
I'm trying to implement the XLabs CameraViewModel functionality into my Xamarin Forms App. Unfortunately, the given example uses XAML to bind the views with data, but i need to do it in code behind.
The following code is used to select a picture and get it's source.
public class CameraViewModel : XLabs.Forms.Mvvm.ViewModel
{
...
private ImageSource _imageSource;
private Command _selectPictureCommand;
public ImageSource ImageSource
{
get { return _imageSource; }
set { SetProperty(ref _imageSource, value); }
}
public Command SelectPictureCommand
{
get
{
return _selectPictureCommand ?? (_selectPictureCommand = new Command(
async () => await SelectPicture(),() => true));
}
}
...
}
And these commands are bound to XAML :
<Button Text="Select Image" Command="{Binding SelectPictureCommand}" />
<Image Source="{Binding ImageSource}" VerticalOptions="CenterAndExpand" />
How can I apply the same commands in code-behind for created elements?
CameraViewModel ViewModel = new CameraViewModel();
var Take_Button = new Button{ };
Take_Button.SetBindings(Button.CommandProperty, //*???*//);
var Source_Image = new Image { };
Source_Image.SetBinding(Image.SourceProperty, //*???*//);
I've successfully binded SelectPictureCommand by doing the following:
Take_Button .Command = ViewModel.SelectPictureCommand;
However I have my doubts about it being the correct way, and the same logic cannot be applies to ImageSource.
For the button you have:
var Take_Button = new Button{ };
Take_Button.SetBinding(Button.CommandProperty, new Binding { Path = nameof(ViewModel.SelectPictureCommand), Mode = BindingMode.TwoWay, Source = ViewModel});
For the image you have:
var Source_Image = new Image { };
Source_Image.SetBinding(Image.SourceProperty, new Binding { Path = nameof(ViewModel.ImageSource), Mode = BindingMode.TwoWay, Source = ViewModel });
I have bit map in View Model. Now I want to bind to the XAML from View Model.
public static String _imgQRCode;
public String imgQRCode
{
get { return _imgQRCode; }
set { this.RaiseAndSetIfChanged(x => x.imgQRCode, value); }
}
Bit Map:-
imgQRCode = GenerateQRCode(phoneNumber).ToString();
GenerateORCode:-
private static WriteableBitmap GenerateQRCode(string phoneNumber)
{
BarcodeWriter _writer = new BarcodeWriter();
_writer.Renderer = new ZXing.Rendering.WriteableBitmapRenderer()
{
Foreground = System.Windows.Media.Color.FromArgb(255, 0, 0, 255),
};
_writer.Format = BarcodeFormat.QR_CODE;
_writer.Options.Height = 400;
_writer.Options.Width = 400;
_writer.Options.Margin = 1;
var barcodeImage = _writer.Write("tel:" + phoneNumber);
return barcodeImage;
}
Here i can not bind the image. Please let me any idea to bind the image from viewModel.
Thanks in advance.
Change the data type from string to WriteableBitmap for imgQRCode.
You can not bind the image to string.
So long as datacontext is correct for your tag, you should define a property for the bitmap, e.g.
WriteableBitmap QRCode { get; set; } // Implement INotifyPropertyChanged the way you do it
Then have QRCode set in your other property setter, like so:
public String imgQRCode
{
get { return _imgQRCode; }
set
{
this.RaiseAndSetIfChanged(x => x.imgQRCode, value);
this.QRCode = GenerateQRCode(value);
}
}
then in XAML you can do <Image Source="{Binding Path=QRCode}" />