I'd like to bind my dropdown to a generic list.
It seems really simple but I keep getting the error DataBinding: 'InternalPurchasingForms.Types.Item' does not contain a property with the name 'itemID'.
Here's my code for the class:
namespace InternalPurchasingForms.Types
{
public class Item
{
public int itemID;
public String name;
//...
}
}
Here's my dropdown databinding code:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
List<Item> allItems = DataAccessLayer.getAllItems();
uxDropDownItemList.DataSource = allItems;
uxDropDownItemList.DataValueField = "itemID";
uxDropDownItemList.DataTextField = "name";
uxDropDownItemList.DataBind();
}
}
I want to tell the dropdown that the "value" for each line is Item.itemID and that the "text" is Item.Name, but ASP.NET's telling me that those fields don't exist inside Item. I'm able to access Item's fields just fine elsewhere.
How do I do this correctly?
Make sure you are using a getter and setter in your Item class for itemID and name.
I am setting properties in this way and its working fine while binding with dropdown.
private int _itemid= 0;
private string _name = "";
public string name
{
set { _name = value; }
get { return _name ; }
}
public int itemID
{
set { _itemid= value; }
get { return _itemid; }
}
Related
I tried setting the new feature in Xamarin Forms 3 which is ReturnType and I have set it to Next. My form has multiple fields and I want to make that the next Entry is focused when the Next button is pressed. However it just closes the keyboard. I did read the documents however I could not find the way to focus it to the next Entry. Can someone please guide?
Thanks in advance.
Those who want to know how I implemented it, it is as follows:
I created a behavior which will handle the OnAttachedTo and OnDetachingFrom so that I can handle the Completed event to move the focus. Now for that, I need a BindableProperty. I created the following code out of the logic:
public class NextEntryBehavior : Behavior<Entry>
{
public static readonly BindableProperty NextEntryProperty = BindableProperty.Create(nameof(NextEntry), typeof(Entry), typeof(Entry), defaultBindingMode: BindingMode.OneTime, defaultValue: null);
public Entry NextEntry
{
get => (Entry)GetValue(NextEntryProperty);
set => SetValue(NextEntryProperty, value);
}
protected override void OnAttachedTo(Entry bindable)
{
bindable.Completed += Bindable_Completed;
base.OnAttachedTo(bindable);
}
private void Bindable_Completed(object sender, EventArgs e)
{
if (NextEntry != null)
{
NextEntry.Focus();
}
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.Completed -= Bindable_Completed;
base.OnDetachingFrom(bindable);
}
}
As you can see, there is a NextEntry property, we use it via XAML to focus on the desired entry field once the user marks it as complete using the Next button.
XAML:
<Entry ReturnType="Next">
<Entry.Behaviors>
<behaviors:NextEntryBehavior NextEntry="{x:Reference LastName}" />
</Entry.Behaviors>
</Entry>
In the above behavior, the LastName reference I used is the control to which the focus should go when the user taps on Next.
This way, it worked as expected and is reusable across the project.
the property ReturnType for Entry will only set graphically the Return Key in Keyboard to the specified type - Next in your case.
In order to set Focus for another Entry in the view you need to call Focus() from within the targeted Entry in the code-behind.
For Example:
private void txtUsername_OnCompleted(object sender, EventArgs e)
{
txtPassword.Focus();
}
if you're applying MVVM pattern. You will need a property in the Entry to Bind on for ViewModel property. One way to achieve this is by extending Entry control to add a bindable property called "IsActive" and create a Trigger that listens for changes on this property and calls Focus(), like below:
public class ExtendedEntry : Entry
{
public static readonly BindableProperty IsActiveProperty = BindableProperty.Create(
nameof(IsActive),
typeof(bool),
typeof(ExtendedEntry),
defaultBindingMode: BindingMode.TwoWay,
defaultValue: false);
public bool IsActive
{
get => (bool)GetValue(IsActiveProperty);
set => SetValue(IsActiveProperty, value);
}
private Trigger _isActiveTriger;
private EntryIsActiveAction _activeAction;
public ExtendedEntry()
{
InitTriggers();
}
private void InitTriggers()
{
InitIsActiveTrigger();
}
private void InitIsActiveTrigger()
{
_activeAction = new EntryIsActiveAction();
_isActiveTriger = new Trigger(typeof(ExtendedEntry))
{
Value = false,
Property = IsActiveProperty,
EnterActions = { _activeAction },
ExitActions = { _activeAction }
};
Triggers.Add(_isActiveTriger);
}
}
public class EntryIsActiveAction : TriggerAction<ExtendedEntry>
{
protected override void Invoke(ExtendedEntry sender)
{
if (sender.IsActive)
{
sender.Focus();
return;
}
sender.Unfocus();
}
}
Example Usage:
Xaml page:
<Entry x:Name="txtPassword" IsActive="{Binding IsPasswordActive}" />
ViewModel:
private bool _isPasswordActive;
public bool IsPasswordActive
{
get => _isPasswordActive;
set
{
_isPasswordActive = value;
OnPropertyChanged();
}
}
I am getting data from a web service and I am loading it in Picker. Now I want to call a new web service to get some data related to selected item. But I am not getting that selected item.
I am using below class model to get data from web service and loading it in Picker.
public class ModelGetEmployeeList
{
public string ServiceStatus { get; set; }
public List<EmployeeList> EmpList { get; set; }
}
public class EmployeeList
{
public string uid { get; set; }
public string fname { get; set; }
public string lname { get; set; }
}
This is how I loaded data in Picker:
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync ();
var Items = JsonConvert.DeserializeObject <ModelGetEmployeeList> (content);
foreach(EmployeeList emp in Items.EmpList)
{
pickerEmployee.Items.Add(emp.uid.ToString()+"-"+emp.fname.ToString()+" "+emp.lname.ToString());
}
}
Now I am implementing SelectedIndexChanged event like this:
public void PickerEmployee_SelectedIndexChanged(object sender, SelectedItemChangedEventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var item = sender as EmployeeList;
var selectedItem = item.uid;
DisplayAlert (selectedItem.ToString (), "OK", "OK");
}
}
But its giving me an error that above method has wrong signature.
You can take sellected value with this:
string selectedEmployee = string.Empty;
selectedEmployee = pickerEmployee.Items[pickerEmployee.SelectedIndex];
According to the Xamarin.Forms Picker documentation SelectedIndexChanged event is expecting delegate which matches EventHandler delegate (EventHandler documentation)
So, you have to change signature of your method :
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
...
}
Your signature is wrong.
Also the following code is wrong:
var item = sender as EmployeeList;
var selectedItem = item.uid;
Please find the corrected version below :
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var selectedItem = PickerEmployee[SelectedIndex];
DisplayAlert (selectedItem, "OK", "OK");
}
}
The Xamarin Forms picker will get you only the string which was added to the list and not the object.
If you need the object either you can use the selectedIdex on your orginal lsit to get the object as :
var selectedEmp = Items.EmpList[SelectedIndex];
Or you can use a Bindable Picker.
public void PickerEmployee_SelectedIndexChanged(object sender, EventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var selectedItem = (EmployeeList)PickerEmployee.SelectedItem;
DisplayAlert (selectedItem.fname, "OK", "OK");
}
}
public void PickerEmployee_SelectedIndexChanged(object sender, SelectedItemChangedEventArgs e)
{
if (pickerEmployee.SelectedIndex == -1)
{
//Message
}
else
{
var item = sender as Picker;
var selectedItem = item.SelectedItem as EmployeeList;
var uid =selectedItem.uid;
DisplayAlert (uid .ToString (), "OK", "OK");
}
}
The Items collection is a list of strings so you can get the currently selected value using SelectedIndex
var selectedValue = picker.Items [picker.SelectedIndex];
If you are using binding then yes, the exposed property is the SelectedIndex.
For more info click here
//How to get value of picker in Xamarin forms
//We are getting Text and Value from API
//xaml page
<controls:BorderlessPicker
x:Name="Pickdoctype"
ItemDisplayBinding="{Binding text}"
SelectedIndexChanged="Pickdoctype_SelectedIndexChanged"
HorizontalOptions="FillAndExpand"
Title="Enter Document Type"
FontSize="20"
TextColor="Gray">
</controls:BorderlessPicker>
// xaml.cs page
private void Pickdoctype_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
DocumentTypeModel selectedItem = (DocumentTypeModel)Pickdoctype.SelectedItem;
updatePickerValue = selectedItem.value;
}
catch (Exception ex)
{
}
}
// class
public class DocumentTypeModel
{
public string text { get; set; }
public string value { get; set; }
}
I need advices! So I have a custom repeater where I write the footer in the Custom control here is the code :
[ParseChildren(true)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[DefaultProperty("Text")]
[ToolboxData("<{0}:CustomRepeater runat=server></{0}:CustomRepeater>")]
public class CustomRepeater : Repeater
{
[PersistenceMode(PersistenceMode.InnerDefaultProperty),
TemplateContainer(typeof(GuessFooterTemplate))]
private ITemplate FooterTemp {get; set;}
protected override void InitializeItem(RepeaterItem item)
{
base.InitializeItem(item);
FooterTemp = new GFooterTemplate();
this.FooterTemplate = FooterTemp;
}
//Here I try to hide the footer template
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public override ITemplate FooterTemplate
{
get
{
return base.FooterTemplate;
}
set
{
base.FooterTemplate = value;
}
}
}
internal class GFooterTemplate : ITemplate
{
PlaceHolder ph = new PlaceHolder();
public void InstantiateIn(Control Container)
{
ph.Controls.Add(new LiteralControl("Test for Footertemplate"));
Container.Controls.Add(ph);
}
}
So as the footer is writing programmatically, I would like to hide the FooterTemplate for somebody who use the custom repeater.. I was thinking [PersistenceMode(PersistenceMode.InnerDefaultProperty)] will do that but apparently not.. Have somebody an idea?
Thanks a lot
If I understand correctly, you don't want the users of your CustomRepeater to be able to modify the FooterTemplate...
I see 2 possible solutions:
Use the new modifier on your property to completely redefine it:
private new ITemplate FooterTemplate
{
get { return base.FooterTemplate; }
set { base.FooterTemplate = value; }
}
Or modify the setter to do nothing, thus preventing the modification:
public override ITemplate FooterTemplate
{
get
{
return base.FooterTemplate;
}
set
{
/* base.FooterTemplate = value; */
}
}
HTH
I am trying to store a generic list in a viewstate-backed property as follows:
[Serializable]
public class UploadedFile
{
public string FileName { get; set; }
public Guid FileGuid { get; set; }
}
public List<UploadedFile> UploadedFiles
{
get
{
return (List<UploadedFile>) (ViewState["UploadedFiles"] ?? new List<UploadedFile>());
}
set
{
ViewState["UploadedFiles"] = value;
}
}
When I try to add an item to the list, the UploadedFiles.Count remains zero:
var uploadedFile = new UploadedFile {FileName = args.FileName, FileGuid = args.FileGuid};
UploadedFiles.Add(uploadedFile); // UploadedFiles.Count == 0 here!
Anyone have an idea here?
When you create the initial list, you dont save it into viewstate, try this..
public List<UploadedFile> UploadedFiles
{
get
{
var list = (List<UploadedFile>) (ViewState["UploadedFiles"] ??
new List<UploadedFile>());
ViewState["UploadedFiles"] = list;
return list;
}
set
{
ViewState["UploadedFiles"] = value;
}
}
What you're actually doing here is getting the property (which will initially return a new List) and then adding something to that new list, I think this is actually what you want to do:
List<UploadedFile> list = UploadedFiles;
list.Add(uploadedFile);
UploadedFiles = list;
This will write back to the ViewState after modifying the list.
To make life easier, I usually just do something like this to track ViewState for objects. Then you don't need any special handling when you refer to it elsewhere in code.
// Lazy loading object
protected List<string> ItemList {
get {
if (_ItemList==null) {
_ItemList = new List<string>();
}
return(_ItemList);
}
}
protected list<string> _ItemList=null;
// Save & Load it to viewstate as needed
protected override object SaveViewState()
{
if (_ItemList != null)
{
ViewState["ItemList"] = ItemList;
}
return base.SaveViewState();
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
if (ViewState["ItemList"] != null)
{
_ItemList = (List<string>)ViewState["ItemList"];
}
}
private List Lista
set
{
ViewState.Add("Lista", value);
}
get
{
return ViewState["Lista"] != null ? (List<UploadedFile>)ViewState["Lista"] : null;
}
}
I am trying to get a sample to work using MVVM Light and the Messaging Class. In the sample, I have a test project created from the MVVM Template for Silveright 4. I have added a button on the main page. When the button is clicked, it updates a property on the ViewModel. When the property is updated, I want to show a messagebox with the new value.
The key line of code is:
Messenger.Default.Register(this, new Action(ShowMessage));
I can get this to work in WPF, but not silverlight. It should call ShowMessage with the string parameter when the property changes, but it does not. If I use:
Messenger.Default.Send("Hello MVVM");
This works and the string is sent as a message to ShowMessage.
However, the message does not get sent if the property changes, even though the property was created with the MVVMINPC snippet and has the following line:
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
This should have the same effect as Messager.Default.Send but it seems to be ignored. ThePropertyChangedEvent is indeed raised, but the messanger part seems to be disconnected.
Am I doing something wrong? Here is the full MainViewModel:
public class MainViewModel : ViewModelBase
{
public RelayCommand MyRelayCommand { get; set; }
public const string MyPropertyPropertyName = "MyProperty";
private string _myProperty = "test";
public string MyProperty
{
get
{
return _myProperty;
}
set
{
if (_myProperty == value)
{
return;
}
var oldValue = _myProperty;
_myProperty = value;
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
}
}
public void DoSomething()
{
//Messenger.Default.Send("Hello MVVM"); //Works
this.MyProperty = "Hello World"; //Doesn't work.
}
public void ShowMessage(string message)
{
MessageBox.Show(message);
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
Messenger.Default.Register(this, new Action<string>(ShowMessage));
MyRelayCommand = new RelayCommand(new Action(DoSomething));
this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MainViewModel_PropertyChanged);
}
void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
MessageBox.Show(e.PropertyName);
}
}public class MainViewModel : ViewModelBase
{
public RelayCommand MyRelayCommand { get; set; }
public const string MyPropertyPropertyName = "MyProperty";
private string _myProperty = "test";
public string MyProperty
{
get
{
return _myProperty;
}
set
{
if (_myProperty == value)
{
return;
}
var oldValue = _myProperty;
_myProperty = value;
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
}
}
public void DoSomething()
{
//Messenger.Default.Send("Hello MVVM"); //Works
this.MyProperty = "Hello World"; //Doesn't work.
}
public void ShowMessage(string message)
{
MessageBox.Show(message);
}
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
Messenger.Default.Register(this, new Action<string>(ShowMessage));
MyRelayCommand = new RelayCommand(new Action(DoSomething));
this.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MainViewModel_PropertyChanged);
}
void MainViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
MessageBox.Show(e.PropertyName);
}
}v
OK, I found that the Register line should look like this:
Messenger.Default.Register(this, new Action<PropertyChangedMessage<string>>(ShowMessage));
The point being there are different types of messages, and you have to register the PropertyChangedMessage type to recieve property changed messages.
Then also, the Action that recieves the message needs to take the correct parameter, like this:
public void ShowMessage(PropertyChangedMessage<string> e)
{
MessageBox.Show(e.NewValue.ToString());
}