WP7 - Update ListPicker items asynchronous - windows-phone-7

In this case isn't supposed that I can see the values from list in ListPicker?
xaml
<toolkit:ListPicker
x:Name="lpkBoards"
ItemsSource="{Binding AllBoards}"
DisplayMemberPath="Name" >
</toolkit:ListPicker>
xaml.cs
public SettingsPage()
{
InitializeComponent();
// Set the page DataContext property to the ViewModel.
this.DataContext = App.ViewModel;
...
boardsTask.ContinueWith(
(call) =>
{
App.ViewModel.AllBoards = call.Result.ToList();
}
);
ViewModel
// All to-do items.
private List<Board> _allBoards;
public List<Board> AllBoards
{
get { return _allBoards; }
set
{
_allBoards = value;
NotifyPropertyChanged("AllBoards");
}
}

You need to change the List<Board> to ObservalbeCollection<Board> if you are trying to bind it to a UI element and want it to work.

Related

[UWP How to get control of a UserControl placed inside a ListView without altering the listview binding source?

I have placed a UserControl inside a ListView.
How do I get the control of this UserControl in the view.
If I place it inside a ListView, I am unable to access it in the view. I also do not wish to make any changes to the listView binding source.
Its name isn't accessible directly in the view.
I am able to access the events but not Properties(x:Name , Visibility etc..).
You can use VisualTreeHelper class to get your UserControl .
Get each ListViewItem by calling the ListView's ContainerFromItem or ContainerFromIndex.
Create a recursive function to find the DependencyObjects that are in each ListViewItem as a UserControl.
I made a simple to show how it works. You can refer to the following code.
MainPage.xaml
<Grid>
<ListView x:Name="MyListView" Margin="0,0,0,109">
<ListView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<Grid>
<local:MyUserControl1></local:MyUserControl1>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Content="Button" Margin="682,943,0,0" VerticalAlignment="Top" Click="Button_Click"/>
</Grid>
MainPage.cs
public List<string> ItemsSourceList { get; set; }
public MainPage()
{
this.InitializeComponent();
ItemsSourceList = new List<string>();
ItemsSourceList.Add("1");
ItemsSourceList.Add("2");
ItemsSourceList.Add("3");
ItemsSourceList.Add("4");
ItemsSourceList.Add("5");
MyListView.ItemsSource = ItemsSourceList;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
foreach (var strItem in ItemsSourceList)
{
// get every listview item first
ListViewItem item = MyListView.ContainerFromItem(strItem) as ListViewItem;
// the DependencyObject is the UserControl that you want to get
DependencyObject myUserControl = FindChild(item);
}
}
public DependencyObject FindChild(DependencyObject parant)
{
int count = VisualTreeHelper.GetChildrenCount(parant);
for (int i = 0; i < count; i++)
{
var MyChild = VisualTreeHelper.GetChild(parant, i);
if (MyChild is MyUserControl1)
{
//Here can get the MyUserControl1.
MyUserControl1 myUserControl = (MyUserControl1)MyChild;
myUserControl.Foreground = new SolidColorBrush(Colors.Red);
return myUserControl;
}
else
{
var res = FindChild(MyChild);
return res;
}
}
return null;
}

Create bindable properties for Treeview in Xamarin Forms

I needed to use a Treeview in my xamarin forms application, however the only existing TreeView on the net are not free (Syncfusion and Telerik).
So I found this very interesting project : https://github.com/AdaptSolutions/Xamarin.Forms-TreeView
the only problem that I found is that the ItemSource and SelectedItem properties are not bindable and therefor I can't use it on an MVVM Pattern. Which brings us to my question, How can I make them bindable.
I tried to follow this documentation : https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/bindable-properties
but still nothing. Can anyone help me with that please ? Thank you
UPDATE :
this is the TreeView class :
public class TreeView : ScrollView
{
#region Fields
private readonly StackLayout _StackLayout = new StackLayout { Orientation = StackOrientation.Vertical };
//TODO: This initialises the list, but there is nothing listening to INotifyCollectionChanged so no nodes will get rendered
private IList<TreeViewNode> _RootNodes = new ObservableCollection<TreeViewNode>();
private TreeViewNode _SelectedItem;
#endregion
#region Public Properties
public TreeViewNode SelectedItem
{
get => _SelectedItem;
set
{
if (_SelectedItem == value)
{
return;
}
if (_SelectedItem != null)
{
_SelectedItem.IsSelected = false;
}
_SelectedItem = value;
SelectedItemChanged?.Invoke(this, new EventArgs());
}
}
public IList<TreeViewNode> RootNodes
{
get => _RootNodes;
set
{
_RootNodes = value;
if (value is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += (s, e) =>
{
RenderNodes(_RootNodes, _StackLayout, e, null);
};
}
RenderNodes(_RootNodes, _StackLayout, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset), null);
}
}
#endregion
#region Constructor
public TreeView()
{
Content = _StackLayout;
}
#endregion
#region Private Static Methods
private static void AddItems(IEnumerable<TreeViewNode> childTreeViewItems, StackLayout parent, TreeViewNode parentTreeViewItem)
{
foreach (var childTreeNode in childTreeViewItems)
{
if (!parent.Children.Contains(childTreeNode))
{
parent.Children.Add(childTreeNode);
}
childTreeNode.ParentTreeViewItem = parentTreeViewItem;
}
}
#endregion
#region Internal Static Methods
internal static void RenderNodes(IEnumerable<TreeViewNode> childTreeViewItems, StackLayout parent, NotifyCollectionChangedEventArgs e, TreeViewNode parentTreeViewItem)
{
if (e.Action != NotifyCollectionChangedAction.Add)
{
AddItems(childTreeViewItems, parent, parentTreeViewItem);
}
else
{
AddItems(e.NewItems.Cast<TreeViewNode>(), parent, parentTreeViewItem);
}
}
#endregion
}
so what Im trying to do here is making RootNodes bindable as well as SelectedItem afterwards.
What I did is simply adding this, thinking it should work but obviously it does not :
public static readonly BindableProperty RootNodesProperty =
BindableProperty.Create(nameof(RootNodes), typeof(IList<TreeViewNode>), typeof(TreeView));
public IList<TreeViewNode> RootNodes
{
get => (IList<TreeViewNode>)GetValue(RootNodesProperty);
set
{
SetValue(RootNodesProperty, value);
_RootNodes = value;
if (value is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += (s, e) =>
{
RenderNodes(_RootNodes, _StackLayout, e, null);
};
}
RenderNodes(_RootNodes, _StackLayout, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset), null);
}
}
UPDATE 2 :
Here is what it looks like
Hope this helps
It seems you will not need to create custom ItemSource and SelectedItem in ScrollView, because Xamarin Foms has Bindable Layouts that contains ItemsSource and ItemTemplateSelector .
Bindable layouts enable any layout class that derives from the Layout class to generate its content by binding to a collection of items, with the option to set the appearance of each item with a DataTemplate. Bindable layouts are provided by the BindableLayout class, which exposes the following attached properties:
ItemsSource – specifies the collection of IEnumerable items to be displayed by the layout.
ItemTemplate – specifies the DataTemplate to apply to each item in the collection of items displayed by the layout.
ItemTemplateSelector – specifies the DataTemplateSelector that will be used to choose a DataTemplate for an item at runtime.
If you need to use ScrollView, sample code as follows:
<ScrollView>
<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
Orientation="Horizontal"
...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:CircleImage Source="{Binding}"
Aspect="AspectFill"
WidthRequest="44"
HeightRequest="44"
... />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>

