I'm making an app that scans for BLE devices and displays them in a ListView.
The problem is that when I once it displays the devices once but if I scan twice it result the devices twice etc.
This is the code what I got so far. In Mainpage.cs I create an ObservableCollection where I store the devices and which I clear everytime I call the scan methode.
<StackLayout Margin="15,15,10,15" >
<Label Text="Paired Devices" HorizontalOptions="Center" FontSize="Subtitle"/>
<ListView x:Name="paired" ItemsSource="{Binding deviceList}" ItemTapped="Paired_ItemTapped" BackgroundColor="White" SeparatorColor="Black">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Mainpage.cs
private void Button_Clicked(object sender, EventArgs e)
{
if(ble.State == BluetoothState.Off)
{
DisplayAlert("Bluetooth", "Please turn on bluetooth", "OK");
}
deviceList.Clear();
adapter.DeviceDiscovered += (s, a) =>
{
if (a.Device.Name != null)
{
deviceList.Add(a.Device);
}
Console.WriteLine(deviceList.Count);
};
if (!ble.Adapter.IsScanning)
{
adapter.StartScanningForDevicesAsync();
}
}
You have not shown the entire code here which you should have. So without that this is simply conjecture. The most probable cause to me of this occurring is you are adding the values to deviceList without removing the previous items.
Make sure when you are adding the items to deviceList to remove the old items in your Collection by either instantiating a new object of your Collection or by deleting unwanted (old) items from your Collection before adding any new items to it.
Related
My List MyWordsList has 10000 elements. I am Trying to add the next 100 elements in collectionview every time I scoll down.
Here is my code c#:
public MainPage()
{
Var MyWordsList = await mywordsdatabase.GetWords();
WordSList.ItemsSource =MyWordsList.Take(100); // start with 100 elemets in the list;
WordSList.RemainingItemsThreshold = 5;
WordSList.RemainingItemsThresholdReached += WordSList_RemainingItemsThresholdReached;
}
private void WordSList_RemainingItemsThresholdReached(object sender, EventArgs e)
{
// Load More Data Here when scroll down
// Take the next 100 elements
// if all the elements are added do not add
}
Here is Xaml code :
<CollectionView x:Name="WordSList" ItemsLayout="Vertical" >
<CollectionView.ItemTemplate >
<DataTemplate>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Label TextColor="#7D7D7D" Text="{Binding Word1}" FontSize="15" />
<Label TextColor="Black" Text=" - " FontSize="15" />
<Label TextColor="#0F9D58" Text="{Binding Word2}" FontSize="15" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Thanks for your help
when you do this you are making a local variable that only exists in the method that contains it.
Var MyWordsList = await mywordsdatabase.GetWords();
because you want to use this data later, you need to make it a class variable. You also need a variable to store your data source in
List<MyClass> MyWordsList;
ObservableCollection<MyClass> datasource;
int ndx = 100;
public MainPage()
{
MyWordsList = await mywordsdatabase.GetWords();
WordSList.ItemsSource = datasource = new ObservableCollection<MyClass>(MyWordsList.Take(ndx));
...
}
then
private void WordSList_RemainingItemsThresholdReached(object sender, EventArgs e)
{
datasource.AddRange(MyWordsList.Skip(ndx).Take(100));
ndx += 100;
}
Not sure what is your intention here regarding the 10000 items. if you are fine to load them all at once
MyWordsList = await mywordsdatabase.GetWords();
Then you don't need the rest of code as CollectView supports virtualization through the underline control. You can feed the whole collection and it will dynamically allocate/deallocate the item UI element as needed efficiently.
If loading 10000 items from database takes too long, that is where you need to mess around with _RemainingItemsThreshold etc. First the database interface needs to be modified to be able to return only segment of items e.g. mywordsdatabase.GetWords(startIndex, count);Then it is probably a good idea to refer some of infinite scrolling implementation:
https://doumer.me/infinite-scroll-with-the-xamarin-forms-collection-view/
I have a <List> that adds and removes elements by calling a modal from a <Button> as shown in the figure.
When lifting the modal, I show the user the elements that can be associated to the main list and also indicate with a <Switch> if these elements are added or not, with the objective that when pressing the switch add or remove elements from the main list
The problem is that when the modal is lifted, the method that adds and deletes elements to the list is executed and every time I raise the modal, my records are duplicated, as shown in the figure
This is due to the fact that when lifting the modal, the method that adds or removes chemicals is executed, this is called every time the property value that is binded to the <Switch> in the view changes
Why is this happening? How can I avoid it?
Then I present my code ...
MODAL.XAML:
<StackLayout
BindingContext="{Binding AgregarSustancia}">
<ListView
ItemsSource="{Binding ListaSustancias}"
SelectedItem="{Binding SelectedSustancia}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout Orientation="Vertical">
<Label Text="{Binding NombreSustancia}"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"/>
</StackLayout>
<Switch
OnColor="{StaticResource das.color.verde}" HorizontalOptions="EndAndExpand"
VerticalOptions="Start"
IsToggled="{Binding SustanciaAsociada, Mode=OneWay}">
</Switch>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout/>
AGREGARSUSTANCIA.CS:
bool sustanciaAsociada;
[JsonProperty(PropertyName = "chemicalIsAssociateWithInstallation")]
public bool SustanciaAsociada
{
get
{
return sustanciaAsociada;
}
set
{
if (value != sustanciaAsociada)
{
sustanciaAsociada = value;
AsociarDesasociar(sustanciaAsociada);
}
}
}
//METHOD THAT ADDS OR ELIMINATES DEPENDING ON THE VALUE OF THE PARAMETER
private async void AsociarDesasociar(bool sustanciaAsociada)
{
//ADD TO LIST
if (sustanciaAsociada)
{
}
else //REMOVE TO LIST
{
}
}
Then my ViewModel that fills the modal list
VIEWMODEL.CS: (MODAL)
#region Constructor
public AgregarSustanciaViewModel(ObservableCollection<AgregarSustancia> listaAgregarSustancia)
{
navigationService = new NavigationService();
ListaSustancias = new ObservableCollection<AgregarSustancia>();
listaSustanciasAux = new List<AgregarSustancia>(listaAgregarSustancia);
ListaSustancias = listaAgregarSustancia;
}
#endregion
How can I prevent the method AsociarDesasociar() in the Get-Set property of the Switch from executing the modal? How can I encapsulate this method?
Any help for me?
create a bool InitComplete and initialize it to false. This will prevent AsociarDesasociar from executing before initialization is complete
if (value != sustanciaAsociada)
{
sustanciaAsociada = value;
if (InitComplete) {
AsociarDesasociar(sustanciaAsociada);
}
}
after your class has finished whatever initialization is required, then set InitComplete = true
Hello I'm new to Xamarin development. I am trying to implement the address bar feature in the application. When user starts typing the address I want to show the suggestions using Googles places API.
I have already got the background service calls to google and getting the suggestions in a LIST and trying to bind the list in the VIEW. But when binding the application is crashing and look of List is also doesn't look as expected.
View:
<Entry Placeholder="From Address" x:Name="FromAddressTxtbx" Text="{Binding AddressText}" TextChanged="Handle_TextChanged_1"/>
<ListView ItemsSource="{Binding Addresses}" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Address}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Can anyone please provide me a suggestion or Direction I want this look like address bar in the UBER app.
Thank in advance
Here is a solution about using Entry and ListView to show updated list when text changed in Entry.
Xaml:
<Entry x:Name="MainEntry" TextChanged="MainEntry_TextChanged" Placeholder="Inupt Adress"/>
<ListView x:Name="NameListView" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding .}" TextColor="Navy" FontSize="40"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ContentPage:First setting example data for ListView,
List<string> adressnames = new List<string>()
{
"Alabama", "Florida" , "Kentucky" , "Missouri", "North Carolina" ,"South Dakota" , "Wisconsin"
};
NameListView.ItemsSource = adressnames;
Now when Text changed , ListView will list updated data:
private void MainEntry_TextChanged(object sender, TextChangedEventArgs e)
{
var keyword = MainEntry.Text;
NameListView.ItemsSource = adressnames.Where(name => name.Contains(keyword));
}
By the way , you also can use SearchBar to achieve it:
<SearchBar x:Name="MainSearchBar" TextChanged="MainSearchBar_TextChanged" Placeholder="Inupt Adress"/>
With text Changed method:
private void MainSearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
var keyword = MainSearchBar.Text;
NameListView.ItemsSource = adressnames.Where(name => name.Contains(keyword));
}
I have an item class with values for name and price which are stored in an SQLite database. I'm displaying them in a Listview with a Label for the name and an Entry for the price.
<ListView x:Name="itemListView">
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding name}"/>
<Entry Text="{Binding Path=price, Mode=TwoWay, StringFormat='{}{0:c}'}" Keyboard="Numeric" Completed="updateItem" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView>
I want to make it so when the Entry change is completed it will update the item in the SQLite database with the new value for price, however, I don't know how to retrieve the Item which was finished from the Listview. I think I need to use the following method but I don't know what to put in it.
async void updateItem(object sender, EventArgs e)
{
//Code to update the item with the SQLite database with the new price
}
in your updateItem handler, then BindingContext of the item should be element from the ItemSource that is being updated
async void updateItem(object sender, EventArgs e)
{
var item = (MyItemType) ((Entry)sender).BindingContext;
//Code to update the item with the SQLite database with the new price
}
Hi so I'm doing a note taking app and Ive got it connected to my SQL Azure Database.
The items get automatically populated through MobileServiceCollectionView.
After tapping an item, a detailView should be opened to the right...
I dont know why but tapping an item does not select it, so I cant check for listView.SelectedItem in the noteListView_Tapped event.....
What is wrong with my listview?
<ListView x:Name="noteListView" Margin="20,0,0,0" Tapped="noteListView_Tapped">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="2">
<CheckBox x:Name="CheckBoxComplete" IsChecked="{Binding Complete, Mode=TwoWay}" Checked="CheckBoxComplete_Checked" Padding="3"/>
<TextBlock x:Name="TextBlockTodoItem" Text="{Binding Title}" Padding="3" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And here the Tapped event.. It crashed on TodoItem t = (TodoItem)lv.SelectedItem;
So i added the if condition and now nothing happens except for the debug prints.
private void noteListView_Tapped(object sender, TappedRoutedEventArgs e)
{
Debug.WriteLine("0");
ListView lv = (ListView)sender;
if (lv.Items.Count > 0)
{
if (lv.SelectedItems.Count > 0)
{
TodoItem t = (TodoItem)lv.SelectedItem;
Debug.WriteLine("1");
Debug.WriteLine(t.Title);
try
{
Location l = TodoItem.StringToLocation(t.LocationTaken);
Debug.WriteLine("2");
MapLayer.SetPosition(locationIcon, l);
map.SetView(l, 15.0f);
}
catch (Exception ex)
{
Debug.WriteLine("Map set position failed.: " + ex.Message);
}
}
}
}
So what do I have to change or how do I know which item has been clicked/selected?
Why not just use the SelectionChanged event on the listview?
<ListView SelectionChanged="noteListView_SelectionChanged">
Then in your code behind
private void noteListView_SelectionChanged(object sender, RoutedEventArgs e)
{
if((sender as ListView).Items.Count > 0)
{
.....
}
}
I think (though I'm not sure) that your problem is that tapping the listView, and so the tapped event, is not the same as selecting an item in the list.