multiple image at the same component (image placeholder) - xaml

In my app, I load an image from URL.
<Image Source="{Binding Image}" />
I want to load a small image from local in advance. After the image from remote is downloaded completely, replace or overwrite this local image.
Is there any simple way to achieve this function?
Such as multiple background image in a div.
http://css-tricks.com/stacking-order-of-multiple-backgrounds/

This is the simplest way to achieve what you desire;
<Grid>
<Image Source="YourLocalImage" />
<Image Source="{Binding Image}" />
</Grid>
So, in your app until your URL image is loaded, your local image will be visible & once your URL image is loaded, that will be visible. See, if this helps.

Not a built-in functionality in xaml...but this would do the trick.
At first you put the local image location as a value in image property. Then you need to have a Image downloaded completed event so that you can detect when Image is successfully downloaded from remote location.
Inside this event you can replace Image property value so that it changes the image in the UI. But make sure your class in which Image is defined has implemented INotifyPropertyChanged interface.
public class MyData : INotifyPropertyChanged{
private string image;
public string Image {
set{
Notify("Image");
image = value;
}
get{ return image; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void Notify(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Related

View a specific image from the complete gallery path without browsing

I'm trying:
<Image Source="/storage/emulated/0/Pictures/Test/IMG_20200408_085036.jpg"/>
No effect.
File imageSpc = new File('/storage/emulated/0/Pictures/Test/IMG_20200408_085036.jpg');
var imageSpc = new File('/storage/emulated/0/Pictures/Test/IMG_20200408_085036.jpg');
Error, cannot create static variable for type File or var.
<Image x:Name="fotka" Aspect="AspectFit" HeightRequest = "50"
WidthRequest = "60"/>
fotka.Source = ImageSource.FromFile("/storage/emulated/0/Pictures/Test/IMG_20200408_085036.jpg");
No effect
Is possible to show specific image from gallery in XAML or at least from the code
I did enable ADB notification option in device.
In The moment image to be displayed compiler show error:
How to fix this Error?
According to your description, you want to display image using gallery path, if yes, please take a look the following code:
Firstly, you need to get image path from gallery in Android or ios.
Create interface IFileSystem in PCL(Forms)
public interface IFileSystem
{
string GetGalleryImage();
}
Then implementing this interface in platform, the example is in Android.
[assembly: Dependency(typeof(FileSystemImplementation))]
namespace demo3.Droid
{
public class FileSystemImplementation : IFileSystem
{
public string GetGalleryImage()
{
var filePath = Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures);
var path = System.IO.Path.Combine(filePath.AbsolutePath, "Test/image1.jpg");
return path;
}
}
}
Add one Image control in PCL(Forms), name image1, using DependencyService to get image path.
<Button
x:Name="btn1"
Clicked="Btn1_Clicked"
Text="load image" />
<Image
x:Name="image1"
HeightRequest="100"
WidthRequest="100" />
private void Btn1_Clicked(object sender, EventArgs e)
{
var path = DependencyService.Get<IFileSystem>().GetGalleryImage();
image1.Source = ImageSource.FromFile(path);
}
This is article about DependencyService, you can take a look:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction
Update:
I found, each image before show in activity must be resized to max size 4096 x 4096 px otherwise image not shown, without any errors message.

custom entry box with icon for xamarin form (android,ios)

Entry box should be rounded with an icon to the left or right in it. I'm using the code presented here to create this custom entry.
1. Remove the rectangular border of Entry
Used CustomRender to achieve this.
Forms
public class NoUnderlineEntry : Entry
{
public NoUnderlineEntry()
{
}
}
Android
Set Background to null
public class NoUnderLineEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
this.Control.Background = null;
}
}
iOS
Set BorderStyle to None
public class NoUnderlineEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
this.Control.BorderStyle = UIKit.UITextBorderStyle.None;
}
}
2. Placing Image next to Entry
Adding Image and Entry to the same Grid in two columns.
3. Adding Rounded border to the Entry and Image
Add them inside a Frame with CornerRadius.
XAML
<StackLayout>
<Frame
Padding="10, 5, 10, 5"
HasShadow="False"
BorderColor="Gray"
CornerRadius="30">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<local:NoUnderlineEntry/>
<Image Source="icon.png" Grid.Column="1" WidthRequest="50" Aspect="AspectFit"/>
</Grid>
</Frame>
</StackLayout>
UI result:
Please note: I won't present a copy-and-paste-able answer, but rather an outline on how to add the images. You'll have to integrate the code in your solution by yourself.
On iOS
There already is an answered question on how to achieve this with Swift on iOS, you can find it here.
Basically what to do is to set the right view (or left view respectively) on the UITextField from your custom renderer (in OnElementChanged).
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
var imageView = new UIImageView(new CGRect(0, 0, 20, 20));
var image = UIImage.FromFile("ic_location.png");
imageView.Image = image;
this.Control.RightView = imageView;
this.Control.RightViewMode = UITextFieldViewMode.Always;
}
This sets the view in the right of the UITextField to a UIImageView. If you wanted to show the icon before the text instead, you'd have to set LeftView and LeftViewMode instead. This is how it looks like. (I intentionally did not inline the image, because it rendered the answer less redable.)
Of course the file ic_location.png has to be in your platform projects resources.
You may need some fine tuning, but basically that's it.
On Android
The TextView.setCompoundDrawablesWithIntrinsicBounds
Sets the Drawables (if any) to appear to the left of, above, to the right of, and below the text. Use null if you do not want a Drawable there. The Drawables' bounds will be set to their intrinsic bounds. (source)
By loading the icon from the resource and setting it with SetCompoundDrawablesWithIntrinsicBounds (uppercase now, since we're now on C#) you can display the Entry with the icon:
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
this.Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, this.GetIcon(), null);
this.Control.CompoundDrawablePadding = 25;
}
private Drawable GetIcon()
{
int resID = Resources.GetIdentifier("ic_location", "drawable", this.Context.PackageName);
var drawable = ContextCompat.GetDrawable(this.Context, resID);
var bitmap = ((BitmapDrawable)drawable).Bitmap;
return new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 20, 20, true));
}
This is how the Android version looks like.
For showing the icon on left left, pass the drawable to the first parameter instead of the third.

