How to trigger datatemplate selector in Windows Phone? - windows-phone-7

I have a property and depending upon it's state (say A and B) I either show a usercontrol of animation or a image.
Now, if the property changes, I want to trigger the datatemplate selector again. On searching, I found that in WPF I could have used DataTemplate.Trigger but it's not available in WP.
So, my question is
Is their a way to trigger datatemplate selector so when property changes from state A to B, then appropriate usercontrol gets selected. If yes, then please give some example how to implement it.
Also, as there are only two states, if think I can use Converter to collapse the visibility. For basic if else situation, I will need to write two converters.( Can I somehow do it using one converter only?)
Here is the exact situation.
If state == A :
select userControl_A
else : select userControl_B
Also,
Will the animation usercontrol will effect the performance when it's in Collapsed state?
EDIT- Just realized, I can use parameter object to write just one converter.

You could implement a DataTemplateSelector like described here.
I use it and it works pretty well.
EDIT:
If you need to update the DataTemplate when the property changes, you should subscribe to the PropertyChanged event of the data object in the TemplateSelector and execute the SelectTemplate method again.
Here is the code sample:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
City itemAux = item as City;
// Subscribe to the PropertyChanged event
itemAux.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(itemAux_PropertyChanged);
return GetTemplate(itemAux, container);
}
private DataTemplate GetTemplate(City itemAux, DependencyObject container)
{
if (itemAux != null)
{
if (itemAux.Country == "Brazil")
return BrazilTemplate;
if (itemAux.Country == "USA")
return UsaTemplate;
if (itemAux.Country == "England")
return EnglandTemplate;
}
return base.SelectTemplate(itemAux, container);
}
void itemAux_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// A property has changed, we need to reevaluate the template
this.ContentTemplate = GetTemplate(sender as City, this);
}

Related

Xamarin.Forms.Maps nested inside a ScrollView. Map not usable since ScrollView is intercepting events

Xamarin Android.
I have searched and tried many answers from other threads but can not get it to work.
I have been trying to use RequestDisallowInterceptTouchEvent(true); to stop my parent ScrollView from absorbing the Touch Events and allow panning on the MapView thats nested inside it but not successful.
Here is what I have done so far in my Maps Customer Renderer for Android
private IViewParent _scrolLView;
private IViewParent GetParentScrollView(IViewParent parent)
{
if (parent is ScrollViewRenderer)
return parent;
return GetParentScrollView(parent.Parent);
}
public override bool DispatchTouchEvent(MotionEvent e)
{
GetParentScrollView(Parent).RequestDisallowInterceptTouchEvent(true);
return base.DispatchTouchEvent(e);
}
But when I try to pan on the Map, the scroll view still intercepts and scrolls.
RequestDisallowInterceptTouchEvent is called when a child does not want this parent and its ancestors to intercept touch events .
Try to change GetParentScrollView(Parent) to this , it works on my side .
public override bool DispatchTouchEvent(MotionEvent e)
{
this.RequestDisallowInterceptTouchEvent(true);
return base.DispatchTouchEvent(e);
}
you can add InputTransparent="True" in your scroolview attribut on xaml.
And it's works

Xamarin Forms Map Viewable Area event handler

I have a Xamarin form map on my screen and I'm using PropertyChanged event to retrieve geolocation information from my server and display the proper pins on screen.
While coding the solution I noticed the PropertyChanged event is triggered multiple times (up to 10 times) with a single zoom or drag action on the map. This causes unnecessary calls to server which I want to avoid.
Ideally I want to make only one call to server when the final PropertyChanged event is called but I cant's find an easy solution to implement this.
At this point I've added a refresh button to my page that becomes enabled when a PropertyChanged event happens and I disable it after user uses the button.
Obviously this fixed the too many calls to server but made the solution manual.
I was wondering if there is a more elegant way to make the server call but do it automatically.
Thanks in advance.
I just test the PropertyChanged event on iOS side and it just triggered one time with a single zoom or drag action on the map.
While if it really triggered multiple times, you can use a timer to call the server when the final PropertyChanged event is called, for example:
public partial class MapPage : ContentPage
{
Timer aTimer;
public MapPage()
{
InitializeComponent();
customMap.PropertyChanged += CustomMap_PropertyChanged;
}
private void CustomMap_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (aTimer != null)
{
aTimer.Enabled = false;
aTimer.Stop();
aTimer.Close();
}
aTimer = new Timer();
aTimer.Interval = 1000;
aTimer.Enabled = true;
aTimer.Elapsed += ATimer_Elapsed;
aTimer.Start();
}
private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
aTimer.Stop();
//do web request
Console.WriteLine(sender);
Console.WriteLine("CustomMap_PropertyChanged");
}
}
In the above code, I set the Interval = 1 second, that means in 1 second, whatever how many times PropertyChanged triggered, only the last call will trigger the ATimer_Elapsed function.
The Interval can be set to any value depending on your requirement.

