OpenSilver and Dispatcher.CheckAccess - c#

I am working on porting an old Silverlight application over to OpenSilver. Throughout the Silverlight code there are if( <control>.CheckAccess())... to make sure to be on the correct thread. Is my impression this check is no longer needed in OpenSilver? In other words, the following Silverlight code can be transformed into the following:
Yes, I know that callback-based async methods have been replaced with awaitable tasks. I am going to ask some questions about that conversion in my next question, here. This question is exclusively about the fate of the Dispatcher.CheckAccess
Silverlight:
private void GetNextImage()
{
var cmc = ServiceFactories.CreateCartManager();
cmc.getSlideImageCompleted += (s, e) =>
{
if (imageGrid.CheckAccess())
{
cmc_getSlideImageCompleted(s, e);
}
else
{
var args = new object[] { s, e };
imageGrid.Dispatcher.BeginInvoke(new getSlideImageCompletedDelegate(cmc_getSlideImageCompleted),
args);
}
};
var lastTime = SystemSettings.GetInstance().SlideShowData.LastImageTime;
cmc.getSlideImageAsync(string.IsNullOrEmpty(lastTime) ? null : lastTime);
}
to OpenSilver:
private void GetNextImage()
{
var cmc = ServiceFactories.CreateCartManager();
cmc.getSlideImageCompleted += (s, e) =>
{
cmc_getSlideImageCompleted(s, e);
};
var lastTime = SystemSettings.GetInstance().SlideShowData.LastImageTime;
cmc.getSlideImageAsync(string.IsNullOrEmpty(lastTime) ? null : lastTime);
}

