UWP fill a List via Webservice - c#

Im currently trying to fill a List in my UWP Project with data from a Webservice.
I have testet this code:
public void test()
{
BasicHttpBinding basicAuthBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportCredentialOnly);
basicAuthBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress basicAuthEndpoint = new EndpointAddress("myURI");
LiveOdi.getODI_v1_PortTypeClient ptc = new LiveOdi.getODI_v1_PortTypeClient(basicAuthBinding, basicAuthEndpoint);
ptc.ClientCredentials.UserName.UserName = "myUsername";
ptc.ClientCredentials.UserName.Password = "myPasswort";
ptc.InnerChannel.OperationTimeout = new TimeSpan(0, 0, 1);
string = ptc.getODIAsync("1").ToString();
}
private void button_Click(object sender, RoutedEventArgs e)
{
test();
textBlock.Text = string;
}
When I click the button to receive the data and display it , my Textblock only displays :
System.Threading.Tasks.TaskĀ“1[Test.LiveOdi.getODIResponse]
The same code works fine in forms with datagrid.datasource set to ptc.GetODI("1").
Edit :
Due to a bug (https://social.msdn.microsoft.com/Forums/sqlserver/en-US/84024ccf-7ef2-493e-a7bb-c354f42a354d/does-uwp-10-support-soap-services?forum=wpdevelop) I cannot use this approach anymore.
Can someone name an alternativ ?

ptc.getODIAsync("1") is async, and is returning a Task. That's why it's being displayed in the TextBox (as your code calls ToString on the Task).
You'll likely need to follow the async/await pattern so that you can get the response.
public async Task<string> test()
{
// put all of the web service setup code here, then:
string result = await ptc.getODIAsync("1");
return result;
}
// add async here so that the Click event can use Tasks with await/async
private async void button_Click(object sender, RoutedEventArgs e)
{
// stuff the value when the response returns from test
textBlock.Text = await test();
}

Related

Problem Invoking operations in a Windows Form which triggers async API calls

I have a console application which either invokes a class and runs as a console application or triggers a windows form. The windows form inturn sends parameters and invokes the same operation done otherwise.
Invocation point:
static void Main(string[] args)
{
if(AppSettingsHelper.GetValue<bool>("EnableWindowsForm"))
{
System.Console.WriteLine("EnableWindowsForm is set to true - Running Windows form");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1(0));
//First Time
var form = new ReportGeneratorForm();
Application.Run(form);
}
else
{
System.Console.WriteLine("EnableWindowsForm is set to false - Running direct program in console");
PortalMonitoring monitoring = new PortalMonitoring();
monitoring.Process();
}
}
Now In Click of Button the Same Class is triggered
private void button1_Click(object sender, EventArgs e)
{
PortalMonitoring monitoring = new PortalMonitoring();
monitoring.Process(DateTime.Now); //Date as paramater- Default is null
}
If i trigger the console app, it works well.
However if i click the button the code is stuck at point of async web api call -below code
int reportID = GetReportIDAsync().Result;
private static async System.Threading.Tasks.Task<int> GetReportIDAsync()
{
var reportName = "Portal name";
var reportID = await ops.GetReportId(reportName);
LogAndWriteToConsole("Report ID Feched : " + reportID.ToString());
return reportID;
}
Kindly help me here, i think windows form doesnt seem to allow multi threads by defauly. How to fix this ?
You don't show the complete path from monitoring.Process() to GetReportIDAsync() but it needs to be async/await all the way.
The top level should look like this:
private async void button1_Click(object sender, EventArgs e)
{
// probably add a try/catch here
PortalMonitoring monitoring = new PortalMonitoring();
await monitoring.Process(DateTime.Now); //Date as paramater- Default is null
}
Your no-winforms branch shoud then use monitoring.Process().Wait()

C# - Make UI function during like a infinite loop until button pressed