XAML Slider inside ScrollViewer

For Windows 10 UWP app I have such XAML structure:
<ScrollViewer>
<StackPanel>
<Slider />
<Slider />
...
</StackPanel>
</ScrollViewer>
I would like to create such user experience:
When the user begins horizontal swipe gesture, the slider under the touch should receive the input and start changing its value, while vertical scrolling is completely disabled (even when the user continue draw circle motions)
When the user begins vertical swipe gesture, the scrollviewer should receive the input and start scrolling vertically, while sliders under the touch should stay intact (even when the user continue draw circle motions).
Is it possible to implement this behavior in pure XAML? I think I have tried all possible combinations of properties related to scroll... No luck. Any idea anybody?
After testing on mobile emulator with OS version 10586, I found that when the ScrollViewer is vertically scrolled, it won't effect the Slider inside even if I draw circle, and when the Slider is swiped horizontally, only when its value reaches the max value, the vertical scrolling of the ScrollViewer will be effected if I draw circle.
Is it possible to implement this behavior in pure XAML?
Yes, it is possible.
When the user begins horizontal swipe gesture, the slider under the touch should receive the input and start changing its value, while vertical scrolling is completely disabled (even when the user continue draw circle motions)
You can install the Microsoft.Xaml.Behaviors.Uwp.Managed package in your project, then use its DataTriggerBehavior for example like this:
<ScrollViewer x:Name="scrollViewer" HorizontalScrollMode="Disabled" VerticalScrollMode="Auto">
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding ElementName=slider1,Path=FocusState}" ComparisonCondition="NotEqual" Value="Unfocused">
<Core:ChangePropertyAction PropertyName="VerticalScrollMode" Value="Disabled" />
</Core:DataTriggerBehavior>
<Core:DataTriggerBehavior Binding="{Binding ElementName=slider1,Path=FocusState}" ComparisonCondition="Equal" Value="Unfocused">
<Core:ChangePropertyAction PropertyName="VerticalScrollMode" Value="Auto" />
</Core:DataTriggerBehavior>
<Core:DataTriggerBehavior Binding="{Binding ElementName=slider2,Path=FocusState}" ComparisonCondition="NotEqual" Value="Unfocused">
<Core:ChangePropertyAction PropertyName="VerticalScrollMode" Value="Disabled" />
</Core:DataTriggerBehavior>
<Core:DataTriggerBehavior Binding="{Binding ElementName=slider2,Path=FocusState}" ComparisonCondition="Equal" Value="Unfocused">
<Core:ChangePropertyAction PropertyName="VerticalScrollMode" Value="Auto" />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<StackPanel Height="1300">
<Slider Margin="0,200" x:Name="slider1" />
<Slider x:Name="slider2" />
</StackPanel>
</ScrollViewer>
When using this package in xaml, you will need to declare it in the header for example like this:
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
xmlns:Media="using:Microsoft.Xaml.Interactions.Media"
As you can see in my code, I compared FocusState property of the Slider, if its value is Unfocused, then the vertical scroll mode of the ScrollViewer is enabled. So when user interact with this layout, after swiping on the Slider, he will need to click on the blank part to make the Slider lost focus first, then the vertical scroll mode can be enabled.
When the user begins vertical swipe gesture, the scrollviewer should receive the input and start scrolling vertically, while sliders under the touch should stay intact (even when the user continue draw circle motions).
Base on my test, I think this gesture is ensured by default, so I didn't code for this. If it is not by your side, please leave a comment and provide your device type and OS version so can I have a test.
I have a very similar issue and was able to resolve it with the following custom control. This is a CommandSlider that also allows you to send commands like a button after the sliding is complete (not what you need) but the ScrollViewer manipulation code is in there also. See if this helps your situation. It allows you to do all the work in complete XAML like you've requested.
NOTE: The slider must have ManipulationMode="TranslateX" or "TranslateY"depending on the orientation for this to work also.
public sealed class CommandSlider : Slider
{
public CommandSlider()
{
IsThumbToolTipEnabled = false;
PointerCaptureLost += (s, e) => (Command?.CanExecute(CommandParameter)).GetValueOrDefault().Switch(() => Command?.Execute(CommandParameter));
Loaded += (s, e) => ParentScrollViewer = this.GetParent<ScrollViewer>();
}
private ScrollViewer ParentScrollViewer { get; set; }
protected override void OnManipulationDelta(ManipulationDeltaRoutedEventArgs e)
{
base.OnManipulationDelta(e);
if (ParentScrollViewer != null)
{
var scrollX = Orientation == Orientation.Vertical
? e.Position.X * -1 + ParentScrollViewer.HorizontalOffset
: ParentScrollViewer.HorizontalOffset;
var scrollY = Orientation == Orientation.Horizontal
? e.Position.Y * -1 + ParentScrollViewer.VerticalOffset
: ParentScrollViewer.VerticalOffset;
var zoom = ParentScrollViewer.ZoomFactor;
ParentScrollViewer.ChangeView(scrollX, scrollY, zoom);
}
}
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(CommandSlider), new PropertyMetadata(null));
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(CommandSlider), new PropertyMetadata(null));
public double SourceValue
{
get => (double)GetValue(SourceValueProperty);
set => SetValue(SourceValueProperty, value);
}
public static readonly DependencyProperty SourceValueProperty =
DependencyProperty.Register(nameof(SourceValue), typeof(double), typeof(CommandSlider), new PropertyMetadata(0d,
(s, e) => (s as CommandSlider).Value = (double)e.NewValue));
}
Custom Extension Method
public static class XAMLExtensions
{
public static T GetParent<T>(this DependencyObject dependencyObject) where T : DependencyObject
{
var parentDependencyObject = VisualTreeHelper.GetParent(dependencyObject);
switch (parentDependencyObject)
{
case null:
return null;
case T parent:
return parent;
default:
return GetParent<T>(parentDependencyObject);
}
}
}

