I have this search bar function in my Xamarin forms app and it works perfectly fine when you start to type all the information but when you start to delete the words. The view doesnt refresh and it just clears all the information.
Here is the code for the search
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
SearchBar searchBar = (SearchBar)sender;
noMowersFoundLabel.IsVisible = false;
//Check if the user cleared the text bar, if so: reload list of mowers
if (searchBar.Text.Length == 0)
{
_viewModel.IsBusy = true;
return;
}
//Max 6 digits in a serial number
if (searchBar.Text.Length < 6)
{
//compares substrings to add to the list while the user has not entered full serial number
var sorted = new List<Mower>();
foreach (var m in _viewModel.Items)
{
if (m.MachineSerialNumber.Length > searchBar.Text.Length)
{
//var serialNum = m.MachineSerialNumber.Substring(0, Math.Min(searchBar.Text.Length, 6));
if (m.MachineSerialNumber.Contains(searchBar.Text))
{
sorted.Add(m);
}
}
}
foreach(var m in sorted)
{
if (!m.MachineSerialNumber.Contains(searchBar.Text))
{
sorted.Remove(m);
}
}
sorted.Sort((p1, p2) => (p1.MachineSerialNumber.CompareTo(p2.MachineSerialNumber)));
if(sorted.Count != 0)
{
_viewModel.Items.Clear();
foreach(var m in sorted)
{
_viewModel.Items.Add(m);
}
}
else
{
_viewModel.Items.Clear();
noMowersFoundLabel.IsVisible = true;
}
}
else //user has entered full serial number
{
Mower selectedItem = null;
foreach (var m in _viewModel.Items)
{
if(m.MachineSerialNumber == searchBar.Text)
{
selectedItem = m;
}
}
if(selectedItem != null)
{
//We found the item
_viewModel.Items.Clear();
_viewModel.Items.Add(selectedItem);
}
else{
//No item found
_viewModel.Items.Clear();
noMowersFoundLabel.IsVisible = true;
}
}
I want the view to populate the information when you start to delete words
I don't think it is necessary to diffentiate the length of the input string.
I created a demo and achieved this function, you can refer to the following code:
MyViewModel.cs
public class MyViewModel
{
public ObservableCollection<Item> Items { get; set; }
public MyViewModel() {
Items = new ObservableCollection<Item>();
Items.Add(new Item { Name="name1" , MachineSerialNumber="0001"});
Items.Add(new Item { Name = "name2", MachineSerialNumber = "0102" });
Items.Add(new Item { Name = "name3", MachineSerialNumber = "1203" });
Items.Add(new Item { Name = "name4", MachineSerialNumber = "11204" });
}
public List<Item> GetSearchResults(string queryString)
{
var normalizedQuery = queryString?.ToLower() ?? "";
return Items.Where(f => f.MachineSerialNumber.ToLowerInvariant().Contains(normalizedQuery)).ToList();
}
}
Item.cs
public class Item
{
public string Name { get; set; }
public string MachineSerialNumber { get; set; }
}
TestPage1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SearchBarDemos.TestPage1">
<ContentPage.Content>
<StackLayout>
<SearchBar x:Name="searchBar"
HorizontalOptions="Fill"
VerticalOptions="CenterAndExpand"
Placeholder="Search fruits..."
CancelButtonColor="Orange"
PlaceholderColor="Orange"
TextTransform="Lowercase"
HorizontalTextAlignment="Start"
TextChanged="searchBar_TextChanged"/>
<Label Text="Type in the searchbox to filter results in realtime."
HorizontalOptions="Fill"
VerticalOptions="CenterAndExpand" />
<ListView x:Name="searchResults" ItemsSource="{Binding Items}"
HorizontalOptions="Fill"
VerticalOptions="CenterAndExpand" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}"
Detail="{Binding MachineSerialNumber}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
TestPage1.xaml.cs
public partial class TestPage1 : ContentPage
{
MyViewModel _viewModel;
public TestPage1()
{
InitializeComponent();
_viewModel = new MyViewModel();
this.BindingContext = _viewModel;
}
private void searchBar_TextChanged(object sender, TextChangedEventArgs e)
{
searchResults.ItemsSource = _viewModel.GetSearchResults(e.NewTextValue);
}
}
Note:
I added a function GetSearchResults into MyViewModel.cs
public List<Item> GetSearchResults(string queryString)
{
var normalizedQuery = queryString?.ToLower() ?? "";
return Items.Where(f => f.MachineSerialNumber.ToLowerInvariant().Contains(normalizedQuery)).ToList();
}
And once entering the input string, we can do as follows:
private void searchBar_TextChanged(object sender, TextChangedEventArgs e)
{
searchResults.ItemsSource = _viewModel.GetSearchResults(e.NewTextValue);
}
Related
I have a JSON, like the image below:
I have a ComboBox inside a ListView. I want to display "pairs" in the ComboBox.
XAML:
<ListView Name="ListPairOption">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:PairClass">
<StackPanel
x:Name="pilganStack">
<WebView
x:Name="option"
local:MyProperties.HtmlString="{Binding Name}"/>
</StackPanel>
<ComboBox
x:Name="pairOption"
DisplayMemberPath="NameA"
SelectedValue="{Binding ComboBoxClass, Mode=TwoWay}"
ItemsSource="{x:Bind PilihanS}"
PlaceholderText="Pilih" />
</ListView
Codes:
try
{
JsonObject jsonObject = JsonObject.Parse(jsonText);
JsonObject questionObject = jsonObject["EXAM_QUESTION"].GetObject();
ObservableCollection<PairClass> itemL = new ObservableCollection<PairClass>();
JsonArray mapArray = questionObject["map"].GetArray();
foreach (JsonValue mapValue in mapArray)
{
JsonArray mapArrayI = mapValue.GetArray();
PairClass pair = new PairClass();
foreach (JsonValue mapValueI in mapArrayI)
{
try
{
string v = mapValueI.ToString();
pair.Name = v;
}
}
}
itemL.Add(pair);
}
JsonArray pairArray = questionObject["pairs"].GetArray();
string pairString = "";
foreach (JsonValue pairValue in pairArray)
{
JsonArray pairArrayI = pairValue.GetArray();
List<ComboBoxClass> PilihanS = new List<ComboBoxClass>();
foreach (JsonValue pairValueI in pairArrayI)
{
try
{
var collection = Regex.Matches(v, "\\\"(.*?)\\\"");
foreach (var item in collection)
{
string v3 = item.ToString().Trim('"');
pairString = v3;
}
}
}
PilihanS.Add(new ComboBoxClass() { NameA = pairString });
}
ListPairOption.ItemsSource = itemL;
}
PairClass:
public class PairClass
{
public string Name { get; set; }
public ObservableCollection<ComboBoxClass> PilihanS { get; set; }
public PairClass(string name)
{
Name = name;
}
}
public class ComboBoxClass
{
public string NameA { get; set; }
public override string ToString()
{
return this.NameA;
}
}
}
From the code above, I didn't succeed in displaying it into a ComboBox in a ListView so that the ComboBox is empty, as shown below:
How to display it into a ComboBox?
From the code above, I didn't succeed in displaying it into a ComboBox in a ListView so that the ComboBox is empty, as shown below:
If you want to access the property that out of DataType, please using Binding ElementName=Control Name then access the the outside property from the parent DataContext. please note you need to set current page DataContext as this this.DataContext = this;. it could make sure you can access PilihanS where in the code behind from DataTemplate.
<ComboBox
x:Name="pairOption"
ItemsSource="{Binding DataContext.PilihanS, ElementName=ListPairOption}"
PlaceholderText="Pilih" />
code behind
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
public List<ComboBoxClass> PilihanS { get; set;} = new List<ComboBoxClass>();
And delete this line where in your code above List<ComboBoxClass> PilihanS = new List<ComboBoxClass>();
XAML:
<ComboBox x:Name="cmb" HorizontalAlignment="Left"
Margin="183,39,0,0"
VerticalAlignment="Top"
Width="120"
ItemsSource="{Binding FilteredNames, Mode=OneWay}"
IsTextSearchEnabled="True"
IsEditable="True"
TextSearch.Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}"/>
ViewModel:
public List<string> FilteredNames
{
get
{
return (names.FindAll(x => x.Contains(filter))).ToList<string>();
}
}
public string Filter
{
get
{
return this.filter;
}
set
{
this.filter = value;
NotifyPropertyChanged("FilteredNames");
}
}
public ViewModel()
{
this.names = new List<string>() { "Jerry", "Joey", "Roger", "Raymond", "Jessica", "Mario",
"Jonathan" };
this.filter = "";
}
This is what I have implemented. Please help me out how to get filtered dropdown in combobox.
Like when I input "j", I want to get all the items containing "j" in it.
You should bind string input to ComboBox's Text property:
Text="{Binding Filter, UpdateSourceTrigger=PropertyChanged}"
Also I would suggest using CollectionView for filtering like this:
public ICollectionView FilteredNames { get; set; }
IList<string> names = new List<string>() { "Jerry", "Joey", "Roger", "Raymond", "Jessica", "Mario", "Jonathan" };
public VM()
{
FilteredNames = CollectionViewSource.GetDefaultView(names);
FilteredNames.Filter = (obj) =>
{
if (!(obj is string str))
return false;
return str.Contains(filter);
};
}
string filter = "";
public string Filter
{
get
{
return this.filter;
}
set
{
this.filter = value;
FilteredNames?.Refresh();
}
}
I have a DataGrid that has TextWrapping enabled in cells. Meaning that rows don't have same height. My question is how do I loop through rows and get whats the height of each one?
How the DataGrid looks like:
Here is the datagrid code:
public ObservableCollection<Article> persons = new ObservableCollection<Article>();
for(int i = 0; i < 35; i++)
{
persons.Add(new Article("Restless legs syndrome and tis correlation with other sleep problems in the general adult population of Japan",
"Minori Enomoto, Lan Li, Sayaka Aritake, Yukihiro Nagase, Tatsuhiko Kaji, Hirokuni Tagaya, Masato Matsuura, Yoshitaka Kaneita, Takashi Ohida, Makoto Uchiyama",
"Sleep and Biological Rhythms",
4));
}
dgMain.ItemsSource = persons;
Here is how I counted it:
private void btnTest_Click(object sender, RoutedEventArgs e)
{
int k = 0;
var rows = GetDataGridRows(dgMain);
foreach (DataGridRow r in rows)
{
var rowHeight = r?.ActualHeight;
k++;
}
MessageBox.Show(k.ToString());
}
And here is the Article class:
public class Article
{
private string _title;
public string Title
{
get { return this._title; }
set { this._title = value; }
}
private string _authors;
public string Authors
{
get { return this._authors; }
set { this._authors = value; }
}
private string _journal;
public string Journal
{
get { return this._journal; }
set { this._journal = value; }
}
private int _year;
public int Year
{
get { return this._year; }
set { this._year = value; }
}
public Article(string Title, string Authors, string Journal, int Year)
{
this._title = Title;
this._authors = Authors;
this._journal = Journal;
this._year = Year;
}
}
You can do something like this
var rows = GetDataGridRows(datagrid);
foreach (DataGridRow r in rows)
{
var rowHeight = r?.ActualHeight;
}
public IEnumerable<DataGridRow> GetDataGridRows(System.Windows.Controls.DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row) yield return row;
}
}
Xaml
<StackPanel Orientation="Vertical" >
<Button Click="Button_Click" Height="39" Width="40"></Button>
<DataGrid x:Name="dgMain" AutoGenerateColumns="True" HorizontalAlignment="Left" Height="auto" VerticalAlignment="Top" Width="auto" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" >
</DataGrid>
</StackPanel>
// check box code
private void Checkbox_Checked(object sender, RoutedEventArgs e)
{
List<Service> selectedItems = new List<Service>();
CheckBox checkbox = (CheckBox)sender;
item = checkbox.DataContext.ToString();
string items = string.Join(",", item.ToArray());
you = new Service();
you.id = items;
}
// submit button
private void book_Click(object sender, RoutedEventArgs e)
{
string name = Name.Text;
string phone = Phone.Text;
string email = Email.Text;
string date = Date.Date.ToString();
string description = Description.Text;
Rootobjectsss objnewobject = new Rootobjectsss();
objnewobject.customerName = name;
objnewobject.email = email;
objnewobject.appointmentDate = date;
objnewobject.description = description;
objnewobject.service[0].id = you.id.ToString();
json = string.Empty;
json = Newtonsoft.Json.JsonConvert.SerializeObject(objnewobject, Newtonsoft.Json.Formatting.Indented);
Debug.WriteLine(json);
getData(json);
}
// Object class
public class Rootobjectsss
{
public string customerName { get; set; }
public string email { get; set; }
public string appointmentDate { get; set; }
public string description { get; set; }
public Medicalcenters medicalCenters { get; set; }
public Service[] service { get; set; }
}
public class Medicalcenters
{
public string id { get; set; }
public string email { get; set; }
public string address { get; set; }
public string centerName { get; set; }
}
public class Service
{
public string id { get; set; }
}
//XAML on listview and checkbox
<ListView x:Name="serviceListView"
IsItemClickEnabled="True"
ItemClick="serviceListView_ItemClick"
SelectionChanged="serviceListView_SelectionChanged"
HorizontalAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:Class3">
<Grid>
<StackPanel HorizontalAlignment="Stretch" Orientation="Horizontal">
<TextBlock FontSize="16" Text="{Binding sname}" TextWrapping="Wrap"/>
<CheckBox DataContext="{Binding id}" Name="myCheckBox" FontSize="10" Checked="Checkbox_Checked" Unchecked="myCheckBox_Checked" Margin="20,0,0,0">
</CheckBox>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
// expected result
{"customerName": customer_name,
"email": email,
"appointmentDate": appointment_date,
"description":description,
"medicalCenters":{"id": medical_center_id, "email": medical_center_email, "address": medical_center_address, "centerName": medical_center_name}
"service",[{"id": service_id}, {"id": service_id}]
}
I tested your code snippet on my side, and it will throw System.NullReferenceException exception at objnewobject.service[0].id = you.id.ToString(); code line. So it seems like you didn't have issues about convert the Rootobjectsss instance to json string, but have issues with how to convert the selected CheckBox records to the service array.
In that case, you can save the selected Service to a List<Service> collection then convert this collection to array by ToArray method.
Updated code as follows (Also added the unchecked code which you didn't upload):
Service you = new Service();
List<Service> selectedItems = new List<Service>();
private string json;
public MainPage()
{
this.InitializeComponent();
ObservableCollection<Class3> items = new ObservableCollection<Class3>()
{
new Class3()
{
id="1",
sname="name1"
},
new Class3()
{
id="2",
sname="name2"
},
new Class3()
{
id="3",
sname="name3"
}
};
serviceListView.ItemsSource = items;
}
// check box code
private void Checkbox_Checked(object sender, RoutedEventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
string item = checkbox.DataContext.ToString();
Service you = new Service();
you.id = item;
selectedItems.Add(you);
}
// submit button
private void book_Click(object sender, RoutedEventArgs e)
{
string name = "name1";
string email = "test#microsoft.com";
string date = System.DateTime.Now.ToString();
string description = "I'm the describtion";
Rootobjectsss objnewobject = new Rootobjectsss()
{
customerName = name,
email = email,
appointmentDate = date,
description = description,
service = selectedItems.ToArray()
};
json = string.Empty;
json = Newtonsoft.Json.JsonConvert.SerializeObject(objnewobject, Newtonsoft.Json.Formatting.Indented);
Debug.WriteLine(json);
//getData(json);
}
private void myCheckBox_Checked(object sender, RoutedEventArgs e)
{
CheckBox checkbox = (CheckBox)sender;
foreach (Service removeitem in selectedItems)
{
if (removeitem.id == checkbox.DataContext.ToString())
{
selectedItems.Remove(removeitem);
break;
}
}
}
And the result:
{
"customerName": "name1",
"email": "test#microsoft.com",
"appointmentDate": "5/4/2017 5:59:30 PM",
"description": "I'm the describtion",
"medicalCenters": null,
"service": [
{
"id": "1"
},
{
"id": "3"
}
]
}
I recommend you to add a IsChecked property for the Class3 entity, then you can get all the checked items directly, not by the checked and unchecked events.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
So, I'm at a lost, and hope for some guidance. I'm using MVVM pattern and EF.
My View contains a datagrid bound to a observable collection within the view model.
The UI has furthermore 3 comboboxes with possible data to minimize the data shown.
So I've been googling around and found nothing I could use (or might not have understood it correctly).
How do I search and select the items from a ObservableCollection, and update the datagrid accordingly?
public ObservableCollection<DimTargets> TargetParameters { get; set; }
private void SelectionChanged(object obj)
{
if (obj is FactTargets)
{
SelectedFactTarget = (FactTargets)obj;
}
else if (obj is DimLocation)
{
SelectedLocation = (DimLocation)obj;
ViewCollection.Select(x => x.Location == SelectedLocation.Location);
TargetParameters.Where(x => x.FactTargets == SelectedLocation.FactTargets);
}
else //DimBladeType
{
SelectedBladeType = (DimBladeType)obj;
int[] a = DimTargetsController.ReturnBladeType(SelectedBladeType);
foreach (int i in a)
{
TargetParameters.Single(k => k.ID == i);
}
var os = TargetParameters.Where(d => d.ID == );
TargetParameters = Convert<DimTargets>(os);
//TargetParameters.Where(ka => ka.ID == a);
//TargetParameters = new ObservableCollection<DimTargets>(TargetParameters.Where(t => t.FactTargets == SelectedBladeType.FactTargets));
//var obs = TargetParameters.Where(t => t.FactTargets == SelectedBladeType.FactTargets);
//TargetParameters = Convert<DimTargets>(obs);
//ViewCollection.Select(x => x.BladeType == SelectedBladeType.BladeType).ToList();
}
}
public ObservableCollection<T> Convert<T>(IEnumerable original)
{
return new ObservableCollection<T>(original.Cast<T>());
}
XAML:
ComboBox ItemsSource="{Binding FactTargetCollection, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedFactTarget}" DisplayMemberPath="FYQuater" Behaivor:SelectionChangedBehaviour.Command="{Binding SelectionChangedCommand}"/>
<ComboBox ItemsSource="{Binding LocationCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedLocation}" DisplayMemberPath="Location" Behaivor:SelectionChangedBehaviour.Command="{Binding SelectionChangedCommand}"/>
<ComboBox ItemsSource="{Binding BladeTypeCollection, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedBladeType}" DisplayMemberPath="BladeType" Behaivor:SelectionChangedBehaviour.Command="{Binding SelectionChangedCommand}"/>
<Button Content="Submit" Style="{StaticResource BaseButtonStyle}"></Button>
</StackPanel>
<StackPanel x:Name="WorkPanel" DockPanel.Dock="Right">
<DataGrid ItemsSource="{Binding TargetParameters}">
</DataGrid>
</StackPanel>`
Hope this gives a better idea of what i'm trying to do.
the c# code are filled with examples with what i've tried.
Cant see all of you objects but here is a quick n simple illustration...
public RelayCommand<int> FilterAgeCommand { get; set; }
public Base_ViewModel()
{
FilterAgeCommand = new RelayCommand<int>(OnFilterAgeCommand);
this.TestClassList = new ObservableCollection<TestClass>();
this.TestClassList.Add(new TestClass() { FName = "John", SName = "Doe", Age = 25 });
this.TestClassList.Add(new TestClass() { FName = "Jane", SName = "Doe", Age = 75 });
this.TestClassList.Add(new TestClass() { FName = "Mick", SName = "Doe", Age = 35 });
this.TestClassList.Add(new TestClass() { FName = "Harry", SName = "Doe", Age = 10 });
this.TestClassList.Add(new TestClass() { FName = "Linda", SName = "Doe", Age = 25 });
this.TestClassList.Add(new TestClass() { FName = "Fred", SName = "Doe", Age = 14 });
this.FilteredTestClassList = new ObservableCollection<TestClass>();
this.Age = new List<int>();
for(int i = 1; i <100; i++)
{
this.Age.Add(i);
}
}
private void OnFilterAgeCommand(int obj)
{
this.FilteredTestClassList = Convert<TestClass>((from tc in this.TestClassList where tc.Age < obj select tc).ToList());
}
public List<int> Age { get; set; }
public ObservableCollection<TestClass> TestClassList { get; set; }
private ObservableCollection<TestClass> _FilteredTestClassList;
public ObservableCollection<TestClass> FilteredTestClassList
{
get { return _FilteredTestClassList; }
set { _FilteredTestClassList = value; OnPropertyChanged("FilteredTestClassList"); }
}
public ObservableCollection<T> Convert<T>(IEnumerable original)
{
return new ObservableCollection<T>(original.Cast<T>());
}
A simple class for the demo...
public class TestClass : INotifyPropertyChanged
{
private string _FName;
public string FName
{
get { return _FName; }
set { _FName = value; NotifyPropertyChanged("FName"); }
}
private string _SName;
public string SName
{
get { return _SName; }
set { _SName = value; NotifyPropertyChanged("FName"); }
}
private int _Age;
public int Age
{
get { return _Age; }
set { _Age = value; }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
And some XAML...
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:_36550006.ViewModels"
xmlns:Views="clr-namespace:_36550006.Views"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
Title="Base_View" Height="300" Width="300">
<Window.DataContext>
<ViewModels:Base_ViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<DataGrid ItemsSource="{Binding FilteredTestClassList, NotifyOnSourceUpdated=True}"></DataGrid>
<ComboBox x:Name="cmb" ItemsSource="{Binding Age}" SelectedValuePath="{Binding Age}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding FilterAgeCommand}" CommandParameter="{Binding ElementName=cmb, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</StackPanel>
</Grid>
I essentially have two ObservableCollection, the first holds ALL of your items and the second is a filtered collection that you bind to....