xamarin picker SelectedItem returning null on observable collection

in my xamarin project, picker binding, the SelectedItem is not working. When I have the ItemSource set to a List, the SelectedItem works, but when I change the ItemSource to an ObservableCollection, the SelectedItem always returns null. Can someone see what I am doing wrong?
on loading the view, the pickers are populated through databinding. then on a button event I try and grab the SelectedItem.... which is when it is coming back as null.
xaml
<Picker x:Name="PickerMarket2" Title="Market2" ClassId="PickerMarket2"
ItemsSource="{Binding TestList2}"
ItemDisplayBinding="{Binding ShortDesc}"
SelectedItem="{Binding SelectedMarket}"
Grid.Row="0" Grid.Column="1" >
</Picker>
view model
class VamiMarketViewModel: INotifyPropertyChanged
{
private List<string> _testList;
public List<string> TestList
{
get { return _testList; }
set
{
{
_testList = value;
NotifyPropertyChanged();
}
}
}
private ObservableCollection<Performance> _testList2;
public ObservableCollection<Performance> TestList2
{
get { return _testList2; }
set
{
{
_testList2 = value;
NotifyPropertyChanged();
}
}
}
private string _selectedMarket;
public string SelectedMarket
{
get { return _selectedMarket; }
set
{
{
_selectedMarket = value;
NotifyPropertyChanged();
}
}
}
I just explained the same in your other question here.
To what I see from your code, the SelectedItem seems to be the problem.
Since your Picker's ItemsSource(TestList property) is of type List<Performance>, the SelectedItem property bound to the Picker must be of type Performance. But, in your case, you have kept it as string instead of Performance.
The ItemDisplayBinding must be the name of any property inside your Performance object which in your case is fine since you have a string property called ShortDesc inside your Performance class.
That's the problem I see in your code. Change the type of the property ShortDesc like below and assign any one of the items in your collection TestList to it. Your code will start working fine.
private Performance _shortDesc;
public Performance ShortDesc
{
get { return _shortDesc; }
set
{
{
_shortDesc = value;
NotifyPropertyChanged();
}
}
}
Refer to the documentation here which explains a clear example for Binding objects to Picker.
I hope that helps.

How can I make a > in a cell with Xamarin.Forms?

I have an application where I can change the order and the way cards appear. For anyone who has iOS I need something very similar to the way the Settings > Contacts > Sort Order page works.
This shows two rows. One with First, Last and the other with Last, First. When a user clicks on a row it acts like a radio button and a tick mark appears at the end of the row.
I would like to try and implement this functionality but I am not sure where to start. Should I do this with a ViewCell or a TextCell and how does anyone have any ideas as to how it is implemented this
. 

EDIT 1: Simplified property changed logic in iOS renderer; now there are no references or handlers to cleanup.
In extension to #hankide's answer:
You can create a bindable property IsChecked while extending a TextCell or ViewCell and bind your VM state to it.
public class MyTextCell : TextCell
{
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
"IsChecked", typeof(bool), typeof(MyTextCell),
defaultValue: false);
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
}
Next step would be to create renderer that listens to this property and shows a check-mark at iOS level.
[assembly: ExportRenderer(typeof(MyTextCell), typeof(SampleApp.iOS.MyTextCellRenderer))]
namespace SampleApp.iOS
{
public class MyTextCellRenderer : TextCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var nativeCell = base.GetCell(item, reusableCell, tv);
var formsCell = item as MyTextCell;
SetCheckmark(nativeCell, formsCell);
return nativeCell;
}
protected override void HandlePropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.HandlePropertyChanged(sender, args);
System.Diagnostics.Debug.WriteLine($"HandlePropertyChanged {args.PropertyName}");
if (args.PropertyName == MyTextCell.IsCheckedProperty.PropertyName)
{
var nativeCell = sender as CellTableViewCell;
if (nativeCell?.Element is MyTextCell formsCell)
SetCheckmark(nativeCell, formsCell);
}
}
void SetCheckmark(UITableViewCell nativeCell, MyTextCell formsCell)
{
if (formsCell.IsChecked)
nativeCell.Accessory = UITableViewCellAccessory.Checkmark;
else
nativeCell.Accessory = UITableViewCellAccessory.None;
}
}
}
Sample usage 1
And, sample usage would like:
<TableView Intent="Settings">
<TableSection Title="Sort Order">
<local:MyTextCell Text="First Last" IsChecked="false" />
<local:MyTextCell Text="Last, First" IsChecked="true" />
</TableSection>
</TableView>
Sample usage 2
You can also listen to Tapped event to ensure IsChecked property works as expected.
For example, you bind this property to ViewModel:
<TableView Intent="Settings">
<TableSection Title="Sort Order">
<local:MyTextCell Tapped="Handle_Tapped" Text="{Binding [0].Name}" IsChecked="{Binding [0].IsSelected}" />
<local:MyTextCell Tapped="Handle_Tapped" Text="{Binding [1].Name}" IsChecked="{Binding [1].IsSelected}" />
</TableSection>
</TableView>
and handle tap event:
public SettingViewModel[] Settings = new []{
new SettingViewModel { Name = "First Last", IsSelected = false },
new SettingViewModel { Name = "Last First", IsSelected = true },
};
void Handle_Tapped(object sender, System.EventArgs e)
{
var cell = sender as TextCell;
if (cell == null)
return;
var selected = cell.Text;
foreach(var setting in Settings)
{
if (setting.Name == selected)
setting.IsSelected = true;
else
setting.IsSelected = false;
}
}
The sort order settings page you described is implemented using the UIKit's UITableView. In Xamarin.Forms, you can utilize the TableView control to get the same result.
As you will quickly notice, there's no way to set the checkmark icon with Xamarin.Forms so you'll probably need to create a custom cell, that has the text on the left and the checkmark image on the right.
If you really want to do everything by the book, you should probably create a custom renderer that allows you to set the Accessory property of the current ViewCell. However, this will get a bit complex for such a small feature.

