I have a list of objects that should be passed to another view but I don't know how I can do that in Xamarin.forms, I think I should to use setBinding, but its the only thing I say in this case.
Thank you.
List<Localizacao> localizacaoList = new List<Localizacao>(); ;
if (localizacao != null && lojaPerto != null)
{
localizacaoList = new List<Localizacao>();
Localizacao loc = new Localizacao();
loc.latitude = Double.Parse(lojaPerto.latitude);
loc.longitude = Double.Parse(lojaPerto.longitude);
localizacaoList.Add(loc);
localizacaoList.Add(localizacao);
}
var secondPage = new Views.ComoChegarView ();
secondPage.BindingContext = localizacaoList;
await Navigation.PushAsync(secondPage);
In fact, I sent, but I can't get it again in the other view
If you are not using any additional framework, maybe you can try using constructor parameters.
public partial class ComoChegarView
{
...
private List<Localizacao> Locals{get;set;}
public ComoChegarView(List<Localizacao> locals)
{
InitializeComponent(); //standard code that mix xaml and code behind
this.Locals = locals; //store the data in property
this.BindingContext = this; //Set the binding context
}
}
So you can pass the value when you construct the page.
List<Localizacao> localizacaoList = new List<Localizacao>(); ;
if (localizacao != null && lojaPerto != null)
{
localizacaoList = new List<Localizacao>();
Localizacao loc = new Localizacao();
loc.latitude = Double.Parse(lojaPerto.latitude);
loc.longitude = Double.Parse(lojaPerto.longitude);
localizacaoList.Add(loc);
localizacaoList.Add(localizacao);
}
var secondPage = new Views.ComoChegarView (localizacaoList);
await Navigation.PushAsync(secondPage);
Remember that update your binding in XAML to reflect property access (for example)
<ListView ItemsSource="{Binding Locals}">...</ListView>
What you want to achieve is perfectly supported by all serious MVVM libraries.
1) a view do not pass anything to another view, it is the job of the ViewModels
2) in a MVVM context you can use many techniques to send ou pass data from one ViewModel to another, the main being : MVVM messenger (there's one include in Xamarin.Forms) or dependency injection in the the ViewModel constructor (using an IoC container what most MVVM libraries are offering, using Unity, DryIoc, ...).
It is certainly hard to do if you do not master MVVM pattern but you should take a little time to study this pattern and some libraries as Prism. You will quickly see the benefit of such an approach and will be very happy to write code more efficiently (and find in a minute quick and clean solutions to problems like the one you're talking about here).
Related
The application is using mvvm as well as it can at the moment. Currently the application uses binding in every view. There is a basecontrol class that handles the propertychange currently and uses a global property (ParentProperty). When I try to convert a command to an event, this global property I have is null when the "event" method is hit, but not null when using a command flow with classic bindings. I've set the context in the code behind, and the clicking of the button reaches the method it needs to. It's just I have a property that isn't getting its values when trying to use xbind, over binding/commands.
For the most part I understand and see that xbind works with simple instances, but the event part of it has me scratching my head. The code below is a simple navigation event to another page, where we will be adding a new record. This code works fine using a command, but when trying to do x:bind, the parentproperty is null.
The one difference between the command and event is the Model model = new Model(); in the event method is Model model = obj as Model(); in the command. which takes in a object obj argument.
AddEditView control = new AddEditView();
control.ParentProperty = ParentProperty;
Model model = new Model();
if (Model == null)
{
Model = new Model () { };
}
Model.ParentPropertiesType = ParentProperty ;
control.ModelDetailsForAddEdit = Model;
control.PropertyChanged += ModelDetailsForAddEdit_PropertyChanged;
Utility u = new Utility();
NavigationUtility.ShowDetailPage(ParentProperty.Id, u.GetInitializedControl(control, ParentProperty, 0), "View", "Add View");
Having a very difficult time trying to use pure DI (i.e. no framework) with WPF following MVVM. I have Mark Seemann's book; however, his solution to this seems pretty similar to what I've come up with:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
string connectionString = #"Server=(localdb)\MSSQLLocalDB;Database=RouteMiningDB;Trusted_Connection=True;";
RouteMiningDAL.RouteMiningDataContext db = new RouteMiningDAL.RouteMiningDataContext(new DbContextOptionsBuilder().UseSqlServer(connectionString).Options);
IZIPCodeInfoRepository zipCodeRepo = new RouteMiningDAL.SQLZIPCodeInfoRepository(db);
ZIPCodeInfoService zipCodeInfoService = new ZIPCodeInfoService(zipCodeRepo);
ZIPCodeInfoViewModel zipCodeInfoViewModel = new ZIPCodeInfoViewModel(zipCodeInfoService);
ZIPCodeInfoView zipCodeInfoView = new ZIPCodeInfoView(zipCodeInfoViewModel);
MainWindow mainWindow = new MainWindow();
mainWindow.Content = zipCodeInfoView;
mainWindow.Show();
}
}
Per other resources, as well as Mark's book, OnStartup is used as the Composition Root. All seems well above, however, I feel very limited as to what I can do. For example, I have set the ZIPCodeInfoView to the mainWindow.Content. Obviously with many child Windows such as:
This presents some challenges with layout because I can't really just set it to xxxx.Content (I can I guess, but I don't want to construct the layout in code). How do I go about this? Am I overlooking the ability to do this in XAML? It seems XAML needs a parameterless constructor which obviously does not work for DI's Constructor Injection. Thanks!
Disclaimer: I want to use pure DI.
Nice that you would like to use pure DI. Your question is good. I hoped that the 2nd edition of the book would answer it. It didn't have a plain example/answer for that if I recall it correctly.
However, the idea of Pure DI is that all the dependencies are visible (using construction injection) up front in the app entry point a.k.a. the composition root.
In your case I would chain it up in the following way:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
string connectionString = #"Server=(localdb)\MSSQLLocalDB;Database=RouteMiningDB;Trusted_Connection=True;";
RouteMiningDAL.RouteMiningDataContext db = new RouteMiningDAL.RouteMiningDataContext(new DbContextOptionsBuilder().UseSqlServer(connectionString).Options);
IZIPCodeInfoRepository zipCodeRepo = new RouteMiningDAL.SQLZIPCodeInfoRepository(db);
ZIPCodeInfoService zipCodeInfoService = new ZIPCodeInfoService(zipCodeRepo);
StockHistoryService stockHistoryService = StockHistoryService();
StockHistoryViewModel stockHistoryViewModel = new StockHistoryViewModel(stockHistoryService);
ZIPCodeInfoViewModel zipCodeInfoViewModel = new ZIPCodeInfoViewModel(zipCodeInfoService, stockHistoryViewModel);
ZIPCodeInfoView zipCodeInfoView = new ZIPCodeInfoView(zipCodeInfoViewModel);
MainWindow mainWindow = new MainWindow();
mainWindow.Content = zipCodeInfoView;
mainWindow.Show();
}
}
In that way the main window depends on the StockHistoryViewModel which depends on the StockHistoryService.
For some view model (pop-up/modal window etc) I would use factory pattern with DI so that view model would be created only when/if needed. But it hides the view model's dependecies...
Dependency Injection vs Factory Pattern
This may be a noobish question, but in my records in Coded UI Tests, I have recorded a lot of controls that don't have enough defined properties to be found in playback.
For exemple:
public HtmlEdit UIItemEdit
{
get
{
if ((this.mUIItemEdit == null))
{
this.mUIItemEdit = new HtmlEdit(this);
#region Search Criteria
this.mUIItemEdit.SearchProperties[HtmlEdit.PropertyNames.Id] = null;
this.mUIItemEdit.SearchProperties[HtmlEdit.PropertyNames.Name] = null;
this.mUIItemEdit.SearchProperties[HtmlEdit.PropertyNames.LabeledBy] = null;
this.mUIItemEdit.SearchProperties[HtmlEdit.PropertyNames.Type] = "SINGLELINE";
this.mUIItemEdit.FilterProperties[HtmlEdit.PropertyNames.Title] = null;
this.mUIItemEdit.FilterProperties[HtmlEdit.PropertyNames.Class] = null;
this.mUIItemEdit.FilterProperties[HtmlEdit.PropertyNames.ControlDefinition] = "type=\"text\" value=\"\"";
this.mUIItemEdit.FilterProperties[HtmlEdit.PropertyNames.TagInstance] = "5";
this.mUIItemEdit.WindowTitles.Add("http://cms.home.psafe.com/");
#endregion
}
return this.mUIItemEdit;
}
In this post, I learned about SearchProperties, but it doesn't look to be an appropriate solution in this case.
Is there any other way to wrap these controls properly?
You might be able to find it if its containing element can be found. You can use the containing element to scope the search. So, find that element's parent, then find an input type=text within it:
var container = new HtmlControl(bw); //where bw is the browser window
HtmlDiv parentDiv = new HtmlDiv(container);
parentDiv.SearchProperties[HtmlDiv.PropertyNames.Id] = "theIdOfYourDiv";
HtmlEdit edt = new HtmlEdit(parentDiv); //the search scope is narrowed down to the div only. This may be enough to find your control with the search property.
edt.SearchProperties[HtmlEdit.PropertyNames.Type] = "SINGLELINE";
You have two options:
Try crowcoder's solution of searching in the parent. The problem with this solution is when you move a control around you're going to be changing code a lot.
Add an Id property to all your controls in the HTML, this will make your Coded UI more robust and responsive to changes in the UI.
I have several commands in my ViewModel and I want to have the CanExecute of each button to be bound to an observable busy which is defined as none of the buttons is currently executing.
The following is what I came up with, but obviously it runs into a NullReferenceException.
busy = Observable.CombineLatest(this.PlayCommand.IsExecuting, this.PauseCommand.IsExecuting, (play, pause) => play && pause);
this.PauseCommand = new ReactiveCommand(busy.Select(b => !b));
this.PlayCommand = new ReactiveCommand(busy.Select(b=> !b));
Also the CanExecuteObservable property on ReactiveCommand is readonly, so I need to define an IObservable before I initialize the commands.
Any ideas on how to solve this chicken and egg problem? A better way of observing busy state for a ViewModel (or a collection of ViewModels) would be appreciated also :-)
I would set up a proxy via using a Subject:
var areAllAvailable = new BehaviorSubject<bool>(true);
PauseCommand = new ReactiveCommand(areAllAvailable);
PlayCommand = new ReactiveCommand(areAllAvailable);
Observable.CombineLatest(PauseCommand.IsExecuting, PlayCommand.IsExecuting,
(pa,pl) => !(pa || pl))
.Subscribe(allAreAvailable);
Okay, let's see if I'm thinking straight:
If I simply want to read some data from a source and then apply it to some control, I may as well just do that directly rather than go to the trouble of data binding. IOW, I may as well do this:
foreach (var quad in listQH)
{
...
tb.Text = quad.Ph1;
...as opposed to:
tb.DataBindings.Add(new Binding("Text", quad, "Ph1"));
However, if I want updates within the underlying class instance to update the controls (the "tb" textBox in this case), and user updates of the controls to update those class instance members ("two-way binding"), I need to implement INotifyPropertyChanged. But then, I would have to change this code:
List<QHQuad> listQH = GetForPlatypus(PlatypusId, dow); // listQH locally declared
foreach (var quad in listQH)
{
int QHCell = quad.QH;
if ((QHCell >= 1) || (QHCell <= QUARTER_HOUR_COUNT))
{
string PH1CellToPopulate = string.Format("textBoxA_{0}", QHCell);
string PH2CellToPopulate = string.Format("textBoxB_{0}", QHCell);
string PH3CellToPopulate = string.Format("textBoxC_{0}", QHCell);
var tb = (TextBox)this.Contro.Find(PH1CellToPopulate, true).First();
tb.DataBindings.Add(new Binding("Text", quad, "Ph1"));
. . .
...to:
List<QHQuad> listQH; //global to the form
. . .
listQH = GetInfoForPlatypus(PlatypusId, dow);
foreach (var quad in listQH)
{
// the same as above
And then I'd be able to ultimately save those potentially changed class instance values in this way:
foreach (var quad in listQH)
{
UpdateQH(quad); // quad contains members QH, Ph1, Ph2, and Ph3 ("UPDATE BLA SET PH1 = :Ph1, PH2 = :Ph2, PH3 = :Ph3 WHERE QH = :QH")
}
You have the right idea. Here are a few pointers, though.
INotifyPropertyChanged is only required if you want changes from within the ViewModel to bubble up to the view. It is not required for two-way binding. If you want two way binding and only need to read once when view loads, a plain property is fine.
You may want to check out the MVVM (Model - View - ViewModel) pattern. It is the recommended design pattern for WPF, Silverlight, Metro, etc. because it is great for data-binding heavy implementations.