Dependency service event - xamarin.forms

I am trying to call the event handler from droid side, however it doesn't get fired. everyone else works however this event doesn't get fired. I am not sure what am I doing wrong. I have my dependency service registered at MainActivity and set dependency in my service.
public partial class MainPage : ContentPage
{
DocumentResults results;
IScanService scanService;
public MainPage()
{
InitializeComponent();
results = new DocumentResults();
BindingContext = new MainPageViewModel();
System.Diagnostics.Debug.WriteLine("test cw");
Console.WriteLine("test cw");
scanService = DependencyService.Get<IScanService>();
scanService.ResultsParsedEvent += (s, ev) => { ResultsParsed(null, ev); };
}
void Button_Clicked(System.Object sender, System.EventArgs e)
{
scanService.ScanService();
if (!String.IsNullOrWhiteSpace(test))
{
scanService.Parsing(test);
}
}
private void ResultsParsed(DocumentResults results,EventArgs e)
{
Console.WriteLine("update ");
testLbl.Text = results.Name;
}
}
My interface
public interface IScanService
{
event EventHandler ResultsParsedEvent;
string ScanService();
void Parsing(string test);
void resultsParsed(DocumentResults results, EventArgs e);
}
Droid implementation
public class RegService : IScanService
{
public event EventHandler ResultsParsedEvent;
DocumentResults results;
public string Test;
public String ScanService()
{
Test = "scan";
return Test;
}
public void Parsing(string test)
{
Test = "parsing";
var results= new DocumentResults();
results.Name = Test;
Thread thread1 = new Thread(() => resultsParsed(results,null));
System.Threading.Thread.Sleep(10);
resultsParsed(results,null);
}
public void resultsParsed(DocumentResults results, EventArgs e)
{
ResultsParsedEvent?.Invoke(results, e);
}
}

Related

xamarin.forms changing property of observablecollection does not update UI

