Sort ListView bound to ObservableCollection in XAML - sorting

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

Related

Xamarin custom control in a datatemplate created with CreateContent()

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:

Previously working (in 1.4.7) Apache Wicket 6 DataView not updating when data source SortableDataProvider is updated from a ModalWindow

As the title says, I am trying to update a web app to a more recent Apache Wicket version. The problem is very like this one here, albeit the link is very old (and an ancient version of Wicket, which is not what I'm using)
http://users.wicket.apache.narkive.com/tG6XOAUM/refresh-page-after-form-submit-within-modalwindow
So what I do is:
- display a DataView in a regular page, populated using a SortableDataProvider
- create a panel inside a ModalWindow to make some data changes;
- on onSubmit (using an AjaxFallbackButton) inside this panel, insert a new item into the same SortableDataProvider which I use to populate my DataView
- I then call "target.add(wmc)" on the WebMarkupContainer surrounding my DataView
- my DataView.populateItem registers the change when I add trace code, but the change is not actually displayed ie the screen is apparently not being refreshed.
If I do the same thing from an AjaxFallbackButton.onSubmit() NOT inside a ModalWindow, but in the same WebPage as my DataView, then all is well and I see the change on the page immediately.
I started to upgrade to Wicket 8 but there is so much else to change that I'd rather not do this right now.
I can post code if needs be but I wondered if anyone had come across this problem. As I say, fine in Wicket 1.4.7. Next step would be to create a mini-app to demonstrate this, I guess, which might well lead me to a solution anyway but hoping for some good input from that Wicket community out there ;-)
You're holding a reference from one page to another:
public class TestBugInsertItemPage extends WebPage {
private TestBugPage parent;
This not allowed in Wicket, and I wonder how this has worked in 1.4.
Your trying to update components from another window, that cannot work:
#Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
TestBugInsertItemPage.this.parent.dp.addLine();
target.add(TestBugInsertItemPage.this.parent.wmc);
TestBugInsertItemPage.this.parent.modal.close(target);
}
An AjaxRequestTarget is valid for a single request for a single page only.
You should use a ModelWindow with a panel instead.
Update for your second example:
Passing a panel to a different page won't make a difference. Wicket serializes pages to disk, thus you cannot share any state between them.
You should use a modal dialog with a panel instead:
TestBugPage.this.modal.setContent(TestBugPage.this.myPanel);
Now TestBugPage and your panel reside in the same component hierarchy, they communicate with each other and both can be updated on the same Ajax request.

Panorama Control not showing data

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.

Rendering collection view in CompositeView triggered constructor?

I have a composite view which has a task, and it's comments. I put it onto a contentRegion to display. When rendering model alone, it works fine. However when come to collection, it behaves really strange. console.log shows initialize function has been triggered twice. The first time is when define the view
taskView = new MyProject.Views.Task
model : task
collection : comments
I then do a MyProject.contentRegion.show(taskView) in order to render the model view. After that, I just call comments.fetch() to get all the comments. Then comes the problem, it re-initialized my taskView and the template keep complaining xxx is undefined.
Any thoughts? I know it's weird because another CompositeView in my project works great.
NathanInMac, I've done a little testing from your suggestion of using an itemView and found some interesting stuff.
Was your problem involving nested compositeviews'? As mine was but I'm unsure if that affects anything.
What solved the problem was initially trying a collectionView which couldn't find the itemView so I moved the definition of the itemView for the collectionView/compositeView to before the definition of the collectionView(or extended).
This seems to be a working fix and just a misleading bug with compositeView's double initializing instead of displaying some exception or error.

Best way to notify state modification between ViewModel objects when using the MVVM pattern

I'm working on my first C#/WPF project (I'm a Java/Web developer with some Flex/As experience). The MVVM pattern seemed to be the way to go so I've started climbing the learning curve...
I'd like to know what's considered as the way to go to notify state modifications between related ViewModel objects.
Long story short, I have a UserControl containing a TreeView that is bound to a ReadOnlyCollection exposed by MyTreeViewModel.
SomethingViewModel implements INotifyPropertyChanged and generates an event when its 'IsSelected' property is changed.
MyTreeViewModel has an event handler attached to the PropertyChanged event of SomethingViewModel and updates a property that it manages called 'CurrentlySelectedElement'.
MyTreeViewModel also implements INotifyPropertyChanged and generates an event when its 'CurrentlySelectedElement' property changes.
Finally, I have an event handler in another ViewModel class that handles the selection change.
Is this a correct way of approaching this in C#/WPF?
Also, I'm not really fond of using property names with Strings in my event handling methods; It doesn't seem very refactoring friendly to me.. For now, I've dealt with this by exposing the property name as a static string, so that I can simply use the following in my event handler method:
if(SomeViewModel.PROPERTY_IS_SELECTED.Equals(e.PropertyName)) { ... }
Do you know a better alternative? I guess there should be a way of doing this but to be honest I didn't investigate that any further yet.
Thanks for your feedback!
Check out the Event Aggregator pattern. There are quite a few implementations out there. If you're using a MVVM framework ( https://stackoverflow.com/questions/1280462/what-mvvm-framework-are-you-using, What framework for MVVM should I use? ), chances are it will contain an implementation as well.

Resources