Saving the state of multiple checkboxes for wp7

I created a button to create multiple checkbox on no. of clicks for wp7. Below the codes I used for it.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox x:Name="txtNewTask" HorizontalAlignment="Left" Height="72" TextWrapping="Wrap" VerticalAlignment="Top" Width="328"/>
<Button x:Name="btnAdd" Content="add" HorizontalAlignment="Left" Margin="328,0,0,0" VerticalAlignment="Top" Width="123" Click="btnAdd_Click"/>
<ListBox x:Name="lbToDoList" Margin="0,72,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Click="CheckBox_Click" Background="{x:Null}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" Name="tbkTextName" VerticalAlignment="Center" Margin="5,0,5,0" />
</StackPanel>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Now when I exit and re-open my app, I noticed the checkbox’s are unchecked (default state) and its state is not saved. Can you please help me to save the multiple checkbox's value or state?
Can anybody help me to save the multiple checkbox's state. Thanks in advance for your help!
You need to save data to a time when your application is not running. For that staff I use IsolatedStorage. You can save anything, what you need. I found great tutorial, how it implement. hope it's help.
I Think the best way is, to save the value of the checkbox instantly when it changes.
To do so you can do the following:
Assume that the check box in the myPage.xaml looks like:
<CheckBox Content="{Binding Title}" Name="myAutoSavingCheckBox" Click="myAutoSavingCheckBox_Click"/>
In the myPage.xaml.cs you have to define the following method:
private void myAutoSavingCheckBox_Click(object sender, RoutedEventArgs e)
{
App.ViewModel.MyProperty = myAutoSavingCheckBox.IsChecked;
}
The App.ViewModel is declared in the App.xaml.cs:
public partial class App : Application
{
...
public static MainViewModel ViewModel
{
get
{
// Erstellung des Ansichtsmodells verzögern bis erforderlich
if (viewModel == null)
viewModel = new MainViewModel();
return viewModel;
}
}
...
}
Now you define your Property and the saving Function in the MainViewModel.cs as follows:
public class MainViewModel
{
private bool? myProperty;
public bool? MyProperty
{
get
{
return myProperty;
}
set
{
if (value != myProperty)
{
myProperty = value;
SaveSetting("MyProperty", myProperty);
}
}
}
public void SaveSettings(string whatShallBeSavedKey, object whatShallBeSavedValue)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains("whatShallBeSavedKey"))
IsolatedStorageSettings.ApplicationSettings["whatShallBeSavedKey"] = whatShallBeSavedValue;
else
IsolatedStorageSettings.ApplicationSettings.Add("whatShallBeSavedKey", whatShallBeSavedValue);
}
}
Use IsolatedStorage.ApplicationSettings
Here are two helper methods for accessing application settings
/// Get the current value of the setting, or if it is not found, set the
/// setting to the default setting.
protected valueType GetValueOrDefault<valueType>(string Key, valueType defaultValue)
{
valueType value;
object storedValue = null;
try
{
if (_isolatedStore.TryGetValue(Key, out storedValue))
{
value = (valueType)(_isolatedStore[Key] ?? defaultValue);
}
else
{
//the key was not found
value = defaultValue;
}
}
catch (Exception ex)
{
value = defaultValue;
Logger.Error(ex, "Exception while getting IsolatedStorageSettings: ");
}
return value;
}
protected bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
object storedValue = null;
try
{
if (_isolatedStore.TryGetValue(Key, out storedValue))
{
if (storedValue != value)
{
_isolatedStore[Key] = value;
valueChanged = true;
}
}
else
{
//the key was not found
_isolatedStore.Add(Key, value);
}
}
catch (Exception ex)
{
Logger.Error(ex, "Exception while adding IsolatedStorageSettings.");
}
return valueChanged;
}
And you can then create a property on some settings class or view model that is backed by IsolatedStorage like this.
string CheckBoxValueKeyName = "checkbox_value";
bool CheckBoxValueDefault = false;
public bool CheckBoxValue
{
get
{
return GetValueOrDefault<bool>(CheckBoxValueKeyName, CheckBoxValueDefault );
}
set
{
AddOrUpdateValue(CheckBoxValueKeyName, value);
}
}
If you don't want to apply the changes of checking the box immediately to isolated storage, the WP7 Tombstone Helper is a quick way to persist the state of your controls after the app tombstones. So, yes, for persistent storage after the application is closed use Isolated Storage.

Resources