I have an observrable collection in my class that contains checkboxes. I implemented a button to check all checkboxes at once. I tried just cycling through all elements and checking the box via binding:
void selectAll_clicked(System.Object sender, System.EventArgs e)
{
var x = sender as Button;
if (!allSelected)
{
allSelected = true;
x.Text = AppResources.DeselectAll;
foreach (var elem in contactList)
elem.isChecked = true;
}
else
{
allSelected = false;
x.Text = AppResources.SelectAll;
foreach (var elem in contactList)
elem.isChecked = false;
}
}
}
I am sure this effects the list, but the UI isnt updated at all.
How can I make sure the observablecollection "updates" visibly?
I also tried adding propertychanged handler:
private void SetList()
{
listview_contacts.ItemsSource = contactList;
contactList.CollectionChanged += items_CollectionChanged;
}
static void items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (INotifyPropertyChanged item in e.OldItems)
item.PropertyChanged -= item_PropertyChanged;
}
if (e.NewItems != null)
{
foreach (INotifyPropertyChanged item in e.NewItems)
item.PropertyChanged += item_PropertyChanged;
}
}
static void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
}
BUt this just says that the cast isnt valid...
Thank you
I was able to achieve that by altering my type like so:
public class ContactType : INotifyPropertyChanged
{
private string _name;
private bool _isChecked;
public string name
{
get => _name; set
{
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(name)));
}
}
public string phone { get; set; }
public string initials { get; set; }
public bool isChecked
{
get => _isChecked; set
{
_isChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(isChecked)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

Updating content between tabs binded by Preference

I am using a tabbed app and I have a button on one tab, when the user clicks then it increments a Preference and I want to update its value on another tab that is Binded to a label. I tried to experiment with MVVM but I couldnt figure it out.
Page 1 view:
public partial class Page1View: ContentPage
{
public Page1View()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Preferences.Set("Total", Preferences.Get("Total", 0)+1);
}
}
Page 2 Viewmodule:
public class Page2ViewModule : INotifyPropertyChanged
{
public int Total
{
get => Preferences.Get(nameof(Total), 0);
set
{
if (Preferences.Get(nameof(Total),0) == value)
return;
Preferences.Set(nameof(Total), value);
OnPropertyChanged(nameof(Total));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here's what I done with MessagingCenter. On the button click event I sent a message like this:
private void Button_Clicked(object sender, EventArgs e)
{
Preferences.Set("Total", Preferences.Get("Total", 0)+1);
MessagingCenter.Send<Page>(this, "test");
}
In the Page2 view module I added a constructor that subscribes to message:
public Page2ViewModule()
{
MessagingCenter.Subscribe<Page>(this, "test", (p) =>
{
Total = Preferences.Get(nameof(Total), 0);
});
}
And that still doesn't work. But I'm not sure would this be the best way to do it? Or is there a more efficient way?
For Jason's question: Page2 already been created and the Subscribe method execute before you call Send, I test at my side, Page2 is been created and the Subscribe method execute after you call Send, so I think it works fine using MessagingCenter to notify each page when the Preference has been updated.
Tab one Page.
private void btn1_Clicked(object sender, EventArgs e)
{
Preferences.Set("Total", Preferences.Get("Total", 0) + 1);
label1.Text = Preferences.Get("Total", 0).ToString();
MessagingCenter.Send<Page>(this, "test");
}
Tab two page.
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding Total}" />
</StackLayout>
</ContentPage.Content>
public partial class Tab2 : ContentPage
{
public Tab2()
{
InitializeComponent();
this.BindingContext = new Page2ViewModule();
}
}
public class Page2ViewModule : ViewModelBase
{
private int _Total;
public int Total
{
get { return _Total; }
set
{
_Total = value;
RaisePropertyChanged("Total");
}
}
public Page2ViewModule()
{
MessagingCenter.Subscribe<Page>(this, "test", (p) =>
{
Total = Preferences.Get("Total", 0);
});
}
}

Why not working: RelayCommand RaiseCanExecuteChanged

When I call the PressCommand.RaiseCanExecuteChanged(); in the TimerOnElapsed method, nothing happened.
What could be the problem?
(GalaSoft.MvvmLight.WPF4 v4.0.30319 and GalaSoft.MvvmLight.Extras.WPF4 v4.0.30319)
Here is my test code:
using System.Timers;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
namespace CommandTest {
public class MainWindowVM : ViewModelBase {
public MainWindowVM() {
PressCommand = new RelayCommand(
() => MessageBox.Show("Pressed"),
() => _canExecute);
PressCommand.CanExecuteChanged += (sender, args) => System.Diagnostics.Debug.WriteLine(System.DateTime.Now.ToLongTimeString() + " CanExecuteChanged");
_timer = new Timer(1000);
_timer.Elapsed += TimerOnElapsed;
_timer.Enabled = true;
}
public RelayCommand PressCommand { get; private set; }
#region Private
private void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs) {
_canExecute = !_canExecute;
PressCommand.RaiseCanExecuteChanged();
System.Diagnostics.Debug.WriteLine("At {0} enabled: {1}", elapsedEventArgs.SignalTime.ToLongTimeString(), _canExecute);
}
private readonly Timer _timer;
private bool _canExecute;
#endregion
}
}
Thank you in advance
Explanation:
The TimerOnElapsed method runs on a Worker Thread but to invoke the PressCommand.RaiseCanExecuteChanged(); must be on the UI thread.
So this is the solution, the updated TimerOnElapsed method:
private void TimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs) {
_canExecute = !_canExecute;
Application.Current.Dispatcher.Invoke(PressCommand.RaiseCanExecuteChanged);
System.Diagnostics.Debug.WriteLine("At {0} enabled: {1}", elapsedEventArgs.SignalTime.ToLongTimeString(), _canExecute);
}

ASP.NET Threads and Static class

I have created Scheduler class which is call MailBot.Start static method while ASP.NET application is started. I suspect that the code is not thread safe because some variables(maybe, not sure about this) in MailBot.Start method is mixed. Is it true?
I would like to have only one method running for the whole ASP.NET app.
void Application_Start(object sender, EventArgs e)
{
WebHelper.Scheduler(TimeSpan.FromMinutes(2), TimeSpan.FromMinutes(10), MailBot.Start);
}
public static class MailBot
{
public static void Start()
{
//The actual code...
}
}
public delegate void SchedulerEvent();
public static void Scheduler(TimeSpan firstTime, TimeSpan interval, SchedulerEvent callback)
{
var timer = new System.Timers.Timer { Interval = firstTime.TotalMilliseconds };
timer.Elapsed += delegate
{
timer.Enabled = false;
try
{
timer.Interval = interval.TotalMilliseconds;
callback();
}
finally
{
timer.Enabled = true;
}
};
timer.Start();
}

EF SingleOrDefault doesn't work on ASP.NET

I've wrote some unit-tests for my project who tests my presenters, these presenters queries an EF context with SingleOrDefault, all the unit-tests are successful. But when I run my ASP.NET application I get continuously the error "'Single' not supported by Linq to Entities?" I want to know why this behavior is kicking in? I can't find any documentation about this behavior.
I use the following code:
Presenter:
public class ManagedQueryPresenter : BasePresenterMetModel<IManagedQueriesView, ManagedQueryBeheerModel>, IWebPartPresenter
{
public ManagedQueryPresenter(IManagedQueriesView view) : base(view, new ManagedQueryBeheerModel()) { }
#region IPagePresenter Members
public void OnViewInitialize()
{
}
public void OnViewInitialized()
{
}
public void OnViewLoaded()
{
}
#endregion
public void OnManagedQueriesSelecting()
{
View.ManagedQueries = Model.GetAll();
}
public void OnManagedQueryInserted(ManagedQuery entity)
{
Model.AddManagedQuery(entity);
View.ManagedQueries = Model.GetAll();
}
public void OnManagedQueryUpdated(ManagedQuery entity)
{
Model.UpdateManagedQuery(entity);
}
public void OnManagedQueryDeleted(ManagedQuery entity)
{
Model.DeleteManagedQuery(entity);
}
}
Model:
public class ManagedQueryBeheerModel : BaseModel, IModel
{
public void AddManagedQuery(ManagedQuery entity)
{
...
}
public void DeleteManagedQuery(ManagedQuery entity)
{
...
}
public void UpdateManagedQuery(ManagedQuery entity)
{
DoEntityAction<bool>(context =>
{
ManagedQuery toUpdate = context.ManagedQueries.Include(q => q.ManagedQueryParameters).SingleOrDefault(x => x.ID == entity.ID);
...
context.SaveChanges();
return true;
});
}
public IList<ManagedQuery> GetAll()
{
return DoRepositoryAction<ManagedQuery, List<ManagedQuery>>(repository => (List<ManagedQuery>)repository.GetAll());
}
public ManagedQuery Get(long ID)
{
return DoRepositoryAction<ManagedQuery, ManagedQuery>(repository => repository.GetSingleOrDefault(x => x.ID == ID));
}
}
UnitTest:
[TestMethod()]
public void OnManagedQueryUpdatedTest()
{
IManagedQueriesView view = new MockedManagedQueriesView();
ManagedQueryPresenter target = new ManagedQueryPresenter(view);
ManagedQuery entity = ManagedQueryHelper.CreateNewRecord(target.Model);
entity.Name += "Updated";
target.OnManagedQueryUpdated(entity);
}
public static class ManagedQueryHelper
{
public static ManagedQuery CreateNewRecord(ManagedQueryBeheerModel model)
{
ManagedQuery entity = new ManagedQuery
{
Description = "Test Query",
Name = "Test",
QueryText = #"SOME QUERY",
HasOutput = true,
Category = "Test",
};
model.AddManagedQuery(entity);
return entity;
}
}
ASP.NET View (Codebehind of ascx):
public partial class ManagedQueriesUserControl : WebPartMangedUserControlWithPresenter<ManagedQueryPresenter>, IManagedQueriesView
{
protected ASPxGridView _grid;
protected ObjectContainerDataSource _ocdsManagedQueries;
#region IServicesView Members
public IList<Entities.ManagedQuery> ManagedQueries
{
set
{
_grid.ForceDataRowType(typeof(ManagedQuery));
_ocdsManagedQueries.DataSource = value;
}
}
#endregion
protected void _ocdsManagedQueries_Deleted(object sender, Microsoft.Practices.Web.UI.WebControls.ObjectContainerDataSourceStatusEventArgs e)
{
Presenter.OnManagedQueryDeleted((ManagedQuery)e.Instance);
}
protected void _ocdsManagedQueries_Updated(object sender, Microsoft.Practices.Web.UI.WebControls.ObjectContainerDataSourceStatusEventArgs e)
{
Presenter.OnManagedQueryUpdated((ManagedQuery)e.Instance);
}
protected void _ocdsManagedQueries_Inserted(object sender, Microsoft.Practices.Web.UI.WebControls.ObjectContainerDataSourceStatusEventArgs e)
{
Presenter.OnManagedQueryInserted((ManagedQuery)e.Instance);
}
protected void _ocdsManagedQueries_Selecting(object sender, Microsoft.Practices.Web.UI.WebControls.ObjectContainerDataSourceSelectingEventArgs e)
{
Presenter.OnManagedQueriesSelecting();
}
#region IWebPartView Members
public bool IsValid()
{
return Page.IsValid;
}
public string ErrorText
{
set { }
}
#endregion
}
I believe you can find the answer on this thread Error, method not supported by LINQ to Entities
I was forgotten that unittests are by default in VS2010 written in .NET 4 and my code in .NET3.5 so therefore it isn't working. In EF4 Single(OrDefault) is supported!

Resources