There is no need to use Dispatcher.CheckAccess since OpenSilver is currently single threaded (it uses mono.wasm runtime which doesn't support threads yet).
However, OpenSilver keeps compatibility with Silverlight, so if you have an old Silverlight code which does the check you can just keep it (it will always return true when running in Browser).

Related

Atapi CallInfoChangeEvent not fired

I am using the TAPI 2.0 wrapper from JulMar (https://atapi.codeplex.com/) and I'm having trouble with it.
The Initialization
void initTAPI()
{
myTAPI = new TapiManager("GetCaller");
if (!myTAPI.Initialize())
{
MessageBox.Show("FAILED!");
}else
{
name = myTAPI.Lines[0].Name;
lineName = (myTAPI != null && myTAPI.Lines.Length > 0 ? name : string.Empty);
foreach(TapiLine line in myTAPI.Lines)
{
line.NewCall += this.OnNewCall;
line.Ringing += this.OnRinging;
line.CallStateChanged += this.OnCallState;
line.CallInfoChanged += this.OnCallInfo;
}
MessageBox.Show(lineName);
}
}
So I get the lineName. When I now dial a number through the program, it fires
OnCallState
private void OnCallState(object sender, CallStateEventArgs e)
{
if (InvokeRequired == true)
{
this.BeginInvoke(new EventHandler<CallStateEventArgs>(this.OnCallState), new object[] { sender, e });
return;
}
label1.Text = "Outgoing Call...";
}
But what I actually want to do is to get the number of an incoming call, but OnCallInfo does not get fired.
OnCallInfo
private void OnCallInfo(object sender, CallInfoChangeEventArgs e)
{
if (InvokeRequired == true)
{
this.BeginInvoke(new EventHandler<CallInfoChangeEventArgs>(this.OnCallInfo), new object[] { sender, e });
return;
}
label1.Text = "Incoming Call...";
}
It says somehwere, that it only works with x86, so I changed the target but still no success.
PS: I have a call manager (ProCall) installed on the same machine, that tells me when someone calls, so I should be able to get the info in c# as well?
Here is the whole code if someone is interested: http://pastebin.com/Q5W5iGun
Depending on TSP, you may get call info messages, but TAPI does not force the driver to do this. So some TSP make you get the info yourself. In the Win32 API this is done via lineGetCallInfo.
After a quick look in this atapi wrapper, this happens in the GatherCallInfo method of the TapiCall class. However I can see no way to trigger this manually in this wrapper. You would need to modify the atapi source to make this a public method.
You can use example from TAPI which do the same. The only difference is new line.Monitor() method
foreach (TapiLine line in tapiManager.Lines)
{
try
{
line.NewCall += OnNewCall;
line.CallStateChanged += OnCallStateChanged;
line.CallInfoChanged += OnCallInfoChanged;
line.Monitor();
}
catch (TapiException ex)
{
LogError(ex.Message);
}
}
For further reading read this https://atapi.codeplex.com/SourceControl/latest#Atapi/trunk/source/test/TcMon/TapiMonitorForm.cs

Disposed Forms with a Base and threading returns null for progress bar

I have a base form that I use when calling 2 forms. Previously when calling the forms I didn't dispose of them, but I have found that reusing them, they would stay in memory and not get collected. So I have instead used a using statement instead to clear the memory, and all my problem are fixed.
But now a new problem arises, one that I had previously when testing my app with mono on Linux. I though it might be a mono specific problem, but since adding the using statement the same thing happens on my Windows machine. So it might just be that the Garbage Collector on Mono is different and was disposing properly of my forms.
Here is my problem I have a thread that I start to extract files in the background And I have progress bar telling me the progress, before using the dispose if I closed the form and reopened it my files extracted correctly and the progress bar was working fine. But now they work fine the first time, but if I reopen the form or the other one that has the same base, the extraction is not working, no files are extracted because I have a null exception when reporting the progress.
private void ExtractFiles()
{
Zip.ExtractProgress += new EventHandler<ExtractProgressArgs>(Utils_ExtractProgress);
Thread t = new Thread(new ThreadStart(Zip.ExtractZip));
t.IsBackground = true;
t.Start();
FilesExtracted = true;
}
void Utils_ExtractProgress(object sender, ExtractProgressArgs e)
{
UpdateProgress(e.Pourcentage);
}
private delegate void UpdateProgressDelegate(int Pourc);
private void UpdateProgress(int Pourc)
{
lock (this)
{
if (Progress.ProgressBar.InvokeRequired)
{
UpdateProgressDelegate del = new UpdateProgressDelegate(UpdateProgress);
Progress.ProgressBar.BeginInvoke(del, Pourc);
} else
{
Progress.Value = Pourc;
}
}
}
This code is in my BaseForm, the Progress control isn't null, but all of it's properties have null exceptions. So when checking if Invoked is required it raises an Null exception.
Here is my Zip.Extract method
public static event EventHandler<ExtractProgressArgs> ExtractProgress;
static ExtractProgressArgs Progress;
internal static void ExtractZip()
{
try
{
using (ZipFile zip = ZipFile.Read(Variables.Filename))
{
Progress = new ExtractProgressArgs();
Progress.TotalToTransfer = Convert.ToInt32(zip.Sum(e => e.UncompressedSize));
zip.ExtractProgress += new EventHandler<ExtractProgressEventArgs>(zip_ExtractProgress);
Old = 0; New = 0;
foreach (ZipEntry item in zip)
{
item.Extract(Variables.TempFolder, ExtractExistingFileAction.OverwriteSilently);
}
}
} catch (Exception)
{
}
}
static long Old;
static long New;
static void zip_ExtractProgress(object sender, ExtractProgressEventArgs e)
{
if (e.EventType == ZipProgressEventType.Extracting_EntryBytesWritten)
{
New = e.BytesTransferred;
Progress.Transferred += New - Old;
Old = e.BytesTransferred;
if (ExtractProgress != null)
{
ExtractProgress(e.CurrentEntry, Progress);
}
} else if (e.EventType == ZipProgressEventType.Extracting_AfterExtractEntry)
{
Old = 0;
}
}
Might be because my Zip.Extract is static? I have almost no knowledge of multi-threading, like synchronization, etc.
The short answer is yes, some of your problems are due to the static nature of those operations.
You should be able to resolve the problem by removing the static declarations from your Zip class and then creating an instance of it as needed.

C# to VB.NET conversion error, advice requested

I am trying to translate the following C# snippet to VB:
public bool ShowHandlerDialog(string message)
{
Message = message;
Visibility = Visibility.Visible;
_parent.IsEnabled = false;
_hideRequest = false;
while (!_hideRequest)
{
// HACK: Stop the thread if the application is about to close
if (this.Dispatcher.HasShutdownStarted ||
this.Dispatcher.HasShutdownFinished)
{
break;
}
// HACK: Simulate "DoEvents"
this.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
Thread.Sleep(20);
}
return _result;
}
But the translation is giving an error on this line:
this.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
The translation is:
Me.Dispatcher.Invoke(DispatcherPriority.Background, New ThreadStart(Function() Do End Function))
Which doesnt seem to convert correctly the bit after New ThreadStart. Can somebody please explain what 'delegate {}' does in
new ThreadStart(delegate {}));
and how I might correct the translation error? Thanks for any advice!
That line simply fires up a new thread and waits for it to finish. The "delegate { }" code is simply an anonymous/inline method (I don't think that is supported in VB.NET); just as if you would point to an empty method basically. For instance, in c# event-handlers can be bound to anonymous (inline) delegate methods as so:
this.OnClick += (EventHandler)delegate(object sender, EventArgs ea) {
MessageBox.Show("Click!");
};
The comment above says [// HACK: Simulate "DoEvents"]. Just replace the two lines with DoEvents for VB.NET and you should be set. That then allows other threads to do their work before continuing, thus improving responsiveness.
Hope this helps!

problem with RX and web service collection loading wp7

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.

C# Workflow ManualWorkflowSchedulerService Multithreading Question

Hey guys, I just wanted to verify what I'm doing is correct. It came to our attention that a Windows Service had a pretty serious memory leak. I was able to track it down to how Workflow was being called. I reworked it a bit to stop the memory leak, but I wanted to validate that the code is doing what I think it is. Note I do not know the first thing about Workflow, so I'm coming to you.
Basically, the code was executing the Workflow on a thread, but was not removing the handler to WorkflowRuntime.Terminated. I am trying to ensure that the Workflow is executed asynchronously. Here are the relevant portions of code:
Checking to ensure there is only once instance of the WorkflowRuntime:
private static void _CheckRuntimeInstance()
{
lock (_padlock)
{
if (_wfRuntime == null)
{
_wfRuntime = new WorkflowRuntime();
ManualWorkflowSchedulerService schedulerService = new ManualWorkflowSchedulerService();
_wfRuntime.AddService(schedulerService);
_wfRuntime.StartRuntime();
}
}
}
Inside a static method, creating the specific WorkflowInstance to run:
_CheckRuntimeInstance();
// create the instance
WorkflowInstance instance = _wfRuntime.CreateWorkflow(typeof(WorkflowType),parameters);
instance.Start();
Guid instanceId = instance.InstanceId;
ThreadPool.QueueUserWorkItem(CallbackMethod, instanceId);
Thread callback method:
private static void DeviceLocationAssignmentCallback(Object state)
{
Guid instanceId = (Guid)state;
EventHandler<WorkflowTerminatedEventArgs> workflowTerminatedHandler = null;
EventHandler<WorkflowCompletedEventArgs> workflowCompletedHandler = null;
workflowTerminatedHandler = delegate(object sender, WorkflowTerminatedEventArgs e)
{
if (instanceId == e.WorkflowInstance.InstanceId)
{
// Remove event registration.
_wfRuntime.WorkflowTerminated -= workflowTerminatedHandler;
_wfRuntime.WorkflowCompleted -= workflowCompletedHandler;
if (e.Exception != null)
{
// Log error.
}
}
};
_wfRuntime.WorkflowTerminated += workflowTerminatedHandler;
workflowCompletedHandler = delegate(object sender, WorkflowCompletedEventArgs e)
{
if (instanceId == e.WorkflowInstance.InstanceId)
{
// Remove event registrations.
_wfRuntime.WorkflowTerminated -= workflowTerminatedHandler;
_wfRuntime.WorkflowCompleted -= workflowCompletedHandler;
}
};
_wfRuntime.WorkflowCompleted += workflowCompletedHandler;
_wfRuntime.GetService<ManualWorkflowSchedulerService>().RunWorkflow(instanceId);
}
EDIT: Changed the title of the post to get more views.

Categories

Resources