I have a very short question, I have a project built with Xamarin. I am using realm db in this project. And what I want to do is delete all data on realm db whenever I press a button. I can do this in listview with item selected, but I want to delete all data with a single button.
Thank you in advance for your help. Stackoverflow has taught me a lot.
I am using realm db in this project. And what I want to do is delete all data on realm db whenever I press a button. I can do this in listview with item selected, but I want to delete all data with a single button.
If you want to delete all Realm Db record , please take a look the following code.
My model,
public class Student : RealmObject
{
[PrimaryKey]
public int StudentID { get; set; }
public string StudentName { get; set; }
}
MainPage
<StackLayout>
<ListView x:Name="listStudent">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding StudentName}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button
x:Name="Addbtn"
Clicked="Addbtn_Clicked"
Text="add data" />
<Button
x:Name="deletebtn"
Clicked="deletebtn_Clicked"
Text="delete all data" />
</StackLayout>
public partial class Page30 : ContentPage
{
public Page30()
{
InitializeComponent();
}
private void Addbtn_Clicked(object sender, EventArgs e)
{
var realmDB = Realm.GetInstance();
for (int i = 0; i < 20; i++)
{
Student item = new Student()
{
StudentID = i,
StudentName = "cherry " + i
};
realmDB.Write(() =>
{
realmDB.Add(item);
});
}
List<Student> students = realmDB.All<Student>().ToList();
listStudent.ItemsSource = students;
}
private void deletebtn_Clicked(object sender, EventArgs e)
{
var realmDB = Realm.GetInstance();
realmDB.Write(() =>
{
realmDB.RemoveAll();
});
List<Student> students = realmDB.All<Student>().ToList();
listStudent.ItemsSource = students;
}
}
Related
I am using checkbox control under repeater to do a radio button functionality, everything seems to be fine but now stuck on how to bind the checkbox when the page loads. I have saved the radio button text whichever was selected and once user come back to page again I want to bin what he has selected last time. Not getting any hint here how to proceed.
<grial:Repeater
x:Name="PP"
SelectionMode="Single"
InitialSelection="Empty"
ItemSize="100"
HorizontalOptions="Start"
ItemsSource="{Binding BlowerPostions}">
<grial:Repeater.ItemTemplate>
<DataTemplate>
<grial:Checkbox
IsChecked="false"
UncheckedBorderColor="Black">
<Label
TextColor="Black"
Text="{ Binding . }"
Margin="8,0" />
</grial:Checkbox>
</DataTemplate>
</grial:Repeater.ItemTemplate>
<grial:Repeater.SelectedItemTemplate>
<DataTemplate>
<grial:Checkbox
IsChecked="true"
UncheckedBorderColor="Black"
InputTransparent="true">
<Label
TextColor="Black"
Text="{ Binding . }"
Margin="8,0" />
</grial:Checkbox>
</DataTemplate>
</grial:Repeater.SelectedItemTemplate>
</grial:Repeater>
View Model :
public class ProductionViewModel : INotifyPropertyChanged
{
public ObservableCollection<BlowerPostion> _blowerPostions;
public ObservableCollection<BlowerPostion> BlowerPostions
{
get => _blowerPostions;
set
{
_blowerPostions = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs("BlowerPostions"));
}
}
}
public void LoadData()
{
BlowerPostions = new ObservableCollection<BlowerPostion>();
BlowerPostions.Add(new BlowerPostion("Left", 1));
BlowerPostions.Add(new BlowerPostion("Standard", 1));
}
}
public class BlowerPostion
{
public string Text { get; set; }
public int Id { get; set; }
public BlowerPostion(string _text, int _id)
{
Text = _text;
Id = _id;
}
}
I don't use grial:Repeater,but you can refer to the following code which use CheckBox in ListView item.
Item.cs
public class Item
{
public string Name { get; set; }
public string Type { get; set; }
public string Image { get; set; }
//This field indicates whether or not it is selected
public bool isChecked { get; set; }
}
MyViewModel.cs
public class MyViewModel
{
public ObservableCollection<Item> items { get; private set; }
public MyViewModel() {
items = new ObservableCollection<Item>();
items.Add(new Item { Name = "Tomato", Type = "Fruit", Image = "tomato.png", isChecked = true });
items.Add(new Item { Name = "Romaine Lettuce", Type = "Vegetable", Image = "lettuce.png", isChecked = false });
items.Add(new Item { Name = "Zucchini", Type = "Vegetable", Image = "zucchini.png", isChecked = false });
}
}
TestPage1.xaml
<ContentPage.Content>
<ListView x:Name="listview" ItemsSource="{Binding items}" VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5,0,5,0">
<Label Text="{Binding Name}" HorizontalOptions="StartAndExpand" FontSize="30"/>
<input:CheckBox IsChecked="{Binding isChecked}" Type="Check" Color="White" BoxBackgroundColor="Green" TextColor="White" HeightRequest="40"
CheckChanged="CheckBox_CheckChanged" BindingContext="{Binding .}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
TestPage1.xaml.cs
public partial class TestPage1 : ContentPage
{
public List<Item> selectedItems; // define `selectedItems` as the list of selected items.
public MyViewModel viewModel;
public TestPage1 ()
{
InitializeComponent ();
selectedItems = new List<Item>(); // init the `selectedItems`
viewModel = new MyViewModel();
BindingContext = viewModel;
}
private void CheckBox_CheckChanged(object sender, EventArgs e)
{
var checkbox = (Plugin.InputKit.Shared.Controls.CheckBox)sender;
var ob = checkbox.BindingContext as Item;
if (ob != null)
{
System.Diagnostics.Debug.WriteLine("isChecked = " + ob.isChecked + "<---> Name = " + ob.Name +"<---> Type = " + ob.Type );
if (ob.isChecked)
{
selectedItems.Add(ob);
}
else {
// remove the item
}
}
}
}
Note:
1.add new field isChecked in item model
public bool isChecked { get; set; }
2.Add event CheckChanged for the item.And when we check the CheckBox,we can get the corresponding value isChecked of the CheckBox.
<input:CheckBox IsChecked="{Binding isChecked}" Type="Check" Color="White" BoxBackgroundColor="Green" TextColor="White" HeightRequest="40"
CheckChanged="CheckBox_CheckChanged" BindingContext="{Binding .}" />
I'm getting two collections of data from a web service - the full collection and then a subset of items. The subset should be selected on load. I cannot get the SelectedItems to show as selected in the CollectionView, event though that property is set. I've looked over the Monkeys example and all over the web but can't find an example just like this
View:
<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
<CollectionView x:Name="ExperiencesCollectionView"
ItemsSource="{Binding Experiences}"
SelectedItems="{Binding ProfileExperiences, Mode=TwoWay}"
SelectionMode="Multiple">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label
Text="{Binding Description}"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
</StackLayout>
Code Behind:
public partial class ExperiencesPage : ContentPage
{
ExperiencesViewModel viewModel;
public ExperiencesPage()
{
InitializeComponent();
BindingContext = viewModel = new ExperiencesViewModel();
}
protected override void OnAppearing()
{
base.OnAppearing();
if (viewModel.Experiences.Count == 0)
viewModel.IsBusy = true;
}
ViewModel:
public class ExperiencesViewModel : BaseViewModel
{
public ObservableCollection<Experience> Experiences { get; set; }
public ObservableCollection<object> ProfileExperiences { get; set; }
public Command LoadItemsCommand { get; set; }
public string InterestedIn { get; set; }
public ExperiencesViewModel()
{
Title = "My Experiences";
Experiences = new ObservableCollection<Experience>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
}
async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
Experiences.Clear();
//Get these from the REST service
var experiences = await App.ExperienceManager.GetExperiencesAsync();
var serviceExperiences = await App.ExperienceManager.GetProfileExperiencesAsync();
foreach (var exp in experiences)
{
Experiences.Add(exp);
}
foreach (var profileExp in serviceExperiences)
{
ProfileExperiences.Add(profileExp);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
I do not load a small data from the API, in C# code, they are loaded in advance and everything seems to be fine, but as soon as I open the page where ItemsSource = "{Binding BigData}", my UI is blocked for 10 seconds.
Are there any ideas to open the page first, then start loading data without blocking the UI?
I would to suggest you can kick off a task in your view models constructor that loads the data. Using Async and await to load bid data.
I do one sample that using ListView to display 100000 records.
<StackLayout>
<Label Text="test ui in xamarin.forms asyn" />
<ActivityIndicator IsRunning="{Binding isBusy}" IsVisible="{Binding isBusy}" />
<ListView x:Name="listview1" ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding name}" />
<Label HorizontalOptions="CenterAndExpand" Text="{Binding age}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public partial class Page19 : ContentPage
{
public Page19()
{
InitializeComponent();
this.BindingContext = new ItemsViewModel();
}
}
public class ItemsViewModel:ViewModelBase
{
private bool _isBusy;
public bool isBusy
{
get { return _isBusy; }
set
{
_isBusy = value;
RaisePropertyChanged("isBusy");
}
}
public ObservableCollection<people> Items { get; set; }
public ItemsViewModel()
{
Items = new ObservableCollection<people>();
isBusy = true;
Task.Run(async () => await LoadItems());
}
public async Task LoadItems()
{
var items = new ObservableCollection<people>(); // new collection
if (isBusy)
{
await Task.Delay(10000);
// var loadedItems = ItemsService.LoadItemsDirectory();
//foreach (var item in loadedItems)
// items.Add(item);
for (int i = 0; i < 100000; i++)
{
people p = new people();
p.name = "people " + i;
p.age = i;
items.Add(p); // items are added to the new collection
}
Items = items; // swap the collection for the new one
RaisePropertyChanged(nameof(Items)); // raise a property change in whatever way is right for your VM
isBusy = false;
}
}
}
public class people
{
public string name { get; set; }
public int age { get; set; }
}
ViewModelBase is one class that implementing INotifyPropertyChanged
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
My Accounts CollectionView is not updating with the Searchbar. Xaml below.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewmodels="clr-namespace:Pricing051721.ViewModels"
x:Class="Pricing051721.MainPage" Title="KR Pricing"
x:Name="This">
<ContentPage.BindingContext>
<viewmodels:MainPageViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Button Text="Logout" Command="{Binding LogoutCommand}" Margin="0,5,0,5"/>
<SearchBar x:Name="searchBar"
SearchCommand="{Binding PerformSearch}"
SearchCommandParameter="{Binding Text, Source={x:Reference searchBar}}"/>
<CollectionView ItemsSource="{Binding Accounts}" Margin="5">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5" >
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.AccountSelected, Source={x:Reference This}}" CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<StackLayout >
<Label FontSize="Medium" Text="{Binding Name}" ></Label>
<Label Text="{Binding Address}"></Label>
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
I am trying to search through the Accounts already queried in the view model so I don't have to hit the database again. The search works, but Accounts is not updated.
namespace Pricing051721.ViewModels
{
public class MainPageViewModel : INotifyPropertyChanged
{
public ObservableCollection<Account> Accounts { get; set; }
public INavigation Navigation { get; set; }
public ICommand LogoutCommand { get; set; }
AdAuthenticationService authService;
public ObservableCollection<Account> baseAccountList;
public MainPageViewModel()
{
Accounts = new ObservableCollection<Account> { new Account { AllowUpdate = true, Address = "Wait", Name = "Loading" } };
authService = new AdAuthenticationService();
Task.Run(async () =>
{
if (!authService.IsAuthenticated)
{
var response = authService.Authenticate();
await Update(response.AccessToken, "");
}
else await Update(authService.AccessToken, "");
});
AccountSelected = new Command<Account>(async (a) =>
{
if (!a.AllowUpdate)
return;
await Navigation.PushAsync(new UpdateAccountView(a));
return;
var result = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Name,
OkText = "Change",
Title = "Enter New Column Break",
Text = a.ColumnBreak
});
if (result.Ok && result.Text != null && !result.Text.Trim().Equals(""))
{
a.ColumnBreak = result.Text;
isUpdating = true;
var ok = await crm.Update(a);
var message = ok ? "Account Updated!" : "Unable to update!";
await UserDialogs.Instance.AlertAsync(new AlertConfig
{
Title = "Message",
Message = message,
OkText = "Ok"
});
isUpdating = false;
}
}, _ => !isUpdating);
LogoutCommand = new Command(new Action(() => {
authService.Logout();
Environment.Exit(Environment.ExitCode);
}));
}
//search
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand PerformSearch => new Command<string>((string query) =>
{
Accounts = SearchAccounts(query);
});
private bool isUpdating = false;
private Crm crm;
public ObservableCollection<Account> accounts;
public async Task Update(string accessToken, string query)
{
Crm.Setup(accessToken);
crm = Crm.AuthenticatedCrmService;
var accounts = await crm.GetAccounts();
Accounts.RemoveAt(0);
accounts.ForEach(a => Accounts.Add(a));
}
public ObservableCollection<Account> SearchAccounts(string query)
{
Task.Run(async () =>
{
if (!authService.IsAuthenticated)
{
var response = authService.Authenticate();
await Update(response.AccessToken, "");
}
else await Update(authService.AccessToken, "");
});
baseAccountList = Accounts;
if (!(query == ""))
{
var normalizedQuery = query?.ToLower() ?? "";
List<Account> accountsList = (List<Account>)Accounts.Where(f => f.Name.ToLowerInvariant().Contains(normalizedQuery)).ToList();
ObservableCollection<Account> accounts = new ObservableCollection<Account>(accountsList);
Accounts.Clear();
return accounts;
}
else
{
accounts = Accounts;
return accounts;
}
}
public ICommand AccountSelected { get; set; }
}
}
I don't need a neat solution (as you can tell by my code so far), just something that will work Thanks in advance!
My Accounts CollectionView is not updating with the Searchbar
From your code, you don't post some code about PerformSearch command, I don't know how do you search data by searchbar. I do one sample about search some data by searchbar, display in collectionview, you can modify your code according to the following code.
<SearchBar
x:Name="searchBar"
SearchCommand="{Binding PerformSearch}"
SearchCommandParameter="{Binding Text, Source={x:Reference searchBar}}" />
<CollectionView Margin="5" ItemsSource="{Binding Accounts}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<!--<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.AccountSelected, Source={x:Reference This}}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>-->
<StackLayout>
<Label FontSize="Medium" Text="{Binding Name}" />
<Label Text="{Binding Address}" />
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
public partial class Page15 : ContentPage
{
public Page15()
{
InitializeComponent();
this.BindingContext = new AccountViewModel();
}
}
public class AccountViewModel
{
public ObservableCollection<Account> AccountList { get; set; }
public ObservableCollection<Account> Accounts { get; set; }
public ICommand PerformSearch { get; set; }
public AccountViewModel()
{
AccountList = new ObservableCollection<Account>();
Accounts = new ObservableCollection<Account>();
for(int i=0;i<30;i++)
{
Account a = new Account();
a.Name = "account" + i;
a.Address = "address " + i;
AccountList.Add(a);
Accounts.Add(a);
}
PerformSearch = new Command(search => {
if(search!=null)
{
string searchtext = (string)search;
if (!string.IsNullOrEmpty(searchtext))
{
Accounts.Clear();
List<Account> list= AccountList.Where((account) => account.Name.ToLower().Contains(searchtext) || account.Address.ToLower().Contains(searchtext)).ToList();
foreach(Account a in list)
{
Accounts.Add(a);
}
}
Accounts = AccountList;
}
else
{
Accounts = AccountList;
}
});
}
}
public class Account
{
public string Name { get; set; }
public string Address { get; set; }
}
I have in my Xaml a pivot control :
<controls:Pivot ItemsSource="{Binding ObjectList}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Value1}" />
<TextBlock Text="{Binding Value2}" />
</StackPanel>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
My ViewModel is :
public class MyObject
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}
public class MyViewModel : ViewModelBase
{
public const string ObjectListPropertyName = "ObjectList";
private ObservableCollection<MyObject> _objectList;
public ObservableCollection<MyObject> ObjectList
{
get
{
return _objectList;
}
private set
{
if (_objectList == value)
return;
_objectList = value;
RaisePropertyChanged(ObjectListPropertyName);
}
}
private DispatcherTimer timer;
public MyViewModel()
{
ObservableCollection<MyObject> collection = new ObservableCollection<MyObject>
{
new MyObject {Value1 = "One"},
new MyObject {Value1 = "Two"},
new MyObject {Value1 = "Tree"}
};
ObjectList = collection;
timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2)};
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
foreach (MyObject myObject in _objectList)
{
myObject.Value2 = "Something";
}
Application.Current.RootVisual.Dispatcher.BeginInvoke( () => RaisePropertyChanged(ObjectListPropertyName));
}
}
When the timer_tick is reached, I supposed the pivot control to refresh with the new values ... but I can't see any changes.
What do I miss ?
Thanks in advance for your help
I'm guessing that possibly updating the members of the list without updating the list itself is the problem. When you raise the property changed event - it is for the entire collection. The collection is still pointing to an equal reference of itself, despite the fact that the members have changed.
Try placing a breakpoint in the setter and see if the property changed event is fired.