I have a few internal Canvas xaml files which I want to load dynamically at runtime. For example, I want to display the Canvas in a page. However, I cannot seem to get it to work. I've tried using XamlReader, Application.LoadComponent, and using an XDocument; all to no avail. I cannot seem to find the best practice for this on-line either.
The Canvases are stored like this: MyApp/Resources/Logos/Logo1.xaml. I'm not sure if Logo1.xaml should have a build action of "Component" or "Resource". In any case, using the URI of "MyApp;components/Resources/Logos/Logo1.xaml" seems to be correct, but Application.LoadComponent gets an XamlParseException at Line 0 Position 0.
Here's a pseudo-example of Logo1.xaml:
<Canvas
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="286.233" Height="143.425">
<Canvas>
<Path />
<Path />
<Path />
<Path />
</Canvas>
</Canvas>
The data for the path elements has been omitted for brevity's sake.
Any ideas?
I got this to work using build action "Resource" and the XamlLoader with a ContentControl:
var resourceName = string.Format("MyApp;component/Resources/Logos/{0}.xaml", logoName);
var uri = new Uri(resourceName, UriKind.Relative);
var streamResourceInfo = Application.GetResourceStream(uri);
string xaml = null;
using (var resourceStream = streamResourceInfo.Stream)
{
using (var streamReader = new StreamReader(resourceStream))
{
xaml = streamReader.ReadToEnd();
}
}
Canvas canvas = XamlReader.Load(xaml) as Canvas;
this.contentControl.Content = canvas;
The accepted answer is not intuitive to me, but may suit some people.
I generally feel more comfortable with System.IO.File.WriteAllText and System.IO.File.ReadAllText. I borrowed a code piece from MSDN. For a test, just create a new Canvas at runtime:
Canvas newCanvas = new Canvas()
Then, just write it out, with File.WriteAllText, simple too, avoiding all the URI stuff, which as a beginner I find confusing. Lastly, just read it back in as above. Done. This proves you can simply just read in some valid code for a canvas from a text file, and it can be loaded dynamically.
private void Button2_Click(object sender, RoutedEventArgs e)
{
Canvas newCanvas = new Canvas();
newCanvas.Name = "newCanvas";
string savedCanvas = XamlWriter.Save(newCanvas);
File.WriteAllText("savedCanvas.txt", savedCanvas);
savedCanvas = File.ReadAllText("savedCanvas.txt");
// Load the canvas
StringReader stringReader2 = new StringReader(savedCanvas);
XmlReader xmlReader2 = XmlReader.Create(stringReader2);
Canvas newCreatedCanvas = (Canvas)XamlReader.Load(xmlReader2);
this.Content = newCreatedCanvas;
}
The ideas are from MSDN as below:
XamlReader.Load Method (XmlReader)
.NET Framework 4
Reads the XAML input in the specified XmlReader and returns an object that is the root of the corresponding object tree.
Namespace: System.Windows.Markup
Assembly: PresentationFramework (in PresentationFramework.dll)
Related
.NET MAUI has the ability to use SVG images which is really nice, but I haven't been able to set the color of the SVG image. The official docs state I could use the TintColor in the project file but that's not a good solution as I want to be able to use different colors depending on certain conditions. So can we somehow specify the color of a SVG image?
I just figured out that the Maui Community toolkit has a IconTintColorBehavior that does just want I want.
Usage:
<Image Source="shield.png">
<Image.Behaviors>
<toolkit:IconTintColorBehavior TintColor="Red" />
</Image.Behaviors>
</Image>
Maybe you could use skiasharp. I give some examples.
First add Nuget, such as SkiaSharp.Views.Maui.Controls, SkiaSharp.Svg.
In the xaml, define a SKCanvasView. The PaintSurface event handler is where you do all your drawing.
<StackLayout>
<skiact:SKCanvasView WidthRequest="500" HeightRequest="500" x:Name="mycanvasview" PaintSurface="mycanvasview_PaintSurface">
</skiact:SKCanvasView>
</StackLayout>
In the .cs file, implement mycanvasview_PaintSurface method. Add some code like this:
private void mycanvasview_PaintSurface(object sender, SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs e)
{
SKImageInfo info = e.Info;
SKSurface surface = e.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
Stream stream = LoadStream(typeof(MainPage),"myfile.svg");
SKSvg svg = new SKSvg();
svg.Load(stream);
using (var paint = new SKPaint())
{
paint.ColorFilter = SKColorFilter.CreateBlendMode(
SKColors.Yellow,
SKBlendMode.SrcIn);
canvas.DrawPicture(svg.Picture ,paint);
}
}
private static Stream LoadStream(Type type, string v)
{
Assembly assembly = type.GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream(v);
return stream;
}
You svg file will change the color.
I hope my answer could help you.
When I try to use the method to inflate my XAML:
MenuBarItem item = new().LoadFromXaml("<MenuBarItem Text=\"Session\"><MenuFlyoutItem Text=\"New\"/><MenuFlyoutItem Text=\"Save\"/><MenuFlyoutItem Text=\"Load\"/></MenuBarItem>");
the MenuBarItem is created and Text properly assigned but all the MenuFlyoutItems are ommited and not added to the menu.
After reading Load XAML at runtime documentation and particularly the "The LoadFromXaml method can be used to inflate any XAML" and the examples given, I assumed that I can throw any valid XAML into it - from a single button, to a DataTemplate of a ListView, a MenuBarItem for a menu, to a whole ContentPage and it should work. But it's not working in this case - I get Microsoft.Maui.Controls.Xaml.XamlParseException and System.Reflection.TargetInvocationException.
Is this behavior a bug or is documentation missing some details about loading XAMLs?
When I enclose the MenuBarItem in a ContentPage's MenuBarItems like this:
new ContentPage().LoadFromXaml("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage\r\n\txmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\r\n\txmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\r\n\tx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\r\n\tTitle=\"Catalog Items\">\r\n\t<ContentPage.MenuBarItems>\r\n\t\t<MenuBarItem Text=\"Session\">\r\n\t\t\t<MenuFlyoutItem\r\n\t\t\t\tText=\"New\"/>\r\n\t\t\t<MenuFlyoutItem\r\n\t\t\t\tText=\"Save\"/>\r\n\t\t\t<MenuFlyoutItem\r\n\t\t\t\tText=\"Load\"/>\r\n\t\t</MenuBarItem>\r\n\t</ContentPage.MenuBarItems>\r\n</ContentPage>");
it inflates without error and then when I assign elements from the inflated ContentPage to the MainPage's MenuBarItems they display well. But this is an ugly workaround because I don't need a whole ContentPage, just the MenuBarItem.
Your XAML is not complete, thus cannot be parsed.
What the ContentPage has, that your XAML lacks, is the various xmlns lines, that specify the XML elements used in the XAML.
I have not tested, but try replacing <MenuBarItem with
<MenuBarItem\r\n\txmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\r\n\txmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\r\n
Adapt as needed. Any whitespace can be used anywhere \r\n is shown.
If it doesn't work, also prefix with:
<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n
But I believe that is optional.
As an aside, anything that can be done in XAML, can instead be done in C#. C# markup.
C#, being a complete computational language, can often create dynamic UI more easily than XAML, if you are building a UI that depends on different conditions.
A convenient approach in C#, is to define "helper" methods, that take whatever parameters you want, and creates a specific element. That you add to a given parent element, either via C# markup, or methods of a parent layout class.
Its easy to write helper methods that call other helper methods, to build up a whole layout to your specs, controlled at each step by the parameters that matter to you.
At the top level, you might end up with code like this:
// use custom helper methods and methods of "Grid" class.
Grid grid = MyCreateGrid();
grid.Children.Add(MyCreateRowLabel(text), 1, 0);
grid.Children.Add(
// OR use C# markup
new StackLayout
{
Children =
{
new Label().Text("Code:"),
...
}
},
1, 1
);
...
From the official document, it's only using LoadFromXaml for single view or a complete contentPage. I also tried LoadFromXaml for <MenuBarItem Text=\"Session\"><MenuFlyoutItem Text=\"New\"/><MenuFlyoutItem Text=\"Save\"/><MenuFlyoutItem Text=\"Load\"/></MenuBarItem>, and just you said that:
the MenuBarItem is created and Text properly assigned but all the MenuFlyoutItems are ommited and not added to the menu.
But you can achieve it by doing this:
MainPage.xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp_loadXaml.MainPage"
x:Name="contentPage">
<Button Text="click" Clicked="Button_Clicked" HeightRequest="50"/>
</ContentPage>
MainPage.xaml.cs:
private void Button_Clicked(object sender, EventArgs e)
{
var xaml = "<MenuBarItem Text=\"Session\"></MenuBarItem>";
var xaml1 = "<MenuFlyoutItem Text=\"New\"/>";
var xaml2 = "<MenuFlyoutItem Text=\"Save\"/>";
var xaml3 = "<MenuFlyoutItem Text=\"Load\"/>";
MenuFlyoutItem menuFlyoutItem_1 = new MenuFlyoutItem().LoadFromXaml(xaml1);
MenuFlyoutItem menuFlyoutItem_2 = new MenuFlyoutItem().LoadFromXaml(xaml2);
MenuFlyoutItem menuFlyoutItem_3 = new MenuFlyoutItem().LoadFromXaml(xaml3);
MenuBarItem item = new MenuBarItem();
item.LoadFromXaml(xaml);
item.Add(menuFlyoutItem_1);
item.Add(menuFlyoutItem_2);
item.Add(menuFlyoutItem_3);
contentPage.MenuBarItems.Add(item);
}
It works well.
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.
I am currently developing metro apps and I need to write text On images.
I found this http://writeablebitmapex.codeplex.com/
But I am new to XAML and dosent know how to use it specifically.
So can anyone say me how do I use it in order to write text on image.
As I have asked this question on MSDN but I have no reply yet.
Edit:
If I use as Muad'Dib I am getting the error as seen in below screenshot:
The Error is: 'Writeable Bitmap Extensions' is ambiguous in the namespace 'System.Windows.Media.Imaging'
there is one possible solution in the Discussions area for WriteableBitmapEx
here is the code from that "article":
public static void DrawText(this WriteableBitmap wBmp,Point at, string text,double fontSize,Color textColor)
{
TextBlock lbl = new TextBlock();
lbl.Text = text;
lbl.FontSize = fontSize;
lbl.Foreground = new SolidColorBrush(textColor);
WriteableBitmap tBmp = new WriteableBitmap(lbl, null);
wBmp.Blit(at, tBmp, new Rect(0, 0, tBmp.PixelWidth, tBmp.PixelHeight), Colors.White, System.Windows.Media.Imaging.WriteableBitmapExtensions.BlendMode.Alpha);
}
I'm trying to programmatically load a BitmapImage in a XAML Metro app. Here's my code:
var uri = new Uri("/Images/800x600/BackgroundTile.bmp", UriKind.RelativeOrAbsolute);
var imageSource = new BitmapImage(uri);
The second line crashes with a System.ArgumentException:
The given System.Uri cannot be converted into a Windows.Foundation.Uri. Please see http://go.microsoft.com/fwlink/?LinkID=215849 for details.
The link just goes to the MSDN home page, so it's no use.
I've also tried removing the leading /, in case WinRT has different expectations about relative URIs, but I still get the same exception.
Why am I getting this exception for what seems to be a perfectly valid URI?
In the Consumer Preview, the correct URL format has apparently changed to ms-appx:/Images/800x600/BackgroundTile.bmp
Judging from the documentation for Windows.Foundation.Uri, it looks like WinRT doesn't support relative URIs. I tried a pack:// URI, but that gave me a UriFormatException, so apparently that's not the way to do it in WinRT either.
I found the answer on this thread: MS invented yet another URI format for WinRT resources. This works:
new Uri("ms-resource://MyAssembly/Images/800x600/BackgroundTile.bmp")
Note that you don't add your actual assembly name -- the MyAssembly part is literal text.
You will need to use the page's BaseUri property or the image control's BaseUri property like this:
//using the page's BaseUri property
BitmapImage bitmapImage = new BitmapImage(this.BaseUri,"/Images/800x600/BackgroundTile.bmp");
image.Source = bitmapImage;
or
//using the image control's BaseUri property
image.Source = new BitmapImage(image.BaseUri,"/Images/800x600/BackgroundTile.bmp");
you can see the reason and solution here
In case you're still having issues or are being asked to find an app to open the link, are you trying to use a WebView? If so, try using ms-appx-web instead of ms-appx.
An example:
this.webBrowser.Navigate(new Uri("ms-appx-web:///level/level/level/index.html"));
Also note the lack of the URIKind parameter--evidently not needed at all in these instances.
(I believe you may need to vary the leading forward slashes depending on your reference)
This would work in XAML but would not work in code... so each control or page has a BaseUri property which you can use to build the proper uri for assets... here is an example:
imageIcon.Source = new BitmapImage(new Uri(this.BaseUri, "Assets/file.gif"));
// Or use the base uri from the imageIcon, same thing
imageIcon.Source = new BitmapImage(new Uri(imageIcon.BaseUri, "Assets/file.gif"));
also you would need to set the build action to "Content" rather than Embedded Resource... otherwise you need to use the ms-resource:// protocol.
I know this is old but I hope this helps. I wrote this in XAML and it worked for me. The Ide I'm using is vs-2015 with win-10.
<Window>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="NameOfYourImage.JPG or any Image type"/>
</Grid.Background>
<GroupBox x:Name="groupBox" Header="GroupBox" HorizontalAlignment="Left" Height="248" Margin="58,33,0,0" VerticalAlignment="Top" Width="411">
<GroupBox.Background>
<ImageBrush ImageSource="NameOfYourImage.JPG or any Image type"/>
</GroupBox.Background>
</GroupBox>
</Grid>
</Window>
MVVM ;)
public static ImageSource SetImageSource(string uriPath)//.com/image or some path
{
// this method very good for mvvm ;)
try
{
//In Model - public ImageSource AccountPhoto { get; set; }
//AccountPhoto = SetImageSource("some path");
return return new BitmapImage()
{
CreateOptions = BitmapCreateOptions.IgnoreImageCache,
UriSource = new Uri(uriPath)
};
}
catch
{
Debug.WriteLine("Bad uri, set default image.");
return return new BitmapImage()
{
CreateOptions = BitmapCreateOptions.IgnoreImageCache,
UriSource = new Uri("ms-appx:///Avatar/Account Icon.png")
};
}
}