Listview Item not showing after clicking on list item - xamarin

I have created a list in Xamarin and when we select item without scrolling list then everything is fine and when we select item after scrolling list then after clicking list item
lost. Actually list item is exist but not showing and error comes after clicking on list item is :
V/AutofillManager(10440): requestHideFillUi(null): anchor = null
Here is the code:
private ObservableCollection<BlackListNewModel> _DeviceList = new ObservableCollection<BlackListNewModel>();
public ObservableCollection<BlackListNewModel> DeviceList
{
get { return _DeviceList; }
set { SetProperty(ref _DeviceList, value); }
}
DeviceList.Add(new BlackListNewModel
{
DeviceImage = "android",
Name = item.hostname ?? "Android",
Address = item.mac_address,
Id = item.id,
DeviceType = DeviceType.Android,
IsChecked = false,
IsNotChecked = true
});

Related

Using Messaging center xamarin forms PCL to set current objects value

I have a scenario where i create Entry Controls programmatically.
foreach (var control in FormInfo.FormElementsInfo)
{
case "textbox":
//Some code
break;
case "dropdown":
Entry objDropdown = new Entry();
objDropdown.HeightRequest = 40;
objDropdown.StyleId = Convert.ToString(control.ElementId);
objDropdown.SetBinding(Entry.TextProperty, "ElementValue",BindingMode.TwoWay);
objDropdown.BindingContext = control;
layout.Children.Add(objDropdown);
MessagingCenter.Subscribe<Picklists, string>(objDropdown, "PicklistSelected", (sender, arg) =>
{
objDropdown.Text = arg;
// I tried this too as this is two way binding. It didn't show the value.
//control.ElementValue = arg;
} );
break;
}
If i click on any entry it will open me a list view. Once i select the option in the list view it will populate that data in the Entry.
But this should show the selected value only in the current entry but it is changing the value in all the entry's.
How to avoid this situation. I want the selected value to be populated only in the current entry.
Any suggestion would be appreciated. Thank you.
=== More clear question=====
If we create n number of Entry controls programmatically with 2 way binding . Is it possible to change the single entry value on selecting something in other page? If yes how to achieve this?
FormInfo
public class FormInfo
{
public List<FormsElementInfo> FormElementsInfo { get; set; }
}
FormsElementInfo
public class FormsElementInfo : INotifyPropertyChanged
{
private string _elementValue;
public string ElementValue {
get => _elementValue;
set {
if(_elementValue != value)
{
_elementValue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ElementValue"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Content Page
public class ListStackOverflow : ContentPage
{
private FormInfo _info = new FormInfo
{
FormElementsInfo = new List<FormsElementInfo>()
{
new FormsElementInfo { ElementValue = "test 1"},
new FormsElementInfo { ElementValue = "test 2"},
new FormsElementInfo { ElementValue = "test 3"},
new FormsElementInfo { ElementValue = "test 4"},
}
};
private StackLayout _stack = new StackLayout();
private List<string> _source = new List<string>
{
"output 1","output 2","output 3","output 4",
};
public ListStackOverflow()
{
//BindingContext = _info;
foreach(var c in _info.FormElementsInfo)
{
Entry tempEntry = new Entry
{
HeightRequest = 40,
Placeholder = c.ElementValue,
BindingContext = c
};
tempEntry.SetBinding(Entry.TextProperty, "ElementValue");
_stack.Children.Add(tempEntry);
}
ListView _lv = new ListView { ItemsSource = _source };
_lv.ItemSelected += Lv_ItemSelected;
_stack.Children.Add(_lv);
Content = _stack;
}
private void Lv_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var selectedElement = e.SelectedItem.ToString();
var index = _source.IndexOf(selectedElement);
var entry = _info.FormElementsInfo[index];
entry.ElementValue = selectedElement;
}
}
Output
Selecting the corresponding index in the listview will update "ElementValue" for the same index.
First of all Thank you #Joshua Poling for taking time to help me.
I think MessagingCenter is not suitable for this approach.
I am assigning a unique styleId to each element that i create.That basically stores the position in the stack layout.
I have written a delegate which returns the selected value and also the position of the element. As the element is always an Entry that fires this event. I used the below code to achieve this.
Entry myentry = (Xamarin.Forms.Entry)layout.Children[src.ElementId];

Refreshing ListView in Xamarin.Forms for UWP

Details of my System is
Operating System : Windows 10 Pro N
Visual Studio Enterprise 2015
Xamarin.Forms 2.3.1..114
I have created a Tabbed view in which I am navigating to new page using Navigation.PushModalAsync method. In the view, I have a listview with custom Data Template. The Data Template is of ViewCell which contains two Images and one label.
What I am trying to do is when ever a cell is selected, I am showing the Image for checked row and when other row is selected then hiding the other row images and showing the currently selected image.
When first time view loads, I am setting the first row as selected and everything working good, but when I am selecting any other row then ListView is not refreshing. The Image IsVisible property is set correctly but it is not reflecting on the List.
See below code for reference
Code for the ListView
var listView = new ListView();
listView.ItemsSource = StaticData.ListData;
listView.ItemTemplate = new DataTemplate(typeof(CustomDataCell));
listView.VerticalOptions = LayoutOptions.FillAndExpand;
listView.BackgroundColor = Color.White;
listView.SeparatorVisibility = SeparatorVisibility.Default;
listView.RowHeight = 30;
listView.SeparatorColor = Color.White;
listView.ItemTapped += (sender, e) =>
{
if (e == null) return;
selectedValue = (e.Item as ValiditySchema).Value;
SelectValidityItem(listView,selectedValue); // In this method I am setting the IsSelected property to true and other rows IsSelected property to false.
};
Code for CustomDataCell
public class CustomDataCell : ViewCell
{
public Label CellText { get; set; }
public BoxView ImageDetail { get; set; }
public Image CheckedImage { get; set; }
public CustomDataCell()
{
CellText = new Label();
CellText.FontAttributes = FontAttributes.Bold;
CellText.SetBinding(Label.TextProperty, "Text");
CellText.VerticalOptions = LayoutOptions.Center;
CellText.HorizontalOptions = LayoutOptions.Start;
CellText.TextColor = Color.Black;
ImageDetail = new BoxView();
ImageDetail.WidthRequest = 20;
ImageDetail.HeightRequest = 10;
ImageDetail.SetBinding(BoxView.BackgroundColorProperty, "ColorName");
//declaring image to show the row is selected
CheckedImage = new Image();
CheckedImage.Source = "Images/checked.png";
CheckedImage.HorizontalOptions = LayoutOptions.CenterAndExpand;
CheckedImage.VerticalOptions = LayoutOptions.Center;
CheckedImage.SetBinding(Image.IsVisibleProperty, "IsSelected");
var ContentCell = new StackLayout();
ContentCell.Children.Add(ImageDetail);
ContentCell.Children.Add(CellText);
ContentCell.Children.Add(CheckedImage);
ContentCell.Spacing = 5;
ContentCell.Orientation = StackOrientation.Horizontal;
var maiCell = new StackLayout();
maiCell.Orientation = StackOrientation.Vertical;
maiCell.Children.Add(ContentCell);
View = maiCell;
}
}
In order for the ListView to know that items in your ItemsSource have changed you need to raise a INotifyPropertyChanged event on that specific item.
Usually instead of binding the data directly to the ListView, you would rather have a ViewModel representation for each item, following the MVVM pattern:
View <-> ViewModel <-> Model
So what you need to do is to create a ViewModel for your items in StaticData.ListData:
public class ListItemViewModel : INotifyPropertyChanged
{
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set {
_isSelected = value;
OnPropertyChanged();
}
}
// more properties here...
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then you can bind the IsSelected property to your image's Visibility property.
This way when you change IsSelected in your ViewModel, the correct event gets fired and the ListView now knows that something changed and that it needs to refresh the view.

How to load detailpage once in Xamarin Forms MasterDetailPage project

I noticed detailpage is loaded from scratch everytime masterpage menu item is selected (so its constructor is called everytime).
Is there a way to implement a detailpage which is loaded once, so everytime menu item is selected detailpage is simply showed/not showed?
Thanks,
Lewix
I solved implementing a dictionary page cache in MasterDetailPage:
// in constructor
MasterPageMenuCache = new Dictionary<Type, Page>();
// in OnItemSelected
if (MasterPageMenuCache.Count == 0)
MasterPageMenuCache.Add(typeof(FirstDefaultDetailPage), Detail);
var item = e.SelectedItem as MasterPageItem;
if (item != null)
{
if (MasterPageMenuCache.ContainsKey(item.TargetType))
{
Detail = MasterPageMenuCache[item.TargetType];
}
else
{
Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
MasterPageMenuCache.Add(item.TargetType, Detail);
}
masterPage.ListView.SelectedItem = null;
IsPresented = false;
}
Yes you can cache the Pages.
Here is an example with a dictionary which stores the pages.
public partial class MyMasterDetailPage : MasterDetailPage
{
public MyMasterDetailPage()
{
Pages = new Dictionary<MenuType, Page>();
}
public enum MenuType
{
Home,
Settings,
Map
}
private Dictionary<MenuType, Page> Pages { get; set; }
public async Task NavigateAsync(MenuType id)
{
Page newPage;
if (!Pages.ContainsKey(id)) // check the page is already in the dictionary
{
Page page;
switch (id)
{
case MenuType.Home:
page = new ContentPage()
{
Title = "Home",
};
Pages.Add(id, page);
break;
case MenuType.Map:
page = new ContentPage()
{
Title = "Map",
};
Pages.Add(id, page);
break;
case MenuType.Settings:
page = new ContentPage()
{
Title = "Settings",
};
Pages.Add(id, page);
break;
}
}
newPage = Pages[id];
if (newPage == null)
return;
Detail = newPage; // assign the page
}
}

List Picker Selection Change

I have 2 list pickers which showing item name and batch number. Batch number depends on Item Name. So when selecting Item Name I want to bind Batch numbers to the second list picker.My code like this. I'm writen code for Item list picker 'SelectionChanged' event. This is not working.
private void lstItem_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lstItem.SelectedIndex != 0)
{
int itemId = invoice.listItems[lstItem.SelectedIndex].ItemMasterID;
getBatches = invoice.bindBatchesForItem(itemId);
lstBatch.ItemsSource = getBatches;
}
}
bindBatchesForItem will return the list of batch numbers for selected item.This method returning the batch properly. But 'lstItem_SelectionChanged' event calling twise automatically. First time executing properly and when second time executing attached error comming.
public ObservableCollection<BatchNumbers> bindBatchesForItem(int selectedItem)
{
listBatches.Clear();
var batchList = from DailyItemStock DI in APPCommon.SFADB
where Convert.ToDateTime(DI.StockDate).Date == Convert.ToDateTime(APPCommon.TransactionDate).Date && DI.ItemMasterID == selectedItem
select new
{
DI.BatchNo
};
listBatches.Add(new BatchNumbers() { BatchNo = "0" });
foreach (var lists in batchList)
{
listBatches.Add(new BatchNumbers()
{
BatchNo = lists.BatchNo.ToString()
});
}
batchList = null;
return listBatches;
}

values for DropDownList items

I have follwoing code
#Html.DropDownList("optionsforuser", new SelectList(new[] { "Option1", "Option2", "Option3" }), "Select")
Is there anyway to initialize a value of 100 for Option1, 200 for Option2, 250 for Option3 etc within SelectList?
Try using this Extension:
#Html.DropDownList("optionsforuser",
new SelectList(new Dictionary<string, int>
{
{"Option1", 100},
{"Option2", 200},
{"Option3", 250}
},
"Value", "Key")
)
and pass it a Dictionary<string, int> with the dataValueField and dataTextField populated with your values and text
SelectExtensions.DropDownList Method (HtmlHelper, String, IEnumerable(Of SelectListItem))
public static MvcHtmlString DropDownList(
this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> selectList
)
SelectList Constructor (IEnumerable, String, String)
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField
)
For situations where I just want to hard-code select list items (i.e. not get them from some pre-defined collection), I use this handy little class:
public class BetterSelectList : List<SelectListItem>
{
public void Add(string text, object value, bool selected = false) {
this.Add(new SelectListItem {
Text = text,
Value = value.ToString(),
Selected = selected
});
}
}
Why is it "better"? It implements IEnumerable and has a multi-parameter Add method, which is all you need for the C# compiler to allow you to use dictionary-style initializers, resulting in about the most noise-free initialization possible:
var optionsForUser = new BetterSelectList {
{ "Option1", 100, true },
{ "Option2", 200 },
{ "Option3", 250 }
};
Yes you set text and value
var selections = new List<SelectListItem>();
selections.Add(new SelectListItem() { Text = "Option1", Value = "100" });
selections.Add(new SelectListItem() { Text = "Option2", Value ="200" });
Here is an MSDN article on select lists: select list
You can do it in your view like that as the others have posted, but can't you do it in the controller instead?
For example, In your view model:
public class ViewModel()
{
public List<SelectListItem> OptionsForUser{ get; set; }
}
In your controller:
var optionsForUser = new List<SelectListItem>();
optionsForUser.Add(new SelectListItem { Text = "Option1", Value = "100"});
optionsForUser.Add(new SelectListItem { Text = "Option2", Value = "200"});
optionsForUser.Add(new SelectListItem { Text = "Option3", Value = "250"});
var viewmodel = new ViewModel();
viewmodel.OptionsForUser = optionsForUser;
return view(viewmodel);
then in your view:
#Html.DropDownList("optionsforuser", Model.OptionsForUser);
Those other solutions will work too, I just think its not very "clean" to initialise your dropdown list in your view like that. But its probably a matter of taste

Resources