I am trying to show a web page relative to the local folder in a UWP app. This means, I have the page itself as string, but assets (images, scripts) are located in the apps local folder.
I tried to use the NavigateToString method that as I understood should serve this task, in combination with the Source-property of a WebView control.
var baseUri = new Uri("ms-appdata:///local/");
WebView.Source = baseUri;
var page = ...;
WebView.NavigateToString(page);
However, this gives me the following error message when assigning the Source-property of the web view:
Exception thrown: 'System.ArgumentException' in App.exe
Additional information: Value does not fall within the expected range.
So apparently, using the local app folder for assets is not supported?
The app targets minimum Windows 10 Build 10586.
Does anybody know whether there is a useful workaround for this?
Edit: I tried to make a minimum example. In the following, I created a small test app that does nothing but loading a static html file from the local storage. As far as I can tell, this code exactly resembles the XamlWebView example but does raise an ArgumentException.
MainPage.xaml
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<WebView Name="WebView" />
</Grid>
</Page>
MainPage.xaml.cs
using System;
using System.IO;
using Windows.Storage;
using Windows.UI.Xaml.Controls;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace App1
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
Initialize();
}
private async void Initialize()
{
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync("index.html", CreationCollisionOption.ReplaceExisting);
using (var sw = new StreamWriter(await file.OpenStreamForWriteAsync()))
{
sw.WriteLine("<html>");
sw.WriteLine("<body>");
sw.WriteLine("This is some text");
sw.WriteLine("</body>");
sw.WriteLine("</html>");
}
WebView.Navigate(new Uri("ms-appdata:///local/index.html"));
}
}
}
I do not even know where the difference to the sample is, can't find any.
WebView.Source property is ued to gets or sets the Uniform Resource Identifier (URI) source of the HTML content to display in the WebView control.
We usually set the Source property in XAML. The XAML parser automatically converts the string to a Uri. The Source property can be set in code, but rather than doing so, we typically use one of the Navigate methods such as Navigate, NavigateToString and NavigateWithHttpRequestMessage method to load content in code.
And the URI you've used in your code is not a valid URI for WebView control, so you got a Value does not fall within the expected range. error. To load content from app’s local storage, we need to place the content in a subfolder under the local folder. Ref Remarks in WebView class:
To load uncompressed and unencrypted content from your app’s LocalFolder or TemporaryFolder data stores, use the Navigate method with a Uri that uses the ms-appdata scheme. The WebView support for this scheme requires you to place your content in a subfolder under the local or temporary folder. This enables navigation to URIs such as ms-appdata:///local/folder/file.html and ms-appdata:///temp/folder/file.html . (To load compressed or encrypted files, see NavigateToLocalStreamUri.)
Each of these first-level subfolders is isolated from the content in other first-level subfolders. For example, you can navigate to ms-appdata:///temp/folder1/file.html, but you can’t have a link in this file to ms-appdata:///temp/folder2/file.html. However, you can still link to HTML content in the app package using the ms-appx-web scheme, and to web content using the http and https URI schemes.
So when you use WebView.Navigate(new Uri("ms-appdata:///local/index.html"));, you still get the error as ms-appdata:///local/index.html is also not a valid URI for WebView.
Besides, although NavigateToString supports content with references to external files such as CSS, scripts, images, and fonts. But it only supports content in the app package using the ms-appx-web scheme, and web content using the http and https URI schemes. It can't work with assets located in the apps local folder. To achieve what you want you need to put these assets into a subfolder under the local folder and then also store the html string to a file under the same subfolder. In the html, you can use relative URI to reference these assets like what in my previous answer.
Related
I have the following activity which specifies the theme as an attribute
[Activity(Label = "PermissionsActivity", Theme = "#android:style/Theme.Translucent.NoTitleBar")]
public class PermissionsActivity: Activity
This works well, but how can I apply the same at runtime? Maybe by calling SetTheme in OnCreate. I can see SetTheme accepts a resource id integer. I'm having a hard time finding the corresponding Xamarin.Android constant for the aforementioned theme. Please help
Add your theme in style.xml file under Resource folder than access it from resource as int
<style name="MyTheme" parent="Theme.Translucent.NoTitleBar">
</style>
Setting in activity
this.SetTheme(Resource.Style.MyTheme);
Add this code in your onCreate Method:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Call setTheme before creation of any(!) View.
setTheme(android.R.style.Theme_Dark);
// ...
setContentView(R.layout.main);
For reference check this Link
When you add some theme in any folder under the resources of an android project what Visual studio does is it creates a corresponding int value inside the ResourceDesigner.cs file under the resources folder.
Now in Runtime when you need to add these to your code they are available as follows:
If the resource is a style then it is available in Resource.Style.YourResourceName
If the resource is a dimension then it is available in Resource.Dimen.YourResourceName
If the resource is a string then it is available in Resource.String.YourResourceName
If the resource is an image under the drawable folder then it is available in Resource.Drawable.YourResourceName
If the resource is an image under the mipmap folder then it is available in Resource.Mipmap.YourResourceName, And so on and so forth.
Note: These properties are always an integer.
In your case since it is a theme(which is basically a style)
Hence you can get it like this in an Activity:
this.SetTheme(Resource.Style.MyTheme);
And in a Fragment something like this :
this.Activity.SetTheme(Resource.Style.MyTheme);
Hope this helps,
Revert in case of queries.
SOLVED
Accepted answer from here did the trick (using converter)
I have resources.dll which contains not one, but multiple resource files like
A.resx
B.resx
Inside A.resx I have
string TestString
image TestImage
I'm referencing this dll in my project.
Inside xaml I have namespace declared
xmlns:res="clr-namespace:Resources;assembly=Resources"
and I'm trying to get content from resource A.resx.
This one works fine, I can get string from A.resx
<Label Content="{x:Static res:A.TestString}"/>
but I can't access image like this
<Image Source="{x:Static res:A.TestImage}" />
The member TestImage is not recognised or accessible
A.resx has
access modifier set to public
build action to Embedded Resource
image persistence is set to Linked at compile time
If I can get string from it, but can't get image then I have access to resx file and I can rule out permission/access problems. So there must be something that I'm doing wrong with this image.
Question is: why I can't get image from resx file and how to get this work?
I have seen this post: Display GIF in a WP7 application with Silverlight
But in my case? for animating I am using a popup. So when application starts it shows a popup for 5 seconds. In this popup I want to show some .gif image, but it doesn't work.
Here is the code which I implement:
public partial class AnimatedSplashScreen : UserControl
{
protected Uri ImageSource
{
get;
set;
}
public AnimatedSplashScreen()
{
InitializeComponent();
ImageSource =
new Uri(
"http://upload.wikimedia.org/wikipedia/commons/thumb/3/36/Sunflower_as_GIF.gif/200px-Sunflower_as_GIF.gif",
UriKind.Absolute);
ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
}
And xaml code is:
<UserControl.Resources>
<imagetools:ImageConverter x:Key="ImageConverter" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
Width="480"
Height="800"
Background="White">
<imagetools:AnimatedImage Source="{Binding ImageSource, Converter={StaticResource ImageConverter}}" />
But in result it does't work, it shows an empty background.
Updated:
ImageTools.IO.Decoders.AddDecoder();
ImageSource = new Uri("http://a3.twimg.com/profile_images/1136683647/hisoka_normal.gif", UriKind.Absolute);
It still doesn't work
Finally working... Talk about events conspiring against you... You need to fix all these things first!
(note there is a following problem with only the first 2 frames being animated but that is for another question):
Part 6 (getting sleepy now)
Lastly relative image URLs starting with "/" are not supported by the ImageTools.Controls.ImageConverter, so you need to use a relative URL without the leading "/". I found that once every other problem was fixed I was getting an unsupported exception with the path.
ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
InitializeComponent();
this.ImageSource = new Uri("layer1.gif", UriKind.Relative);
this.DataContext = this;
Part 5
You need to set the binding DataContext somewhere.
You do not connect the XAML page DataContext to the code behind object. I could not see where you had done this. A very simple/quick way is to set this.DataContext = this; in the page's constructor.
Part 4
You can only bind to public properties!
Your ImageSource property is currently protected. Change it to Public
public Uri ImageSource
{
get;
set;
}
Part 3
I also note your ImageSource property is not an INotifyPropertyChange type property. So setting it after InitializeComponent will not work.
Try it this way round (or change it to use a notify property):
public AnimatedSplashScreen()
{
ImageSource =
new Uri(
"/200px-Sunflower_as_GIF.gif",
UriKind.Relative);
ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
InitializeComponent();
}
Part 2 (actually not support by ImageTools.Controls.ImageConverter)
The cross domain file was apparently only one problem. Based on the comments you also need to store your images on your own website and reference them with an appropriate URI format.
If you put your files in a folder called images under ClientBin you use this format:
"/images/imagename.jpg"
This is the best option as the images also use Browser caching!
For your example it would be like this:
ImageSource =
new Uri(
"/images/200px-Sunflower_as_GIF.gif",
UriKind.Relative);
ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
and put the example file in your client bin folder under images.
If you do not use the leading "/" Silverlight assumes the files are resources in the current module instead e.g.
"images/imagename.jpg"
Part 1
This is actually a copyright issue, to stop people deep-linking files from other people's sites without permission.
The Wikimedia.org site does not have any cross domain access files e.g.:
http://upload.wikimedia.org/crossdomain.xml
http://upload.wikimedia.org/crossdomainpolicy.xml
wikimedia.org/crossdomain.xml
wikimedia.org/crossdomainpolicy.xml
... presumably as they do not want others to use the files they host there outside of their own website.
That means Silverlight will not allow access to files on those sites as it is a good Internet citizen. Try hosting the files on your own site (where your Silverlight app resides), then it will not need any cross domain access file at all.
Side note: If you do ever need a cross domain file on a website, for use by Silverlight, use a crossdomainpolicy.xml as the other one is not as useful (designed for older flash use)
I have a WPF page used as an input form which contains a number of controls on one side, and a flow document reader on the other.
I want to set the content of this document reader to a specific part of a flow document which is loaded when the form is loaded, (via a loaded event).
I have found an article explaining how to do this, using fragments, but the examples shown are only expressed in XAML.
In my case I need to update the document property of the flow document reader when the user gives focus to one the controls (I have wired up the events already) therefore I need to do this in the code behind rather than XAML.
I have tried setting the document property to:
Document#Control_Sport
where Document is the name of XAML flow document and Control_Sport is the name of the fragment I need to navigate to.
However this gives an error, it doesn't like the hash sign being there.
I tried looking on MSDN but its XAML only. Is there a way I can do this through code?
Any help would be appreciated.
Felix,
Link to MSDN article: http://msdn.microsoft.com/en-us/library/ms750478.aspx#FragmentNavigation
You can navigate to any Block within a FlowDocument by calling Block.BringIntoView.
First, create a Frame object inside your Page or Window object. Setting the JournalOwnership property to "OwnsJournal" will give the document its own navigation bar (forward and back arrows plus a history). You will probably need to add additional parameters to size and locate the frame within your document as well, but I didn't include them in my example since I don't know what your app requires:
<Frame Name="MyFrame" JournalOwnership="OwnsJournal" />
Then, create a pack URI for your document fragment. This document is assumed to be in the same directory as the application's executable; you will need to add more to the path to navigate to the directory where the document resides in your project:
Uri MyUri = new Uri("pack://application:,,,/MyXamlDocument.xaml#MyFragment");
Then, navigate to it from inside your button's Click handler or whatever other means you like to initiate the navigation:
MyFrame.Navigate(MyUri);
I am currently building an application that consists of several components, each of which is essentially a WPF user control with a little C# code around it for the plugin system to work (using MEF).
The problem I am having is that each component should include an icon and for niceness purposes I defined that as a System.Windows.Media.Brush so I can just use the DrawingBrush exported from Design there. Now I need to access that piece of XAML from non-WPF C# where I currently have the horrible workaround of instantiating the user control and asking it for the resource:
private Brush CachedIcon = null;
public override Brush Icon
{
get
{
if (CachedIcon == null)
{
CachedIcon = (Brush)(new BlahControl().TryFindResource("Icon"));
}
return CachedIcon;
}
}
I couldn't find a way to read that resource (which is a .xaml file, and referenced in a ResourceDictionary in the custom control) from a "normal" C# class. Anything belonging to WPF has that nice TryFindResource method but how to do that otherwise? I don't want to have the XAML file with the icon lying around un-embedded.
In your XAML code make sure the icon resource has the build option set to "Resource", and then reference the resource to make it a xaml static resource
<UserControl.Resources>
<BitmapImage x:Key="icon1" UriSource="Resources/Icon1.ico" />
</UserControl.Resources>
Then in your .Net 2.0 code you will find the resource in the "{xamlName}.g.resource" stream
Example code that loads all icons from a xaml dll into a dictionary:
using System.IO;
using System.Reflection;
using System.Collections;
using System.Resources;
...
var icons = new Dictionary<String, Bitmap>();
var externalBaml = Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, "MyXaml.dll"));
Stream resourceStream = externalBaml.GetManifestResourceStream(externalBaml.GetName().Name + ".g.resources");
using (ResourceReader resourceReader = new ResourceReader(resourceStream)) {
foreach (DictionaryEntry resourceEntry in resourceReader) {
if (resourceEntry.Key.ToString().ToUpper().EndsWith(".ICO")) {
icons.Add(resourceEntry.Key.ToString(), Image.FromStream(resourceEntry.Value as Stream) as Bitmap);
}
}
}
My suggestions are:
Provide metadata on your control about where the icon can be found. You can do this with your own custom attribute (see example 1 below). This metadata will allow you to load the icon without creating an instance of the control.
Since you're using MEF, you can use metadata in your export to achieve the same as above. Details here. See example 2 below.
Treat your icon as an ImageSource rather than a Brush. You can use WPF's Image control to show your ImageSource, or you can paint it with an ImageBrush.
Use the technique provided by TFD to read the resource with the name specified in the metadata. Unfortunately, WPF does not appear to provide anything like a BamlReader, which would make it much cleaner to load the WPF resource from a non-WPF context.
Example 1:
[Icon("MyIconResourceName")]
public class BlahControl : Control
{
...
}
Example 2:
[Export(typeof(IApplicationComponent))]
[ExportMetadata("IconResource", "MyIconResourceName")]
public class BlahControl : Control
{
...
}
You can read resources from your assembly as stream.
Example code here:
http://www.wpftutorial.net/ReadWPFResourcesFromWinForms.html
Define the icons at the app level instead of in the control, either in the app.xaml or a master resource dictionary xaml file. Then you can use the same TryFindResource method, but without creating an instance of the control.