I'm trying to create a page where you get an overview of the sponsors of the project, the data is fetched from the database with the following service:
[OperationContract]
public IEnumerable<Sponsor> getSponsors()
{
var query = (from p in dc.Sponsors select p);
IEnumerable<Sponsor> i = query;
return i;
}
When I put my breakpoint on the i I can see that the data is correctly in there.
In my Sponsorspage I do the following
public partial class Sponsorspage : UserControl
{
IEnumerable<Sponsor> sponsors = null;
public Sponsorspage()
{
SponsorsServiceClient client = new SponsorsServiceClient();
client.getSponsorsCompleted +=new EventHandler<getSponsorsCompletedEventArgs>(client_getSponsorsCompleted);
client.getSponsorsAsync();
InitializeComponent();
}
void client_getSponsorsCompleted(object sender, getSponsorsCompletedEventArgs e)
{
if (e.Error != null)
MessageBox.Show(e.Error.ToString());
else
{
sponsors = e.Result;
foreach (Sponsor s in sponsors)
{
SponsorView control = new SponsorView(s.tekst);
SLWrapPanel.Children.Add(control);
}
}
}
For each sponsor in the database, I create the Sponsorview to which I give the source and text. You can see the code for my Sponsorview here.
public partial class SponsorView : UserControl
{
public SponsorView(string tekst)
{
txtSponsor.Text = tekst;
//Uri uri = new Uri(imageSource, UriKind.Relative);
//ImageSource imgSource = new BitmapImage(uri);
//imgSponsor.Source = imgSource;
InitializeComponent();
}
}
But when I run the page, I get the following error:
Object reference not set to an instance of an object.
at OndernemersAward.Views.SponsorView..ctor(String tekst)
at OndernemersAward.Views.Sponsorspage.client_getSponsorsCompleted(Object sender, getSponsorsCompletedEventArgs e)
at OndernemersAward.SponsorsServiceReference.SponsorsServiceClient.OngetSponsorsCompleted(Object state)
What I'm trying to do is give information (here string tekst) from the sponsor s to my user control, which it then uses to fill a textblock. Am I doing this wrong or?
Thanks! :)
Well, you're trying to iterate over results that you are supposed to hold in sponsors variable. However, please note that you're calling asynchronus version (and the only one available in Silverlight, as I recall) of getSponsors method. What it means is, you will not get results immediately after calling service method, but instead you need to wait until event with completed execution will be called.
I don't know why such thing could create some problems with debug, but it's definitely error in code that could result in problems with showing the page.
Here is very simple example on how you should retrieve result from service. Hope this will help you notice error in your approach.
Related
Wierd behaviour when passing values to and from second form.
ParameterForm pf = new ParameterForm(testString);
works
ParameterForm pf = new ParameterForm();
pf.testString="test";
doesn't (testString defined as public string)
maybe i'm missing something? Anyway I'd like to make 2nd variant work properly, as for now - it returns null object reference error.
Thanks for help.
Posting more code here:
calling
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(doc.GetElementById(ParametersButton.Tag.ToString()));
pf.ShowDialog(this);
pf.test = "test";
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
};
definition and use
public partial class ParameterForm : Form
{
public string test;
public XmlElement node;
public delegate void ParameterSubmitResult(object sender, XmlElement e);
public event ParameterSubmitResult Submit;
public void SubmitButton_Click(object sender, EventArgs e)
{
Submit(this,this.node);
Debug.WriteLine(test);
}
}
result:
Submit - null object reference
test - null object reference
pf.ShowDialog(this); is a blocking call, so pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit); is never reached: switch the order.
Submit(this,this.node); throws a null object reference because no event is assigned to it (see above). Generally, you should always check first: if (Submit != null) Submit(this,this.node);
You should change ``pf.ShowDialog(this);topf.Show(this);` so that your main form isn't disabled while your dialog box is open, if that's what you want, or use the model below (typical for dialog boxes.)
I'm not sure what pf_Submit is supposed to do, so this might not be the best way to go about it in your application, but it's how general "Proceed? Yes/No" questions work.
Button ParametersButton = new Button();
ParametersButton.Click += delegate
{
ParameterForm pf = new ParameterForm(testString);
pf.ShowDialog(this); // Blocks until user submits
// Do whatever pf_Submit did here.
};
public partial class ParameterForm : Form
{
public string test; // Generally, encapsulate these
public XmlElement node; // in properties
public void SubmitButton_Click(object sender, EventArgs e)
{
Debug.WriteLine(test);
this.Close(); // Returns from ShowDialog()
}
}
When you want to use your second variant, you have to use a getString()-Method, where you can put the e.g. "testString". The way you wrote it, "testString" should be a method (and got brackets).
EDIT (a bit more precise):
You could write:
pf.getString(testString);
, if "pf" is an instance of your own class, otherwise you had to look up, whether you can retrieve a String in this class.
the thing was in line order :)
pf.Submit += new ParameterForm.ParameterSubmitResult(pf_Submit);
and
pf.Test = "test";
should have been set before
pf.ShowDialog(this);
my mistake thingking that parameter can be passed after 2nd form was displayed
thnx for answers
I am using aCefSharp.Wpf.ChromiumWebBrowser (Version 47.0.3.0) to load a web page. Some point after the page has loaded I want to get the source code.
I have called:
wb.GetBrowser().MainFrame.GetSourceAsync()
however it does not appear to be returning all the source code (I believe this is because there are child frames).
If I call:
wb.GetBrowser().MainFrame.ViewSource()
I can see it lists all the source code (including the inner frames).
I would like to get the same result as ViewSource(). Could some one point me in the right direction please?
Update – Added Code example
Note: The address the web browser is pointing too will only work up to and including 10/03/2016. After that it may display different data which is not what I would be looking at.
In the frmSelection.xaml file
<cefSharp:ChromiumWebBrowser Name="wb" Grid.Column="1" Grid.Row="0" />
In the frmSelection.xaml.cs file
public partial class frmSelection : UserControl
{
private System.Windows.Threading.DispatcherTimer wbTimer = new System.Windows.Threading.DispatcherTimer();
public frmSelection()
{
InitializeComponent();
// This timer will start when a web page has been loaded.
// It will wait 4 seconds and then call wbTimer_Tick which
// will then see if data can be extracted from the web page.
wbTimer.Interval = new TimeSpan(0, 0, 4);
wbTimer.Tick += new EventHandler(wbTimer_Tick);
wb.Address = "http://www.racingpost.com/horses2/cards/card.sd?race_id=644222&r_date=2016-03-10#raceTabs=sc_";
wb.FrameLoadEnd += new EventHandler<CefSharp.FrameLoadEndEventArgs>(wb_FrameLoadEnd);
}
void wb_FrameLoadEnd(object sender, CefSharp.FrameLoadEndEventArgs e)
{
if (wbTimer.IsEnabled)
wbTimer.Stop();
wbTimer.Start();
}
void wbTimer_Tick(object sender, EventArgs e)
{
wbTimer.Stop();
string html = GetHTMLFromWebBrowser();
}
private string GetHTMLFromWebBrowser()
{
// call the ViewSource method which will open up notepad and display the html.
// this is just so I can compare it to the html returned in GetSourceAsync()
// This is displaying all the html code (including child frames)
wb.GetBrowser().MainFrame.ViewSource();
// Get the html source code from the main Frame.
// This is displaying only code in the main frame and not any child frames of it.
Task<String> taskHtml = wb.GetBrowser().MainFrame.GetSourceAsync();
string response = taskHtml.Result;
return response;
}
}
I don't think I quite get this DispatcherTimer solution. I would do it like this:
public frmSelection()
{
InitializeComponent();
wb.FrameLoadEnd += WebBrowserFrameLoadEnded;
wb.Address = "http://www.racingpost.com/horses2/cards/card.sd?race_id=644222&r_date=2016-03-10#raceTabs=sc_";
}
private void WebBrowserFrameLoadEnded(object sender, FrameLoadEndEventArgs e)
{
if (e.Frame.IsMain)
{
wb.ViewSource();
wb.GetSourceAsync().ContinueWith(taskHtml =>
{
var html = taskHtml.Result;
});
}
}
I did a diff on the output of ViewSource and the text in the html variable and they are the same, so I can't reproduce your problem here.
This said, I noticed that the main frame gets loaded pretty late, so you have to wait quite a while until the notepad pops up with the source.
I was having the same issue trying to get click on and item located in a frame and not on the main frame. Using the example in your answer, I wrote the following extension method:
public static IFrame GetFrame(this ChromiumWebBrowser browser, string FrameName)
{
IFrame frame = null;
var identifiers = browser.GetBrowser().GetFrameIdentifiers();
foreach (var i in identifiers)
{
frame = browser.GetBrowser().GetFrame(i);
if (frame.Name == FrameName)
return frame;
}
return null;
}
If you have a "using" on your form for the module that contains this method you can do something like:
var frame = browser.GetFrame("nameofframe");
if (frame != null)
{
string HTML = await frame.GetSourceAsync();
}
Of course you need to make sure the page load is complete before using this, but I plan to use it a lot. Hope it helps!
Jim
I am consuming a web service so I added service reference to my application.
I need to display the data on listBox. for this I only wrote the following code but its not working and I keep getting an error. My code is
public Antocids()
{
InitializeComponent();
ObservableCollection<Class1> p = new ObservableCollection<Class1>();
ServiceReference3.ProductsClient client = new ServiceReference3.ProductsClient();
client.getProdDetailsCompleted += new EventHandler<ServiceReference3.getProdDetailsCompletedEventArgs>(client_getProdDetailsCompleted);
client.getProdDetailsAsync();
}
private void client_getProdDetailsCompleted(object sender, ServiceReference3.getProdDetailsCompletedEventArgs e)
{
ObservableCollection<Class1> p = e.Result; //here I'm getting the error
listBox1.DataContext=p;
}
please tell me the exact procedure
I guess that your service reference does not return a result of type ObservableCollection<Class1>. In that case it makes no sense to treat it as such. What you should instead do is add the elements to an ObservableCollection when you receive your result:
ObservableCollection<Class1> p = new ObservableCollection<Class1>();
public Antocids()
{
InitializeComponent();
listBox1.DataContext=p;
ServiceReference3.ProductsClient client = new ServiceReference3.ProductsClient();
client.getProdDetailsCompleted += new EventHandler<ServiceReference3.getProdDetailsCompletedEventArgs>(client_getProdDetailsCompleted);
client.getProdDetailsAsync();
}
private void client_getProdDetailsCompleted(object sender, ServiceReference3.getProdDetailsCompletedEventArgs e)
{
p.Clear(); // assuming you want to clear the data each time you get a new result
foreach(var result in e.Result)
p.Add(result) // assuming that e.Result holds an IEnumerable of Class1.
}
If your service doesn't return some sort of collection of type Class1, then you will need to manually parse it into Class1 and then add it to the observable collection.
I'm beginner with C# and wp7 platform and I have some problem with good idea to get request from web service.
I made webservice in PHP (nusoap - WSDL) and everything is working fine in "normal" using.
Now I have ObservableCollection saved in IsolatedStorage with I load when Page is open (List of watched stacks exchange). Then I want to refresh data for every item from web service.
I don't know whether this is a good idea.
Code:
private GPWWebservicePortTypeClient client = new GPWWebservicePortTypeClient();
private ObservableCollection<WebServiceClass.ItemGetValues> StoredStock =
new ObservableCollection<WebServiceClass.ItemGetValues>();
public const string _fileName = "listaObserwowanych.xml";
public Page()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(Page_Loaded);
client.GetLastValueCompleted +=
new EventHandler<GetLastValueCompletedEventArgs>(client_GetLastValueCompleted);
foreach (var itemGetValuese in App.ViewModel.Items)
{
client.GetLastValueAsync(itemGetValuese.name);
}
var o =
Observable.FromEvent<GetLastValueCompletedEventArgs(client,"GetLastValueCompleted")
.Subscribe(setList);
}
void client_GetLastValueCompleted(object sender, GetLastValueCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(Convert.ToString(e.Error));
}
else
{
ObservableCollection<WebServiceClass.ItemGetValues> ListValues =
(ObservableCollection<WebServiceClass.ItemGetValues>)
JsonConvert.DeserializeObject(e.Result,
typeof(ObservableCollection<WebServiceClass.ItemGetValues>));
StoredStock.Add(ListValues[0]);
}
}
private void setList(IEvent<GetLastValueCompletedEventArgs> ex)
{
List.ItemsSource = StoredStock;
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
App.ViewModel.LoadData();
List.ItemsSource = App.ViewModel.Items;
}
Like u see I use RX to call method client_GetLastValueCompleted add store result to auxiliary variable (StoredStock). Then refresh List in setList method, but that method is client_GetLastValueCompleted what is not soo good idea, becouse I need to run that method only when all of runned GetLastValueAsync in foreach is completed.
Second problem: becouse of async web service method StoredStock sometime have different order than App.ViewModel.Items .
Any good idea how to do that in right way?
Best regards,
Lukas
You're really mixing up a number of ways to call web services and Rx. You really need to decide on a single way and stick to it.
If you're going to use Rx, then you'll have something like this:
public Page()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
App.ViewModel.LoadData();
var storedStock =
new ObservableCollection<WebServiceClass.ItemGetValues>();
List.ItemsSource = storedStock;
var values =
Observable.Using<WebServiceClass.ItemGetValues, GPWWebservicePortTypeClient>
(() => new GPWWebservicePortTypeClient(), ws =>
{
var clientGetLastValue = Observable
.FromAsyncPattern<string, GetLastValueResponse>
(ws.BeginGetLastValue, ws.EndGetLastValue);
Func<string, WebServiceClass.ItemGetValues> deserializeFirst = r =>
((List<WebServiceClass.ItemGetValues>)JsonConvert
.DeserializeObject(r,
typeof(List<WebServiceClass.ItemGetValues>)))
.First();
return
from item in App.ViewModel.Items
from e in clientGetLastValue(item)
select deserializeFirst(e.Result);
});
values.Subscribe(storedStock.Add);
}
You'll have to get the right method call names for your web service client, but the code should roughly be right. Let me know how you go.
I corrected the code above. Should have returned the query inside the Using call rather than assign it to values.
I corrected the call to FromAsyncPattern to use the correct method names and return type from the actual web service reference class sent via email.
It should look like this:
Observable.FromAsyncPattern<string, GetLastValueResponse>
(ws.BeginGetLastValue, ws.EndGetLastValue);
If you're a beginner with C#, try to avoid RX for the time being. It is a cool technology, but if you use it without clear understanding of what is going on, it will bring more problems than solve.
Use a simple event, and when each async item arrives, locate and update the correspondent one in the stored list.
The Scenario
Currently I have a C# Silverlight Application That uses the domainservice class and the ADO.Net Entity Framework to communicate with my database. I want to load a child window upon clicking a button with some data that I retrieve from a server-side query to the database.
The Process
The first part of this process involves two load operations to load separate data from 2 tables. The next part of the process involves combining those lists of data to display in a listbox.
The Problem
The problem with this is that the first two asynchronous load operations haven't returned the data by the time the section of code to combine these lists of data is reached, thus result in a null value exception.....
Initial Load Operations To Get The Data:
public void LoadAudits(Guid jobID)
{
var context = new InmZenDomainContext();
var imageLoadOperation = context.Load(context.GetImageByIDQuery(jobID));
imageLoadOperation.Completed += (sender3, e3) =>
{
imageList = ((LoadOperation<InmZen.Web.Image>)sender3).Entities.ToList();
};
var auditLoadOperation = context.Load(context.GetAuditByJobIDQuery(jobID));
auditLoadOperation.Completed += (sender2, e2) =>
{
auditList = ((LoadOperation<Audit>)sender2).Entities.ToList();
};
}
I Then Want To Execute This Immediately:
IEnumerable<JobImageAudit> jobImageAuditList
= from a in auditList
join ai in imageList
on a.ImageID equals ai.ImageID
select new JobImageAudit
{
JobID = a.JobID,
ImageID = a.ImageID.Value,
CreatedBy = a.CreatedBy,
CreatedDate = a.CreatedDate,
Comment = a.Comment,
LowResUrl = ai.LowResUrl,
};
auditTrailList.ItemsSource = jobImageAuditList;
However I can't because the async calls haven't returned with the data yet...
Thus I have to do this (Perform the Load Operations, Then Press A Button On The Child Window To Execute The List Concatenation and binding):
private void LoadAuditsButton_Click(object sender, RoutedEventArgs e)
{
IEnumerable<JobImageAudit> jobImageAuditList
= from a in auditList
join ai in imageList
on a.ImageID equals ai.ImageID
select new JobImageAudit
{
JobID = a.JobID,
ImageID = a.ImageID.Value,
CreatedBy = a.CreatedBy,
CreatedDate = a.CreatedDate,
Comment = a.Comment,
LowResUrl = ai.LowResUrl,
};
auditTrailList.ItemsSource = jobImageAuditList;
}
Potential Ideas for Solutions:
Delay the child window displaying somehow?
Potentially use DomainDataSource and the Activity Load control?!
Any thoughts, help, solutions, samples comments etc. greatly appreciated.
First of there is no point in delaying the display of a window. Instead you should design your code to be able to handle asynchronous updates to the data. In this case you have a somewhat interesting situation where you are performing two asynchronous load operations and you are only able to create the data for display when both operations have completed.
One solution to this problem is to move the query where you combine the data to the server side. Then instead of retrieving Image and Audit objects from the server in two separate operations you can retrieve JobImageAudit objects.
Another solution is to create something similar to a view-model for the data you retrieve. Here is a rough sketch to get you started:
public class JobImageAuditViewModel : INotifyPropertyChanged {
IEnumerable<Image> images;
IEnumerable<Audit> audits;
IEnumerable<JobImageAudit> jobImageAudits;
public void GetData() {
this.images = null;
this.audits = null;
this.jobImageAudits = null;
OnPropertyChanged("JobImageAuditList");
// Load images by using GetImageByIDQuery()
// Load audits by using GetAuditByJobIDQuery()
}
void LoadImageCompleted(Object sender, EventArgs e) {
// Store result of query.
this.images = ...
UpdateJobImageAuditList();
}
void LoadAuditCompleted(Object sender, EventArgs e) {
// Store result of query.
this.audits = ...
UpdateJobImageAudits();
}
void UpdateJobImageAudits() {
if (this.images != null && this.jobs != null) {
// Combine images and audits.
this.jobImageAudits = ...
OnPropertyChanged("JobImageAudits");
}
}
public IEnumerable<JobImageAudit> JobImageAudits {
get {
return this.jobImageAudits;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(String propertyName) {
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
You then have to databind auditTrailList.ItemsSource to JobImageAuditViewModel.JobImageAudits. You can do this by setting the DataContext of the ChildWindow or UserControl that contains auditTrailList to an instance of JobImageAuditViewModel and add this attribute to the auditTrailList XAML:
ItemsSource="{Binding JobImageAudits}"
Actually the .NET RIA framework is designed to let the client-side generated entitiy classes assume the role of the view-model in an MVVM application. They can be extended on the client side and they support INotifyPropertyChanged. However, in your case you are using an entity on the client side that doesn't exist on the server side. Combining my first suggestion with data-binding is probably the ultimate solution to your problem.