How to Cleanup a ViewModel in Mvvm Light?

I have a list of items that goes to another page, That page is hooked up to a view model. In the constructor of this view model I have code that grabs data from the server for that particular item.
What I found is that when I hit the back button and choose another item fromt hat list and it goes to the other page the constructor does not get hit.
I think it is because the VM is now created and thinks it does not need a new one. I am wondering how do I force a cleanup so that a fresh one is always grabbed when I select from my list?
I faced the same issue, that's how i solved it.
Have a BaseView class, override OnNavigatedTo
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (NavigatedToCommand != null && NavigatedToCommand.CanExecute(null))
NavigatedToCommand.Execute(null);
}
add DependencyProperty.
public static readonly DependencyProperty NavigatedToCommandProperty =
DependencyProperty.Register("NavigatedToCommand", typeof(ICommand), typeof(BaseView), null);
public ICommand NavigatedToCommand
{
get { return (ICommand)GetValue(NavigatedToCommandProperty); }
set { SetValue(NavigatedToCommandProperty, value); }
}
On the necessary pages, add to xaml (and, of course, inherit BaseView )
NavigatedToCommand="{Binding OnNavigatedToCommand}"
In the ViewModel, make command itself
public RelayCommand OnNavigatedToCommand
{ get { return new RelayCommand(OnNavigatedTo); } }
and implement method you want to call to update list
public async void OnNavigatedTo()
{
var result = await myDataService.UpdateMyList();
if (result.Status == OK)
MyList = result.List;
}
So, now, every time you navigate to page with list, inside of overriden OnNavigatedTo(), a NavigatedToCommand would be executed, which would execute OnNavigatedToCommand (which you set in xaml), which would call OnNavigatedTo, which would update your list.
A bit messy, but MVVM :)
EDIT: What about cleanings, they can be done in OnNavigatedFrom(), which works the same. Or OnNavigatingFrom(), which also can be useful in some cases.

How do I detect NSDatePicker ValueChanged in MonoMac?

Unlike UIDatePicker in Monotouch, the NSDatePicker in MonoMac does not appear to have "ValueChanged". How do I detect changes?
Ideally where datePicker is an NSDatePicker, I want to
datePicker.ValueChanged += DatePickerOnValueChanged
For events, I see "Activated" and "ValidateProposedValue", could it be the latter that I want?
Update. I think I can do something like below. Is it equivalent?
datePicker.Action = new MonoMac.ObjCRuntime.Selector ("datePickerAction:");
and
[Export("datePickerAction:")]
private void datePickerAction()
{
// stuff
}
In your ideal case, you say you want to use an event. The ValidateProposedValue event is fine for this:
picker.ValidateProposedDateValue += (object sender, NSDatePickerValidatorEventArgs e) => {
Console.WriteLine(e.ProposedDateValue);
};
It seems to correspond to the NSDatePickerCellDelegate method datePickerCell:validateProposedDateValue:timeInterval:, which is what I would use in Objective C.

ItemsControl.ItemsSource MVVM performance

I have an (non-virtualized) ItemsControl that binds its ItemsSource to a ObeservableCollection of ViewModel instances. Now once the large amount Model instances is loaded all the ViewModel complemnents needs to be added to that ObservableCollection. How can I add a large amount of ViewModels without making the UI Thread hang?
I suppose the UI Thread hangs because each time a new item is added the ItemsControl needs to update itself and does layout etc. over and over again.
Should I suspend the binding add all
items and then resume? If so, how?
Should I override the
ObservableCollection to implement an
AddRange so only 1 CollectionChanged
Event is fired for adding multiple
items? Or alternatively just replace
the whole collection?
Or is it better
to add each items separately and call
Dispatcher.Invoke for each item
separately? So I would unblock
frequently.
How do you handle large dynamic lists that can not be virtualized?
You can create a a class derived from ObservableCollection which allows you to temporarily suspend CollectionChanged events like this:
public class SuspendableObservableCollection : ObservableCollection
{
private bool suspended;
public bool Suspended
{
get
{
return this.suspended;
}
set
{
this.suspended = value;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset));
}
}
protected override void OnCollectionChanged(
NotifyCollectionChangedEventArgs args)
{
if (!Suspended)
{
base.OnCollectionChanged(args);
}
}
}
<ItemsControl IsAsync="True" ... />

Resources