I am making a Panorama Windows Phone 8 app. This is the first time I have actually used one in an app.
I am having problems showing the data in runtime. Instead I am only seeing a list:
RuntimeOne
RuntimeTwo
RuntimeThree
etc..
I don't have a clue what has happened, it worked the other day. I am going into the SampleData folder and changing LineOne, LineTwo, LineThree, etc but it's not doing anything when I deploy the app to the Windows Phone Emulator.
What's happening is that there are two different sets of data, and the DataContext at runtime is different from design time.
The data that you see in design mode ('design one', 'design two') is
stored in MainViewModelSampleData.cs, so changing that doesn't affect
the runtime experience.
The data at runtime is coming from the LoadData method in
MainViewModel.cs
At the top of MainPage.xaml, you'll see
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
and the "d" namespace here is a mnemonic for 'design'. If you look at the sample data XAML file, you'll notice it declares a class called MainViewModel with a collection of Items.
At runtime, MainViewModel.cs (specifically the LoadData method) adds items one by one to the Items property of the MainViewModel class, and that class is in turn set to be the runtime DataContext in the constructor of MainPage
The panorama control itself has markup like
<phone:LongListSelector Margin="0,0,-22,0" ItemsSource="{Binding Items}">
so it's expecting to see a collection called Items on whatever the current DataContext is, and the fact two different data contexts are in play explains what you're seeing.
The data binding magic is incredibly cool and powerful, but sometimes does leave you scratching your head.
Related
I have implemented a custom DataTemplateSelector according to: GitHub Xamarin Forms.
This allows for a datatemplate to be selected based on an item, which is received through a data binding. This works fine to select a proper datatemplate and render it. However, I am now at a point where I want to add custom controls to this datatemplate (custom buttons). This works on any other page, but for some reason not in this datatemplate.
The relevant lines in the datatemplate:
xmlns:controls="clr-namespace:Universal_ONE.Views.Controls"
<controls:IconButton Command="{Binding RobotLocationSave}"
Image="{StaticResource BoltBlack}"/>
The part the datatemplate is selected and created:
var templateToUse = templateSelector.SelectTemplate(item, null);
View view = (View)templateToUse.CreateContent();
view.BindingContext = bindingContext;
In the catch block I get the error (after calling CreateContent()):
Xamarin.Forms.Xaml.XamlParseException: Position 371:26. Type controls:IconButton not found in xmlns clr-namespace:Universal_ONE.Views.Controls
The problem has to be with the CreateContent(), since using the control outside of this datatemplate works.
EDIT 1
I've created a Minimal Working Example: GitHub.
The datatemplate is now hardcoded, so I'm sure that one is selected.
The same parseexception gets thrown.
I am trying to compile Xamarin.Forms myself so I can debug the framework itself. However, compiling is not going smooth; thus might take a bit longer.
EDIT 2
A bit more info on the MWE:
The MainPage.xaml has the default Xamarin.Forms app code. Below I've added a custom control, which is simply a frame with a label. The text of this label is set via a bindableproperty (not really relevant). Below this control is the datatemplatecontrol added, which in turn calls the datatemplateselector, which returns the datatemplate. This datatemplate contains the same control as the mainpage. Thus the rendered app should have 2 controls. However, in de datatemplatecontrol you can breakpoint on the catch statement (look for my comment). This is where the parseexception will show, which is caused after calling CreateContent() on the datatemplate.
EDIT 3
I've not been clear enough I think. But you have to put a breakpoint on line 41 of datatemplatecontroler.cs. Since the content of the datatemplate is set to null if the createcontent() fails, thus fails gracefully. When hitting the breakpoint you can read the parseexception.
EDIT 4
I've made an issue and a pull request on the Xamarin repository: GitHub. The problem resides with the XamlParser, which has a small bug where it selects the wrong assembly. Inside the issue I've mentioned a workaround which can be used for now.
I try to download your example and run it. When I run to Content = CreateTemplateForItem(ItemTemplate); the program does not report an error, so the program skips the catch method. Here is a screenshot of the runtime:
Then I tried to actively throw an exception in the try statement (throw new Exception();) to make the program enter the catch method, Here is a screenshot of the runtime:
I'm still learning GWT, yet already have to face some kind of challenge for a work I have to do. Can't show any specific code so I'll try to explain it well.
Here's the situation: A certain class "Navigator" creates and save the Presenter instances of my architecture to allow reusing them. There is a method show() inside that same class that actually displays the view related but that system only works full screen by calling RootPanel.get().
What i'd like to do is showing that presenter instance's view inside of a flex panel element declared in a class myView (related to a class myPresenter) that basically uses Flex Panel to structure it's content.
To make it maybe more clear:
class myView{
...
flexPanel.setWidget(firstWIdget)
flexPanel.setWidget(secondWidget) //secondWidget to be replaced by a "thirdWidget"
...
}
I'd like the secondWidget to be replaced by another one, let's call it thirdWidget, that consists of a specific presenter instance's view.
To resume, I'd like my presenter instance's view to not go full screen but only occupy a certain area of the screen.
The displaying is managed almost entirely programmatically, means very limited use of css files and no use at all of xml ui files.
How can I manage this ?
Thanks
Use a SimplePanel as a container for your views returned by your Navigation class instead of adding them directly to root panel, and use that instance of SimplePanel where ever you want.
I have a ListView that is bound through XAML to an ObservableCollection. I used to do the sorting in code behind but there are many operations where I would have to keep in mind that the sorting needs to be refreshed.
So I wanted to make it more clean and make the sorting directly in XAML more dynamically.
Unfortunately I cannot find tags/attributes to do this. All examples I find are for WPF applications using <CollectionViewSource.SortDescription> which seems to be not supported in XAML, at least for now.
I found a AdvancedCollectionView control in the UWP Community Toolkit which I then used. This control uses the existing ObservableCollection and the ListView (source) is now bound to this AdvancedCollectionView.
It seems to work - so what's the problem.
1) I now have to use a huge Nu-Get package with many licenses (which I should have read :-) )
2) I implemented INotifyPropertyChanged for the class that is bound to the ListView (the single item) so that the ListView gets refreshed when a property, e.g. the Title of an item changes. This used to work earlier, before I switched to AdvancedCollectionView but now the event raiser throws a NullReferenceExcpetion.
So I'm now asking myself if there isn't really a more Out-of-the-Box way to do the simple task of sorting a ListView by a bound property?
Apparently the issue with the AdvancedCollectionView occurs because there is currently a bug when no Filter property has been set.
I replaced the NuGet-Package with the complete source and debugged it to locate the error in the ItemOnPropertyChanged where it threw the NullReferenceException on line:
filterResult = _filter(item);
because "_filter" was null.
I reporeted the bug and it looks like a fix will be in version 2.2 of the Community Toolkit:
https://github.com/Microsoft/UWPCommunityToolkit/issues/1686
I have a ViewModel which contains a Boolean property which tells you if the user has authenticated or not.
I have a WrapPanel which is bound to a collection of profiles. The DataTemplate for these profiles has an icon - a closed padlock for when the user is not authenticated and an open one for when the user is authenticated. Ideally these would be bound to the Boolean on the ViewModel but the DataContext for the templates is the individual profile objects.
I have tried,
Setting the Source selector in the binding as specified here although it appear Windows Phone 7 does not support x:Reference
I tried also the Inversion of Control(?) method detailed here (but containerLocator was not found on my object)
I tried applying a Style.Trigger but these are not supported in Windows Phone 7
I also tried accessing the XAML elements in the code behind and updating programmatically on event triggers, however I could not get a handle on the Image element inside the DataTemplate
Edit after comment: WP7 does not support style triggers. But if anyone is looking for this answer on following versions I let the reply below:
I would use a Style Trigger as seen here to update the icon Source property on the fly - as part of the style of your DataTemplate so you would get a hold of your Image.
One way I found that works based on an answer by Damian Antonowicz but does not implement the full inversion of control method that he uses, is as follows,
Create a partial class which resolves to your view-model instance under your view-model namespace, e.g.
public partial class ViewModelInstanceLocator
{
public AppViewModel AppViewModel // Or whatever the type of your view-model is ...
{
get
{
return App.VM; // Or wherever your view model instance is ...
}
}
}
Define the other half of the class in your XAML page as a resource so that it can be referred to as a static resource, I did this in my App.xaml so that it could be referred to everywhere,
<ResourceDictionary>
<viewmodel:ViewModelInstanceLocator x:Key="ViewModelInstanceLocator" />
...
</ResourceDictionary>
You may need to include the relevant namespace if there is not already a reference to your view-model namespace e.g. at the top,
xmlns:viewmodel="clr-namespace:MyAppNamespace.ViewModel"
Finally to bind to the view-model as follows,
{Binding AppViewModel.SomeProperty, Source={StaticResource ViewModelInstanceLocator}}
The binding updates as usual just as if the view-model instance had been referred to through the DataContext. However, it does not work with design-time data.
Right now, I'm working on my first WP7 app and have run into some questions, which I haven't been able to answer despite reading what I could find online. Please consider an app that has a main page, a parameters page and a results page. In the parameters page, the user can enter or update numbers in various textboxes. Hitting the back button takes the user back to the main page, where there is a button called "Calculate". Hitting that button should take the data, perform a calculation with it and take the user to the results page presenting a grid with the results.
In a file called Calculator.cs I have a class called Calculator inside a folder called Models. I also have my MainViewModel.cs, ParametersViewModel.cs, and ResultsViewModel.cs files inside the ViewModels folder and the corresponding MainPage.xaml, along with Parameters.xaml and Results.xaml inside a folder called Views. I'm assuming that all the data will be manipulated within the instance of the Calculator class and then a results set will be returned and directed to Results.xaml. I'm just at a loss as to where to instantiate the Calculator class, pass it data, then retrieve the results. I'm also somewhat puzzled how I will trigger the automatic navigation to the Results page when the calculation is done.
Any help with this would be greatly appreciated.
UPDATE: Passing a complex object to a page while navigating in a WP7 Silverlight application has some more info on the same subject. I can go into App.xaml.cs and add something like this:
public class Foobar
{
public string barfoo = "hah!";
}
public static Foobar myfoob = new Foobar();
Then access it from a ViewModel page, e.g. AboutViewModel.cs, like this:
public AboutViewModel()
{
string goo = App.myfoob.barfoo;
}
But at this point I'm still uncertain what unforseen effects that might have. I'm going to tackle serialization/tombstoning at this point to see what happens with either this approach or by using the same DataContext across pages. Otherwise, one of the posters in the link above mentioned serializing the params and passing them between pages. My concern there would be whether or not there is a character limit as with HTTP GET. Seems there is: URI Limits in Silverlight
There are of course lots of possible designs - and lots of them are correct in different ways!
Here's one I might use:
The Calculate button press should trigger the Navigate to the Results page
On navigate to, the Results page should show some animation (maybe just a progress bar)
On navigate to, the Results page should create a new ResultsViewModel, passing in the MainViewModel as parameters
the constructor (or some init method) of the ResultsViewModel should spark up a thread to do the calculation
when this calculation is complete, then the relevant properties of the ResultsViewModel will get set
at which point the databinding on the Results page will clear the animation and show the results
Other solutions are definitely available - will be interested to read what other people suggest and prefer.
As an aside, one thing to watch out for on your Results page is tombstoning - could be an interesting challenge!