i make a code in C# where i extract some records from an Access database , but i need the while going to the next iteration to depend on the click of a button. i tried with some Thread or Tasks , but it didn't worked because it blocked the UI which i need it to be seen and clickable.
Here's the code:
bool nextClick = false ;
while (readerSelect.Read())
{
// show the correct panel
if (string.Compare(readerSelect[2].ToString(), "P1") == 0)
{
// panel with type 1
textBoxP1Text1.Text = readerSelect[3].ToString();
textBoxP1Text2.Text = readerSelect[4].ToString();
pictureBoxP1Image.ImageLocation = readerSelect[6].ToString();
}
else
{
// panel with type 2
textBoxP1Text2.Text = readerSelect[5].ToString();
}
//this while need to be kind of infinite so the interation can't be processed and
//so when i need to change iteration i click the buttonNext
while (!nextClick) {
startWhile:;
MethodInvoker mi = delegate () {
if (nextClick)
{
Application.DoEvents();
// System.Windows.Forms.Application.Run();
}
};
this.Invoke(mi);
//break;
goto startWhile;
}
private void buttonNext_Click(object sender, EventArgs e)
{
// click on the next button
nextClick = true;
}
You can use a semaphore within an async task, have the button Release it during each click, and have the while loop await it each time through. Here's a quick example, using a form that has a button1 and a label1 added to it:
public partial class Form1 : Form
{
private readonly SemaphoreSlim signal = new SemaphoreSlim(0, int.MaxValue);
public Form1()
{
this.InitializeComponent();
this.RunLoop();
}
private async void RunLoop()
{
var i = 0;
while (true)
{
this.label2.Text = $"Enqueued: {this.signal.CurrentCount}";
await this.signal.WaitAsync(); // Wait button click async
await Task.Delay(1000); // Simulate work
this.label1.Text = $"Completed: {++i}";
}
}
private void button1_Click(object sender, EventArgs e)
{
this.signal.Release();
this.label2.Text = $"Enqueued: {this.signal.CurrentCount + 1}";
// Or if you want to limit the # people can queue up, then put this whole
// thing in an `if (signal.CurrentCount < myLimit)` block, and optionally
// disable the button once limit has been reached, and re-enable it right
// before the `WaitAsync` call above.
}
}
While Dax Fohl's answer works, it seems like you've got a problem in your design. I think you're violating the Single Responsibility Principle by having too much business logic going on in the Form class.
I'd recommend factoring out the business logic into its own class. Then rather than running through everything in a loop, you simply have the button click event process the next record and display the result. Here's an example of what I mean:
public partial class Form1 : Form
{
private readonly DataProcessor dataProcessor = new DataProcessor();
public Form1()
{
this.InitializeComponent();
}
private void button1Next_Click(object sender, EventArgs e)
{
this.buttonNext.Enabled = false;
this.ProcessNext();
}
private async void ProcessNext()
{
string s = await this.dataProcessor.ProcessNext();
this.textBoxP1Text1.Text = s;
this.buttonNext.Enabled = true;
}
}
public class DataProcessor
{
private readonly Random r = new Random(); // Or reader or whatever.
public async Task<string> ProcessNext() // Just using `string` as an example.
{
await Task.Delay(1000);
return this.r.Next().ToString();
}
}
I think this will be easier to understand and more maintainable in the future. When a new team member looks at semaphore stuff (or your future self), it'll be hard to understand/remember what the point of all that was. Here, you just have a local function that does one thing and is easy to follow.

Generating Report in C# causing error

I'm generating report in C# by using background worker but I'm getting this error.
Source code as follows:
I have to access my datagridview Records to access it's data.
A small window opens up in my datagridview which asks user to enter date from and to generate report, then i access back my datagridview convert into data table write in XML file and generate report.
Global Variables
// This is the form where the data lies, I'm accessing it's instance.
Records TR = new Records();
// This is the form where report will be displayed.
TReportDisplay TRD = new TReportDisplay();
// This is the report.
Treport treport1 = new Treport();
private void button1_Click(object sender, EventArgs e)
{
// FIXED HERE - 1
// FIXED - 2 IN THE ANSWER BELOW.
// Accessing my DataGridView Form Instance.
TR = Application.OpenForms.OfType<Records>().ElementAt(0);
treport1.SetDataSource(TR.ds);
TRD.crystalReportViewer2.ReportSource = treport1;
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
TRD.crystalReportViewer2.ReportSource = treport1;
ParameterFieldDefinitions Parameters;
ParameterFieldDefinition Parameter;
ParameterValues Values = new ParameterValues();
ParameterDiscreteValue DiscreteValue = new ParameterDiscreteValue();
DiscreteValue.Value = dateTimePicker1.Text;
Parameters = treport1.DataDefinition.ParameterFields;
Parameter = Parameters["fromdate"];
Values = Parameter.CurrentValues;
Values.Clear();
Values.Add(DiscreteValue);
Parameter.ApplyCurrentValues(Values);
DiscreteValue.Value = dateTimePicker2.Text;
Parameters = treport1.DataDefinition.ParameterFields;
Parameter = Parameters["todate"];
Values = Parameter.CurrentValues;
Values.Add(DiscreteValue);
Parameter.ApplyCurrentValues(Values);
}
}
catch (Exception ex) { MessageBox.Show(ex.Message.ToString(), "Message"); };
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
TRD.ShowDialog();
}
There were two issues, first of all updating progress bar from a different thread for which I got answer, another calling form instance after background worker was causing the issue, just put the variable before background worker start async and fixed.
The error message is telling you that the only way to update the controls is via the thread that the controls are running on. You are currently running on a different thread (the one for the back ground worker).
Take a look at the example in this link for another question on SO Invoke(Delegate) . You basically should have a method that you can call, to update the UI, which can check if it is on the correct thread and if it is not gets the correct thread to call it.
This is a snippet of code that was on the link parvee gave above that shows how you can do this.
public void UpdateProgress(int percentComplete)
{
if (!InvokeRequired)
{
ProgressBar.Value = percentComplete;
}
else
{
Invoke(new Action<int>(UpdateProgress), percentComplete);
}
}