In Xaml, how do you change the value of the SolidColorBrush programmatically?

Hi I have a xaml app that has one particular color used in many places on a page. I want to programmatically change the value of this color. I don't want to have to update every object's color individually. I have tried this:
<Grid
Background="{Binding GalleryViewBrush, Mode=TwoWay}"
Grid.Row="0"
Grid.Column="0">
Then in codebehind:
public Brush GalleryViewBrush { get; set; }
GalleryViewBrush = new SolidColorBrush(Colors.Red);
But the color never works. I have tried xbind too but no luck
thanks
Your view model needs to implement INotifyPropertyChanged, and then fire the PropertyChanged event when your brush property changes. Conventionally that's done in the setter for the property.
private Brush _myBrush;
public MyBrush {
get { return _myBrush; }
set {
_myBrush = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyBrush));
}
}
If your get/set for GalleryViewBrush in your question is what's actually in the code sample in your question, that's likely to be the issue.
Mind typos in my code sample above, I'm hammered ATM.

Universal Windows InkCanvas strokes disappear on RenderTargetBitmap.RenderAsync

I try to render the strokes of a InkCanvas to a RenderTargetBitmap in a windows 10 universal App. Here is my xaml code:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="10" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid x:Name="container">
<Rectangle Fill="LightBlue" />
<InkCanvas x:Name="InkCanvas" />
</Grid>
<Image Grid.Row="2" x:Name="TheImage" />
<Button Grid.Row="3" Content="CopyToRendertargt" Click="Button_Click" />
</Grid>
And here is my code to set the Image.Source property:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
InkCanvas.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse;
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
RenderTargetBitmap renderTarget = new RenderTargetBitmap();
await renderTarget.RenderAsync(this.container);
this.TheImage.Source = renderTarget;
}
}
When i click to button the strokes i made on the InkCanvas disappear and the InkCanvas is forzen until i resize the app window. The strokes are not getting rendered to the RenderTargetBitmap. The Image shows just the LightBlue Rectangle.
Does sombody have a solution for this?
** UPDATE **
For those who are searching for the right way to save strokes to a bitmap on uwp. I found the UWP-way of saving InkCanvas Strokes to a Bitmap: The InkStrokeContainer Object has a method called SaveAsync(...) which saves the strokes to a stream. If you use this stream as source for a Bitmap you get the strokes as Bitmap.
InkStrokeContainer container = TheInkCanvas.InkPresenter.StrokeContainer;
WriteableBitmap bmp;
using (InMemoryRandomAccessStream ims =
new InMemoryRandomAccessStream())
{
await container.SaveAsync(ims);
bmp = await new WriteableBitmap(1, 1)
.FromStream(ims, BitmapPixelFormat.Bgra8);
}
*Note: WriteableBitmapEx is used in this sample code (https://www.nuget.org/packages/WriteableBitmapEx/)
You can use Win2D to render the Ink Strokes.
Add Win2D.uwp to the project from NuGet
Add this InkCanvasExtensions.cs file to your project
Change the namespace or add using Zoetrope; to your source
Create an image file or stream and pass it to the InkCanvas.RenderAsync()
InkCanvasExtensions.cs
namespace Zoetrope
{
using System;
using System.Threading.Tasks;
using Microsoft.Graphics.Canvas;
using Windows.Graphics.Display;
using Windows.Storage.Streams;
using Windows.UI;
using Windows.UI.Xaml.Controls;
/// <summary>
/// InkCanvas Extensions
/// </summary>
public static class InkCanvasExtensions
{
/// <summary>
/// Render an InkCanvas to a stream
/// </summary>
/// <param name="inkCanvas">the ink canvas</param>
/// <param name="fileStream">the file stream</param>
/// <param name="backgroundColor">the background color</param>
/// <param name="fileFormat">the file format</param>
/// <returns>an async task</returns>
public static async Task RenderAsync(
this InkCanvas inkCanvas,
IRandomAccessStream fileStream,
Color backgroundColor,
CanvasBitmapFileFormat fileFormat)
{
// do not put in using{} structure - it will close the shared device.
var device = CanvasDevice.GetSharedDevice();
var width = (float) inkCanvas.ActualWidth;
var height = (float) inkCanvas.ActualHeight;
var currentDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
using (var offscreen = new CanvasRenderTarget(device, width, height, currentDpi))
{
using (var session = offscreen.CreateDrawingSession())
{
session.Clear(backgroundColor);
session.DrawInk(inkCanvas.InkPresenter.StrokeContainer.GetStrokes());
}
await offscreen.SaveAsync(fileStream, fileFormat);
}
}
}
}
In the XAML visuals and RenderTargetBitmap section in the RenderTargetBitmap documentation, it describes: Content that can't be captured will appear as blank in the captured image, but other content in the same visual tree can still be captured and will render (the presence of content that can't be captured won't invalidate the entire capture of that XAML composition).So it could be that the content of InkCanvas is not captureable.
An alternative is to use Win2D (Direct2D .NET wrapper from Microsoft). Win2D can be used in an UWP app via a nuget package. You will be able to manage the ink strokes and save them to image (jpeg, png, and other formats).