There is activity, fragment and a viewmodel binded to them both. Fragment has event which gets raised multiple times by Timer, delegate inside fragment is subscribed to that event and updates single UI element with value from a viewmodel.
Delegate:
private void OnTimerUpdate(object o, EventArgs e) {
this.Activity.RunOnUiThread(() => {TimerTextView.Text = ViewModel.TimerValue;});
}
It is called multiple times as planned, however ui element is not updating, unless I'm interacting with a View (e.g. scrolling).
Previously both ui element and delegate was inside activity and was working properly, however when I refactored it to have separate fragment, this happened.
Have you tried calling TimerTextView.Invalidate() after changing the text?
Found answer here. Which I thought was weird, but actually worked - set width and height of textview I'm updating to some values instead of 'wrap_conent'.
Related
Is there a ScrollView event in xamarin that is triggered when the user forces scroll up and scroll is already at top? Many apps uses this as the "command" to update the page.
Currently, there is no PullToRefresh property or RefreshCommand for a ScrollView built into Xamarin.Forms. However, It does exist on ListView as shown in the docs, which you might be able to use instead depending on your needs.
Also, it does look like there is a PullToRefreshLayout opensource project created by James Montemagno you might be able to use to easily implement pull to refresh with a ScrollView, but it has been a while since it's last been updated.
You can use the Scrolled event handler. If the ScrollView is already positioned at the top of the contents and the user "pulls down" then Y amount will be either 0 or negative (I know this will work on Android and iOS, not sure about UWP and others).
scroll.Scrolled += (object sender, ScrolledEventArgs e) =>
{
if (e.ScrollY <= 0)
{
// scrolled when already at top of list
}
};
I'm trying to implement an NSSplitView similar to Xcode where you can collapse a view by dragging its handle to under half its width and it will collapse automatically. I have that part working, but I need to update the state of a button in the toolbar when this happens. I tried listening to splitViewDidResizeSubviews and checking if the splitView's view is collapsed, but that method fires 16 times with collapsed == true, so I don't think I want to update the button's state 16 times. Is there a cleaner way to do this? I'm new to Cocoa, but from what I've seen, I would expect there to be some way to just say bind this button's state to the isCollapsed property and be done with it. Does such a thing exist?
If you subclass your NSSplitViewController you can add a listener for the SplitViewItem's isCollapsed property:
class MySplitViewController: NSSplitViewController {
var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let sideViewSplitViewItem = splitViewItems[0]
observer = sideViewSplitViewItem.observe(\.isCollapsed, options: [.initial, .new]) {splitViewItem, _ in
print("Sidebar collapsed state changed to: \(splitViewItem.isCollapsed)")
}
}
}
The best way to see what bindings are available is to check the docs, specifically the Cocoa Bindings Reference (look in the sidebar for the view you're after).
NSSplitView doesn't have the binding you describe, so I think you're on the right track with your current approach. Of course, you don't need to update the button's state sixteen times, just check it's value each time, and update it if needs be. It might seem a bit wasteful, but checking the value of a bool is a very cheap operation, and you won't notice any kind of performance hit.
While NSSplitView has no event or observable property for when one of it's subviews is "collapsed", the immediate subview itself will have its hidden property set to YES.
So you can either observe the subview's hidden property yourself, or if you're creating your own custom subview of NSView, you can override the -(void) setHidden:(BOOL)hidden to catch the event.
I do the latter, and it works correctly every time.
-(void)setHidden:(BOOL)hidden
{
[super setHidden:hidden];
// Insert code to react to the "collapsed" event here.
// (You're likely going to tell your parent view,
// self.window.windowController, or something.)
}
Of course the setHidden method / hidden property can in theory be called for purposes other than from NSSplitView "collapsing" your view, but this is very unlikely to ever happen in practice.
I am using a button and a listview to display a list of options to the user. Selection is made with a mouse click, the listview removes its self from the .Controls array + un-registers eventlistener and loads a new listview else where on the screen.
My problem is both listviews trigger e.selected twice:
' private void _lvKids_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
if (e.IsSelected)//fires twice per click
{
HideKidsList();//--REMOVE CURRENT LISTVIEW
ValidateUser();//CREATE NEW LISTVIEW
}`
If the button is clicked a second time to restart the process, it causes a win32 Exception. After much research, this exception is the often the cause of a memory leak. So I'm thinking memory leak?
When I first started, listboxes were used which worked perfectly. I'd love to able to use them, but my form has a graphic for a background and listbox doesn't. Listview does.
I don't have anyone to turn to so any thing you can offer would be appreciated.
Thanks;
Sam
An update if anyone else has the same issue. Selecting the listview item called for it to be removed from Controls array. Removing the listview also cause the selected item to be deselected, thus 4 calls to the handler.
I'm writing a silverlight app and I'm trying trying to improve the loading time.
When my page loads, I first initialize my ObservableCollection:
this.MyItems = new ObservableCollection<Item>();
My UI is a ListBox which I bind to an ObservableCollection through code. In MainPage_Loaded:
MyList.ItemsSource = App.ViewModel.MyItems;
Now I bind the UI to my model. I expect this to be efficient as the collection is empty, and the rest of the UI can continue to load (not sure if my assumption is correct).
DataContext = App.ViewModel;
Now I want to add items to my collection:
for (int i = 0; i < number_of_items; i++)
{
this.MyItems.Add(myItems[i]); // myItems is a List<Item> already populated
Thread.Sleep(20);
}
My goal was to let the thread sleep so that it would have time to render the UI for each list box item. Also, I expected my UI to display one item at a time.
The result is that the ListBox elements appear altogether at once. If I set a Sleep of 1 second, the ListBox gets populated after 1 second times the number of elements.
What's the good way of optimizing this operation? If it's futile, I may also just bind my ListBox to a fully populated ObservableCollection. Thanks!
Try moving the loop to a background thread. Here is one way to do that.
Phạm Tiểu Giao - Threads in WP7
Note you'll need to dispatch the UI update. Something like
Dispatcher.BeginInvoke( () => { this.MyItems.Add(myItems[i]); } );
Sleep will work if you want to use a fixed time period. Just make sure the time period is always longer than the time taken to update the display, or you will potentially overload the UI thread with updates faster than it can process.
The reason we bind to an ObservableCollection is so the built-in notification occurs of property updates through the INotifyPropertyChanged interface implementation. This causes an event to be fired on each update to the underlying collection, which in turn causes a redraw of the related UI element(s) (ListBox in this case). The data template is applied on each redraw to each item in the collection, and is automatically done so through data binding. The items are being added to your collection faster than the draw can take place (on a separate thread), hence why it appears your load is delayed until all items are added. Youre missing the redraw cycles visually on the screen since theyre being drawn and invalidated on the screen when new items are added.
This means that your Thread.Sleep call is only delaying the complete redraw of the element on each item that is added (* number of items being added explains why your UI is being redrawn entirely on each item, but only after all have had their respective Thread.Sleep calls made which blocks the UI thread for n * sleepValue time). This is why we need to use a Dispatcher object as indicated above as these calls are made on a different thread. This allows us to redraw from the UI thread, which in essence, synchronizes the blocking calls.
I would absolutely not use the Dispatcher here as it is redundant and prevents the native synchronization to occur since the dispatcher could be referenceing an element that has not yet been created and added to the visual or logical trees (as clearly experienced by your comment on settign the value to 1000ms versus 20ms). You will still be redrawing all items in the collection as each is added making your sleep call invalid, or nonfunctional, for lack of a better term.
What I offer as an alternative solution is that you could add a storyboard animation on the Opacity property of the root element of your data template to create the visual effect of the items doing something "one at a time as being added." This way, as each item is added to the underlying collection, they will be drawn with the opacity fade animation, giving the illusion that each item is being added one at a time (and animating into view) with separate animations (at different offsets within the defined animation). I believe this will give you the effect youre looking for. But since the draw call comes from ListBox as it maintains its collection of items, the entire collection will be invalidated on each .Add call to your ViewModel items ObservableCollection object. There really is no way to override this behavior since it happens one level upstream in the hierarchy. I would advise against the provided approach.
I have a simple slider, with only 3 options. It seems strange to force the user to drag the small thumbnail on the slider, when it would be a lot easier to click one of the 3 actual labels by the side of the slider. Does anyone know how to accomplish this?
This is a cool problem.
The Label object used by Slider turns out to be a subclass of Label (called SliderLabel). So, probably the best approach would be to subclass Slider and add event listeners to the labels.
I think you could successfully add event listeners in either the commitProperties method or the updateDisplayList method. I'm not sure if one would be preferable to the other, but commitProperties seems like the more correct choice.
So, in your subclass of Slider:
override protected function commitProperties():void
{
super.commitProperties();
for(var i:int = 0; i < labelObjects.numChildren; i++)
{
if(!SliderLabel(labelObjects.getChildAt(i)).hasEventListener(MouseEvent.CLICK))
{
SliderLabel(labelObjects.getChildAt(i)).addEventListener(MouseEvent.CLICK,sliderLabelClickListener);
}
}
}
and then maybe something like this for sliderLabelClickListener:
private function sliderLabelClickListener(e:MouseEvent):void
{
dispatchEvent( new SliderLabelClickEvent(e.target) );
}
I think you'd want a custom event there, rather than dispatching a regular Event, so you could include the name/id/value of the label.
Also, you may want to put in a 'dispose' method to remove the CLICK event listener from the labels when the Slider is removed from the stage. It's not an issue if you aren't going to be removing the Slider, but if you are, what I normally do is create a method called dispose and put all my manual removal logic there (removing event listeners, unwatching/removing ChangeWatchers). Then I assign a listener to the component's REMOVED_FROM_STAGE event and call the dispose method from that listener.
Are you sure a slider is the best component to use in this case? Generally speaking, sliders are to be used when the user has a large range of contiguous options to choose from, where the precision of a user's choice doesn't really matter (e.g. a volume slider - having volume at 51% as opposed to 50% really won't make much of a difference).
If you only have three options, and the user is only allowed to select one of those three options, I would suggest using either a combo box or a radio button group.