wcf call completed event is not fired in correct order

In my Silverlight application, I put the WCF call in my ViewModel class.
DateTime CurrentDateTime;
internal void GetDateTime()
{
var client = new WcfClient();
client.GetCurrentDateTimeCompleted += GetCurrentDateTimeCompleted;
client.GetCurrentDateTimeAsync();
}
private void GetCurrentDateTimeCompleted(object sender, GetCurrentDateTimeCompletedEventArgs args)
{
try
{
CurrentDateTime = args.Result;
}
Then in my code behind code some.xaml.cs file. I have a checkbox clicked event.
private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
var msgBoxControl = new MessageBoxControl();
msgBoxControl.Closed -= MessageBoxYesNo_Closed;
msgBoxControl.Closed += MessageBoxYesNo_Closed;
Inside the method MessageBoxYesNo_Closed, I call the method in the ViewModel class.
private void MessageBoxYesNo_Closed(object sender, EventArgs e)
{
try
{
this.ViewModel.GetDateTime();
curDateTime = this.ViewModel.CurrentDateTime;
My question is that sometimes the line curDateTime = this.ViewModel.CurrentDateTime; is executed before wcf call completed method, so I can't get the right value.
I guess that it may be there are two threads, one is in UI, the other one is in service call? Please don't use async/await as I have to use Visual Studio 2010.
Thanks
Get the solution, just add a while loop:
this.ViewModel.GetDateTime();
while (true)
{
this.ViewModel.CurrentDateTime = DateTime.Now;
if (this.ViewModel.CurrentDateTime != DateTime.MinValue)
break;
}
curDateTime = this.ViewModel.CurrentDateTime;

Remake button method to call from constructor or any event

Is there any way how I can call method img_Tapped without tap(not when I click on UI element(button))but call it for example from constructor? I have handler to MessageReceived. If no anyone can advise how I can remake these two methods for the same function - I dont need click element these method should be performed when is app started or page loaded ...
method 1:
private async void img_Tapped(object sender, TappedRoutedEventArgs e)
{
...
mws = new MessageWebSocket();
mws.Control.MessageType = SocketMessageType.Binary;
mws.MessageReceived += MessageReceived;
await mws.ConnectAsync(server);
messageWriter = new DataWriter(mws.OutputStream);
messageWriter.WriteBytes(buff);
await messageWriter.StoreAsync();
}
method 2:
private void MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
try
{
using (DataReader reader = args.GetDataReader())
{
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
byte[] read = reader.ReadBuffer(reader.UnconsumedBufferLength).ToArray();
}
}
catch (Exception ex)
{
}
}
.
.
.
I find this but its not good because click/tap on button is still needed and I dont want it.
img.Tapped += new TappedEventHandler(my method with button parameters);

Categories

Resources