I have created a property in app.xaml ( Public Static List id {get set} )
Can i add Data (Eg: App.id.Add(user.id)) to it.
So that i can take the added data from the page and use it any navigated page (Eg: App.id[3]).
Initializing is the problem when page refreshed the data goes back to App.id[0]
Alternativ you could use the Singleton pattern here, this will ensure that the list is created and only one instance exsist.
In your App.cs file write the following:
private static List<string> _id;
public static List<string> id
{
get
{
if (_id == null)
_id = new List<string>();
return _id;
}
set
{
_id = value;
}
}
Yes you can, public properties defined in app.cs can be reached from all your pages in your app.
in your App.cs
public List<String> id = new List<string>();
// Call this method somewhere so you create some data to use...
// eg in your App() contructor
public void CreateData()
{
id.Add("ID1");
id.Add("ID2");
id.Add("ID3");
id.Add("ID4");
id.Add("ID5");
}
When you need to use it your can get the data from eg. the OnNavigateTo event handler
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Sets the data context for the page to have a list of strings
this.DataContext = ((App)Application.Current).id;
// Or you can index to the data directly
var a = ((App)Application.Current).id[2];
}
Related
I have an application that I am working on. The call to the data manager to set up looks like this:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new Japanese.MainPage();
}
public static DataManager DB
{
get
{
if (AS.dm == null)
{
AS.dm = new DataManager();
}
return AS.dm;
}
}
protected override void OnStart()
{
AS.GetSettings();
AS.selectedPhraseCount = AS.dm.GetTotalPhrasesCountForSelectedCategories();
}
In other words the datamanager is set up when it's first needed.
Can someone tell me if there is any advantage to doing this. It would seem to me to be simpler just to do a call to AS.dm = new DataManager() in the onStart event.
public partial class DataManager
{
protected static object locker = new object();
protected SQLiteConnection db1;
protected SQLiteConnection db2;
public DataManager()
{
db1 = DependencyService.Get<ISQLiteDB1>().GetConnection();
db2 = DependencyService.Get<ISQLiteDB2>().GetConnection();
You'd need to post a bit more code (for example where are dm and AS declared?) to be absolutely sure, but this method of having a static declaration with a private constructor is called the Singleton pattern and is designed to ensure that only one instance of the object (in your case the DataManager) can ever exist.
See this existing question
However, your code looks slightly odd in the OnStart because it looks like you are referencing the datamanager using the dm backing variable rather than the DM property.
Given the following ViewModel...
public class NameEntryViewModel
{
public NameEntryViewModel()
{
Branding = new Dictionary<string, string>();
Branding.Add("HeaderLabelText", "Welcome to the app");
}
public Dictionary<string, string> Branding { get; set; }
}
Bound to the page...
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Monaco.Forms.Views.NameEntryPage">
<Label Text="{Binding Branding[HeaderLabelText]}" />
</ContentPage>
When the page comes up the Label will get the text 'Welcome to the app'. This works great and fits into our plan for being able to customize and globalize our app. Then Branding dictionary is statically set in this example, but in the real world it is initialized by data from a service call.
However, should the user want to switch the language to Spanish, we would need each bound label to update to the new value. It's easy enough to reset the Branding dictionary and fill it with Spanish translations, but how can we force the controls to refresh from their bound sources?
I am trying to avoid two-way data binding here b/c we don't want the code overhead of creating a backing property for each Text property of the controls. Hence we are binding to a dictionary of values.
ANSWER
I accepted the answer below, but I didn't use a traditional property setter. Instead when a user wants to toggle a different language, we now have a centralized handler that repopulates our Dictionary and then notifies of the change to the Dictionary. We are using MVVMCross, but you can translate to standard forms...
public MvxCommand CultureCommand
{
get
{
return new MvxCommand(async () =>
{
_brandingService.ToggleCurrentCulture();
await ApplyBranding(); // <-- this call repopulates the Branding property
RaisePropertyChanged(() => Branding);
});
}
}
As #BillReiss mentioned you need to use the OnPropertyChanged event inherit the NameEntryViewModel from this class:
public class BaseViewModel : INotifyPropertyChanged
{
protected BaseViewModel ()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler (this, new PropertyChangedEventArgs (propertyName));
}
}
And create a private property that you can assign to you public property something like:
Dictionary<string, string> _branding = new Dictionary<string, string>();
public Dictionary<string, string> Branding
{
get
{
return _branding;
}
set
{
_branding = value;
OnPropertyChanged(nameof(Branding));
}
}
And with this every time you set the Branding property it will let the View know that something changed! Sometimes if you are doing this on a back thread you have to use Device.BeginInvokeOnMainThread()
In your BaseViewModel class is a method:
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null) {}
like:
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
Use SetProperty in the setter-properties of your inherited view-model class.
Then it will work.
INotifyPropertyChanged is already implemeted in BaseViewModel. So nothing to change here.
I have a ViewComponent that I need to invoke twice only! How and where can I tell the invokations count?
Currently I can use a session but I dislike using session in mvc apps! How may I achieve this?
namespace Partials.Components
{
public class MyComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
Session["invoked"]=(int)Session["invoked"]+1;
var model = new{
Website="Stack Overflow",
Url="www.http://stackoverflow.com"
};
return View("_MyComponent ", model);
}
}
}
and in my view
#Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>#Session["invoked"]</span> times</span>
You can use TempData. It persists only until the next request.
TempData["invoked"]=(int)TempData["invoked"]+1;
View:
<span>Invoked ViewComponent <span>#TempData["invoked"]</span> times</span>
Note: TempData uses session under the covers.
You can use HttpContext.Items which has the advantage of not using the session. These items are stored and shared per request, which would also fit your objective.
In your viewComponent you can add/retrieve an item as in this.Context.Items["MyComponentInvocationCount"]. Whenever the count is greater than 2 you can just return an empty content with return Content(String.Empty).
You can combine that with an extension method so you can get the count from outside that class:
[ViewComponent(Name = "MyComponent")]
public class MyViewComponent : ViewComponent
{
internal static readonly string ContextItemName = "InvocationCount";
public IViewComponentResult Invoke()
{
this.InvocationCount = this.InvocationCount + 1;
if (this.InvocationCount > 2) return Content(String.Empty);
//return your content here
return Content("Can be invoked");
}
private int InvocationCount
{
get
{
return this.Context.InvocationCount();
}
set
{
this.Context.Items[ContextItemName] = value;
}
}
}
public static class MyViewComponentExtensions
{
public static int InvocationCount(this HttpContext context)
{
var count = context.Items[MyViewComponent.ContextItemName];
return count == null ? 0 : (int)count;
}
}
Then you could use it in a view as follows:
#Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>#Context.InvocationCount()</span> times</span>
If you add the above lines 3 times in a view, you will see that the third one does not add any content.
EDIT - Using ViewComponentInvoker
I have been exploring how to implement this feature adding a custom ViewComponentInvoker.
I started by adding a new attribute that can be used to decorate ViewComponents so they are limited to a certain number of invocations per request:
public class PerRequestInvocationLimitAttribute: Attribute
{
public int PerRequestInvocationLimit { get; set; }
}
You would then create your view component as usual, the only change being adding this attribute:
[PerRequestInvocationLimit(PerRequestInvocationLimit = 2)]
public class MyViewComponent : ViewComponent
{
//implementation of view component
}
We can then create a custom IViewComponentInvoker that decorates the DefaultViewComponentInvoker.
This custom view component invoker will keep track of the number of
times a view component has been invoked in the current request.
When a view component that has the new attribute is invoked, it will only
really invoke it if the number of invocations is below the limit.
Implementing this view component invoker looks like:
public class LimitedPerRequestViewComponentInvoker : IViewComponentInvoker
{
private readonly IViewComponentInvoker _defaultViewComponentInvoker;
public LimitedPerRequestViewComponentInvoker(IViewComponentInvoker defaultViewComponentInvoker)
{
this._defaultViewComponentInvoker = defaultViewComponentInvoker;
}
public void Invoke(ViewComponentContext context)
{
if (!CanInvokeViewComponent(context)) return;
this._defaultViewComponentInvoker.Invoke(context);
}
public Task InvokeAsync(ViewComponentContext context)
{
if (!CanInvokeViewComponent(context)) return Task.WhenAll();
return this._defaultViewComponentInvoker.InvokeAsync(context);
}
private bool CanInvokeViewComponent(ViewComponentContext context)
{
// 1. Increase invocation count
var increasedCount = context.ViewContext.HttpContext.IncreaseInvocationCount(
context.ViewComponentDescriptor.ShortName);
// 2. check if there is any limit for this viewComponent, if over the limit then return false
var limitAttribute = context.ViewComponentDescriptor.Type
.GetCustomAttributes(true)
.OfType<PerRequestInvocationLimitAttribute>()
.FirstOrDefault();
if (limitAttribute != null && limitAttribute.PerRequestInvocationLimit < increasedCount)
{
return false;
}
// 3. There is no limit set or the limit has not been reached yet
return true;
}
}
It uses some extension methods to set/get the invocation count from HttpContext.Items (That you could also use in your view to get the number of times a view component was invoked)
public static class ViewComponentExtensions
{
public static int InvocationCount(this HttpContext context, string viewComponentName)
{
var count = context.Items[GetHttpContextItemsName(viewComponentName)];
return count == null ? 0 : (int)count;
}
internal static int IncreaseInvocationCount(this HttpContext context, string viewComponentName)
{
var count = context.InvocationCount(viewComponentName);
context.Items[GetHttpContextItemsName(viewComponentName)] = ++count;
return count;
}
private static string GetHttpContextItemsName(string viewComponentName)
{
return string.Format("InvocationCount-{0}", viewComponentName);
}
}
The final piece is to create a new IViewComponentInvokerFactory replacing the default one, so it creates an instance of the new custom view component invoker instead of the default one. You also need to register it on Startup.cs:
public class MyViewComponentInvokerFactory : IViewComponentInvokerFactory
{
private readonly IServiceProvider _serviceProvider;
private readonly ITypeActivatorCache _typeActivatorCache;
private readonly IViewComponentActivator _viewComponentActivator;
public MyViewComponentInvokerFactory(IServiceProvider serviceProvider, ITypeActivatorCache typeActivatorCache, IViewComponentActivator viewComponentActivator)
{
_serviceProvider = serviceProvider;
_typeActivatorCache = typeActivatorCache;
_viewComponentActivator = viewComponentActivator;
}
public IViewComponentInvoker CreateInstance(ViewComponentDescriptor viewComponentDescriptor, object[] args)
{
return new LimitedPerRequestViewComponentInvoker(
new DefaultViewComponentInvoker(_serviceProvider, _typeActivatorCache, _viewComponentActivator));
}
}
//Configure the ViewComponentInvokerFactory in Startup.ConfigureServices
services.AddTransient<IViewComponentInvokerFactory, MyViewComponentInvokerFactory>();
With all these pieces in place, you can use your view component 3 times and you will see how it will be rendered only twice:
#Component.Invoke("MyComponent")
<span>Invoked ViewComponent <span>#Context.InvocationCount("MyComponent")</span> times</span>
I prefer this solution for a few reasons:
It is based on the hooks provided by the new mvc framework.
Does not need changes to your view component, other than adding the attribute that sets the invocation limit.
It works when invoking view component asynchronously.
In JavaFX I want to check if a checkbox is selected and I want to do this using the lookup(#id) method. However this method returns a Node, which doesn't have the isSelected() method.
The code below shows the GUIController and a class Visualize it calls, where the status of the checkbox is read. I added a solution (reading the checkbox properties in GUIController and passing them to Visualize), but this is not how I want to proceed. I whish that the checkbox status is read in Visualize, because there will be many other GUI elements that I need to read so it is more compact to pass on a single object to Visualize instead of a list precomputed in GUIController.
Thank you for suggestions!
GUI Controller:
public class GUIController implements Initializable {
#FXML private AnchorPane RootPane;
#FXML private CheckBox TextCheckBox;
#Override
public void initialize(URL url, ResourceBundle rb) {
Boolean TextCheckBoxSelected = TextCheckBox.isSelected();
Visualize visualizeInstance = new Visualize();
root3D = visualizeInstance.draw(RootPane, TextCheckBoxSelected);
/* ... */
Class called by GUIController:
public class Visualize {
public Visualize() {
//
}
public Group draw(AnchorPane RootPane, Boolean TextCheckBoxSelected) {
System.out.println(RootPane.lookup("#TextCheckBox"));
System.out.println(TextCheckBoxSelected);
/* ... */
Output:
CheckBox[id=TextCheckBox, styleClass=check-box]'Text'
true
If you really want to do it this way, just downcast the result of the lookup:
public class Visualize {
// ...
public Group draw(AnchorPane rootPane) {
CheckBox textCheckBox = (CheckBox) rootPane.lookup("#TextCheckBox");
boolean selected = textCheckBox.isSelected();
// ...
}
}
If you are doing this because you need your Visualize object to respond to changes in the CheckBox's selected state, then consider passing a BooleanProperty instead, which you can observe if you need:
public class Visualize {
private BooleanProperty selectedProperty ;
public Visualize(BooleanProperty selectedProperty) {
this.selectedProperty = selectedProperty ;
// ...
}
// ...
public Group draw() {
boolean selected = selectedProperty.get();
// ...
}
}
and
Visualize visualizeInstance = new Visualize(textCheckBox.selectedProperty());
root3D = visualizeInstance.draw();
In my app, all domain classes follow the standardization:
All implement the interface IEntity
Id properties are protected*
The properties of type IList are protected and initialized in the constructor.
Below is a classic example of a domain entity:
public class CheckListItemTemplate : IEntity
{
public virtual int Id { get; protected set; }
public virtual string Text { get; set; }
public virtual CheckListItemTemplate Parent { get; set; }
public virtual IList<CheckListItemTemplate> Itens { get; protected set; }
public CheckListItemTemplate()
{
Itens = new List<CheckListItemTemplate>();
}
public void AddItem(CheckListItemTemplate item)
{
item.Parent = this;
Itens.Add(item);
}
}
*This is because the id is generated by the database and not run the risk of some developer trying to set this property.
Test project
We have a fake generic repository used in the tests:
public class Repository<T> : IRepository<T>
where T : class, IEntity
{
private readonly IDictionary<int, T> _context = new Dictionary<int, T>();
public void Delete(T obj)
{
_context.Remove(obj.Id);
}
public void Store(T obj)
{
if (obj.Id > 0)
_context[obj.Id] = obj;
else
{
var generateId = _context.Values.Any() ? _context.Values.Max(p => p.Id) + 1 : 1;
var stub = Mock.Get<T>(obj);
stub.Setup(s => s.Id).Returns(generateId);
_context.Add(generateId, stub.Object);
}
}
// ..
}
As you can see in the Store*, all test objects (of type IEntity) should be a Mock**. This is because in UI project, when we save an object NHibernate updating the property Id. In testing project we have to do this manually, and we have no way to set the property Id with a new value, so the solution was mock the entire object to the Get property Id correspond to the new Id . Exactly what does this line stub.Setup(s => s.Id).Returns(generateId).
*By convention, objects with Id <= 0 are new and Id> 0 are existing objects in the database.
**For Mock I use Moq.
Id as protected
The biggest problem occurs because of Id property and the fact that is protected.
When we talk about the designer, is a great approach but this brings huge inconvenience when we test our application.
For example, in a test that I'm writing I need my Fake repository with some data already populated.
Code
Follow me. I have the following classes (+ CheckListItemTemplate shown above.)
public class Passo : IEntity
{
public int Id { get; protected set; }
public virtual IList<CheckListItemTemplate> CheckListItens { get; protected set; }
}
public class Processo : IEntity
{
public virtual int Id { get; protected set; }
public virtual Passo Passo { get; set; }
public virtual IList<CheckListItem> CheckListItens { get; protected set; }
}
After saving the Processo, the first Passo is associated with the Processo: (sorted by Ordem field following field CreateAt)
model.Passo = PassoRepositorio.All().OrderBy(p => p.Ordem).ThenBy(p => p.CreateAt).First();
model.CheckListItens.Clear();
Parallel.ForEach(Mapper.Map<IList<CheckListItem>>(model.Passo.CheckListItens), (it) => model.AddCheckListItem(it));
This code is running whenever you save a new Processo. For any test that creates a new Processo, this code will be executed!
Test
If we have to create a test that creates a new Processo, our first goal is to populate the PassoRepositorio repository with some dummy data*, with Passos and CheckListItemTemplates specifically for the above code does not fail**.
*To populate objects with dummy data I use AutoFixture.
** Will fail if no Passo is found in the repository .First() and this Passo has no checklist Mapper.Map(model.Passo.CheckListItens).
So we need a repository of Passos and each Passo with a list of CheckListItens.
Remember that every object IEntity should be an Mock<> so we can mock property Id
First attempt
First configure my TestInitialize to populate my repository with some dummy data:
var fix = new Fixture();
var listPassos = fix.Build<Mock<Passo>>()
.Do((passo) => {
passo.SetupProperty(x => x.Nome, fix.Create<string>());
passo.SetupGet(x => x.CheckListItens).Returns(
fix.Build<CheckListItemTemplate>() // Needs to a Mock<>
.With(p => p.Texto)
.OmitAutoProperties()
.CreateMany(5).ToList()
);
})
.OmitAutoProperties()
.CreateMany(10);
foreach (var item in listPassos)
passoRepository.Store(item.Object);
Then I can run the tests:
[TestMethod]
public void Salvar_novo_processo_modificar_data_atendimento_passo_atual()
{
// Arrange
var fix = new Fixture();
var vm = fix.Create<ProcessoViewModel>();
//Act
Controller.salvar(vm); // Problem here. (For convert ProcessoViewModel to Processo I use a AutoMaper. In repository needs destination to be a Mock<Processo>
var processo = Repository.Get(p => p.DataEntrada == vm.DataEntrada && p.ProximoAtendimento == vm.ProximoAtendimento);
//Asserts
processo.Should().NotBeNull();
processo.Passo.Should().NotBeNull();
}
Questions
We create a list of 10 Passo where each Passo is actually is a Mock<>, great! But:
For each Passo have a list of 5 'Mock' items, and each Id should be 1, 2, 3, 4 and 5 (in that order). How to achieve this? How to obtain this list of IList<Mock<>> inside a Mock<> with Id already filled? That is, the configuration
passo.SetupGet(x => x.CheckListItens).Returns( ???
The responsible for creating objects in my controller, basically uses AutoMapper to convert my ViewModel object to an object that can be persisted Model in my repository:
model = Mapper.Map<TModel>(vm);
The problem is that my repository Fake can not save an object IEntity, just Mock<IEntity>. How to configure AutoMapper to always return a Mock<>?
Answer for Question 1: In case this helps, you can use a closure to maintain a running counter to use as an id. For example:
class MyTestClass
{
int _runningCounter = 0;
public void SomeTest()
{
/* ... some other code including mock creation ...*/
someMock.Setup(m => m.ReturnNewWidgetEntity())
.Returns(() => new WidgetEntity{ Id= ++_runningCounter });
}
}
Each time ReturnNewWidgetEntity is called on the mocked object, the Id property will be set to an increased number.
Answer for Question 2: I would suggest that rather than having a concrete dependency on the Mapper class, you replace this with an injected dependency on IMapperEngine. Richard Dingwall explains the technique here: http://richarddingwall.name/2009/05/07/mocking-out-automapper-with-dependency-injection/
Basically you register Mapper.Engine as the singleton implementation of IMapperEngine in your container and then in your unit tests mock it so that it gives you the required Mock<> classes.
I hope one or both of these answers at least give you food for thought. It was a bit difficult to follow your whole example, to be honest!