Any ideas on how to pass parameters to Silverlight on startup from URL QueryString?
Thank You
One approach you can take is to expose a method that can be accessed from JavaScript. So in your xaml.cs file you need to add the following to your constructor:
this.Loaded += new RoutedEventHandler(Page_Loaded);
Then add the following event handler:
void Page_Loaded(object sender, RoutedEventArgs e)
{
HtmlPage.RegisterScriptableObject("YourControlName", this);
}
and:
[ScriptableMember]
public void YourMethod(string yourData)
{
// Do your stuff here
}
Then in the ascx or aspx page where your Silverlight control is instantiated add the following JavaScript:
var silverlightControl;
function onSilverlightLoad(sender, args) {
silverlightControl = sender.getHost();
var yourData = "some data";
silverlightControl.Content.YourControlName.YourMethod(yourData);
}
It does also mean that your Silverlight control has to be instantiated via the <object... tag rather than via <asp:Silverlight...
Although Chris's method will work, it's easier to pass startup information through Silverlight's initialization parameters feature.
If all you need to do is get at key-value pairs of the query string, there is a much simpler way using the HtmlPage class:
HtmlPage.Document.QueryString["your_key"];
Related
I make a Wpf projcect which demos how to use WebView to Navigate a html file inside of the App, but fails.
The main cs file code is below:
public MainWindow()
{
this.InitializeComponent();
this.wv.ScriptNotify += Wv_ScriptNotify;
this.Loaded += MainPage_Loaded;
}
private async void Wv_ScriptNotify(object sender, Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlScriptNotifyEventArgs e)
{
//await (new MessageDialog(e.Value)).ShowAsync();
textBlock.Text = e.Value;
//返回结果给html页面
await this.wv.InvokeScriptAsync("recieve", new[] { "hehe, 我是个结果" });
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
//我们事先写好了一个本地html页面用来做测试
this.wv.Source = new Uri("ms-appx-web://Assets/index.html");
//this.wv.Source = new Uri("http://www.baidu.com");
}
And the html file index.html is inside of the project, located at Assets/index.html. Its source code is here:
https://github.com/tomxue/WebViewIssueInWpf/raw/master/WpfApp3/Assets/index.html
I put the project code onto GitHub: https://github.com/tomxue/WebViewIssueInWpf.git
If the project works well, when WebView visits the inner html file, it should show a button at first.
But I saw nothing.
More:
According to the accepted answer(Thank to Pavel Anikhouski), I changed my code as below and it now works.
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
//我们事先写好了一个本地html页面用来做测试
//this.wv.Source = new Uri("ms-appx-web://Assets/index.html");
//this.wv.Source = new Uri("http://www.baidu.com");
var html = File.ReadAllText("../../Assets\\index.html");
wv.NavigateToString(html);
}
It seems to be a known issue with WebView control in WindowsCommunityToolkit
You can use only absolute URIs to resources in members of the WebView control that accept string paths.
WebView controls don't recognize the ms-appx:/// prefix, so they can't read from the package (if you've created a package for your
application).
WebView controls don't recognize the File:// prefix. If you want to read a file into a WebView control, add code to your application that
reads the content of the file. Then, serialize that content into a
string, and call the NavigateToString(String) method of the WebView
control.
So, instead of loading a file this.wv.Source = new Uri("ms-appx-web://Assets/index.html"); try to read a local file and then navigate to the string
var html = File.ReadAllText("Assets\\index.html");
this.wv.NavigateToString(html);
It should work fine (I've seen the button and message at my end). Also, don't forget to copy Assets\index.html to the output directory (set Copy Always or Copy if newer)
How to access textBlock from another xaml window?
I have the Main Page and there is the event handler xmppClient_OnMessage. I want to do something like this:
void xmppClient_OnMessage(object sender, MessageEventArgs e)
{
this.NavigationService.Navigate(new Uri("/message.xaml", UriKind.Relative));
message.textBlock1.Text += e.Message.From + ": " + e.Message.Body;
}
you can pass the data using query parameters just like in html.
this.NavigationService.Navigate(new Uri("/message.xaml?messageid=1", UriKind.Relative));
and retrive it like this on next page
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (this.NavigationContext.QueryString.ContainsKey("messageid"))
{
//your code here
}
base.OnNavigatedTo(e);
}
You don't - by the time you navigate to another window the previous one will probably be gone (aka removed from memory). You should pass all the data you need via Navigation as query parameters or just have a static object in memory.
Intro:
I have a RIA service on Silverlight application that generates the code from the .Web app.
On a server side, I am using EF4 and a DomainService based on a EF4 model.
First example:
If I extend the DomainService with my own methods implementing IEnumerable or IQueryable the RIA generates the appropriate methods on its DomainContext class. Something like this:
public partial class SymbolicDataService
{
public IQueryable<Chemical> GetWeightedChemicals(int min, int max)
{
// ... some EF query here
}
}
RIA generates the method, so I can do something like this on Silverlight side:
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
SymbolicDataContext db = new SymbolicDataContext();
var chemicals = db.Load(db.GetWeightedChemicalsQuery(10,24), onChemicalsLoaded, false);
}
and then I respond to the loading in a onChemicalsLoaded callback function.
Second example:
If I want a method that does not return IEnumerable or IQueryable, but is a void method, I mark the DomainService's method with [Invoke] attribute:
[Invoke]
public void FlushChemical(Chemical chemical)
{
// some code that does what it does (with EF)
}
Now I can do something like:
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
SymbolicDataContext db = new SymbolicDataContext();
var chemical = db.GetWeightedChemicals(10,24).FirstOrDefault();
db.FlushChemical(chemical);
}
Third Example:
If I do:
public void ShakeChemical(Chemical chem, int timeShaking)
{
// Shake the chemical until it drops
}
RIA will create an Entity method on client side that enables me to do this:
private void btnShake_Click(object sender, RoutedEventArgs e)
{
Chemical chem = (ListBox)sender.SelectedItem as Chemical;
chem.ShakeChemical(22);
db.SaveChanges();
}
Question:
My question here is how to make the last two examples work asynchronously like the LoadOperation? In the first example, I can use callback on Load method to respond to the operation completion, but I have no idea how to make the other two functions asynchronous and I don't want my UI to block during the calls.
EDIT:
I see now that the second example's method has an overload with Action argument so I do have a callback for the second example. However, the question remains for the third example.
I'm assuming that the third scenario is updating a Chemical object in some way?? If this is the case then just look into "Named Update" methods for RIA Services. Hope this helps
In my WP7 application i'm calling and consuming a webservice with these methods:
In my page .cs file:
public void Page_Loaded(object sender, RoutedEventArgs e)
{
if (NavigationContext.QueryString["val"] == "One")
{
listAgences=JSON.callWSAgence("http://...");
InitializeComponent();
DataContext = this;
}
}
In my json class i have these methods :
public List<Agence> callWSAgence(string url)
{
WebClient webClient = new WebClient();
Uri uri = new Uri(url);
webClient.OpenReadAsync(uri);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompletedTestAgence);
return listAgences;
}
public void OpenReadCompletedTestAgence(object sender, OpenReadCompletedEventArgs e)
{
StreamReader reader = new System.IO.StreamReader(e.Result);
jsonResultString = reader.ReadToEnd().ToString();
addAgencesToList();
reader.Close();
}
public void addAgencesToList()
{
jsonResultString = json.Substring(5, json.Length - 6);
listAgences = JsonConvert.DeserializeObject<List<Agence>>(json);
}
The problem is that the OpenReadCompletedTest method in the json class is not called right after
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompletedTestAgence);
So the listAgences returned is empty.
But later OpenReadCompletedTest is called and everything works fined, but my view has already been loaded.
What can i do to have a kind of synchronous call or to reload my view after the webservice response being parsed and my list being filled.
The behaviour (problem) you are seeing is because the web request is made asynchronously.
If you want to have a separate object call the web server this will need to handle a callback to process the response or make appropriate changes itself.
Also:
- the code in the question doesn't show what the variable json is defined as. In Page_Loaded it looks like a custom class but in OpenReadCompletedTestAgence and addAgencesToList it looks like a string.
- the code in Page_Loaded sets the value of listAgences twice.
check out the following question for more information about making asychronous calls synchrously Faking synchronous calls in Silverlight WP7
I've created a Silverlight project that produces [something].xap file to package a few silverlight UserControls. I would like to manipulate that .xap file through the use of javascript in the browser to show and hide user controls based upon java script events.
Is it possible to do this?
If so any sample could or links to documentation would be appreciated.
Thanks in advance
Kevin
Here's my solution...not sure if it's the "best-practices" way...comments????
In the App class within my Silverlight application I have the following code:
private Page _page = null;
private void Application_Startup(object sender, StartupEventArgs e)
{
_page = new Page();
this.RootVisual = _page;
HtmlPage.RegisterScriptableObject("App", this);
}
Also to the App class I add a [ScriptableMember] to be called from JavaScript
[ScriptableMember]
public void ShowTeamSearch(Guid ctxId, Guid teamId)
{
_page.ShowTeamSearcher(ctxId, teamId);
}
The Page class is the default one that get's created within the Silverlight Control project, it really doesn't have any UI or logic, it's just used to swap in/out the views.
Login oLogin;
TeamSearcher oSearcher;
public Page()
{
InitializeComponent();
oLogin = new Login();
oSearcher = new TeamSearcher();
oLogin.Visibility = Visibility;
this.LayoutRoot.Children.Add(oLogin);
}
Also a method is added to show/hide the views...this could/will probably get more advanced/robust with animations etc...but this shows the basic idea:
public void ShowTeamSearcher(Guid ctxId, Guid teamId)
{
oSearcher.UserTeamId = teamId;
oSearcher.UserContextId = ctxId;
LayoutRoot.Children.Remove(oLogin);
LayoutRoot.Children.Add(oSearcher);
}
Then to invoke this in the JavaScript after assigning the id of oXaml to the instance of the silverlight host.
var slControl = document.getElementById('oXaml');
slControl.Content.App.ShowTeamSearch(sessionId, teamId);
This seems to work and isn't all that bad of a solution, but there might be something better...thoughts?
Here is a my collections of my links for this subject.
Javascript communication to
Silverlight 2.0
Silverlight
interoperability
Silverlight
and JavaScript Interop Basics