I am trying to create an expandable listview in forms and I am receiving an error "The type or namespace name 'Items' could not be found (are you missing a using directive or an assembly reference?)" I was trying to have the buttons hide or show with a boolean value upon touch.
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ExpandableListViewTest
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ListViewType : ContentPage
{
public ObservableCollection<string> Items { get; set; }
public bool IsVisible { get; set; }
public ListViewType()
{
InitializeComponent();
IsVisible = false;
Items = new ObservableCollection<string>
{
new Items
{
Title = "Sad"
},
new Items
{
Title = "Angry"
},
new Items
{
Title = "Fearful"
}
};
}
public void HideOrShowItem(Items item)
{
item.IsVisible = true;
UpdateItems(item);
}
private void UpdateProducts(Items item)
{
var index = Items.IndexOf(item);
Items.Remove(item);
Items.Instert(index, item);
}
}
}
Your ObservableCollection Items has the type parameter string, but you are trying to create objects of type Items, which is not possible for two reasons
First of all (and this is what the compiler complains about) there is no type Items, hence you can't create instances of this type
Second, if the ObservableCollection has the type parameter string you can't add any items but strings.
You could either add strings to the collection
Items = new ObservableCollection<string>
{
"Sad",
"Angry",
"Fearful"
};
or you create the type Item (renamed it)
class Item
{
Title { get; set; }
}
and then create instances of that type:
Items = new ObservableCollection<Item>
{
new Item
{
Title = "Sad"
},
new Item
{
Title = "Angry"
},
new Item
{
Title = "Fearful"
}
};
Of course you have to change the type of Items to ObservableCollection<Item>, for the reason stated above (can't add objects of type Item to an ObservableCollection<string>).
Related
So I have this view and it's generated by CMS. The brains of the view are in another view rendered by RenderAction.
Up until now it has looked like this:
Main.cshtml
<div>CMS content</div>
#{
var myContent = new MainContentModel() {
SomethingUsedFurtherDown = "Easier for CMS people to edit"
}
Html.RenderAction("_Main", "Foo", new { arg1 = "this", arg2 = "that", content = myContent });
}
MainContentModel.cs
namespace MyApp.Services.ViewModels.Foo
{
public class MainContentModel
{
public string SomethingUsedFurtherDown { get; set; }
}
}
MainViewModel.cs
namespace MyApp.Services.ViewModels.Foo
{
public class MainViewModel
{
public string Arg1 { set; set; }
public string Arg2 { set; set; }
public string Name { get; set; }
public string Age { get; set; }
public string Address { get; set; }
public MainContentModel Content { get; set; }
}
}
_Main.cshtml
#model MyApp.Services.ViewModels.Foo.MainViewModel
#Html.EditorFor(m => m.Name)
#Html.EditorFor(m => m.Age)
#Html.EditorFor(m => m.Address)
<!-- whatever - doesn't matter -->
FooController.cs
namespace My.App.Controllers
{
using System;
using System.Web.Mvc;
public class FooController
{
public ActionResult Main(string arg1, string arg2, MainContentModel cm)
{
var vm = new MainViewModel() { Arg1 = arg1, Arg2 = arg2, Content = cm };
return this.View("_Main", vm);
}
}
}
All works fine. So why am I bothering you? Well, this isn't the real code, obviously. There are many more arguments to the controller method and it's all getting rather messy. So I figured I would pass in the view model from the outer view.
Main.cshtml
<div>CMS content</div>
#{
var myVM = new MainViewModel() {
Arg1 = "this"
, Arg2 = "that"
, Content = new MainContentModel() {
SomethingUsedFurtherDown = "Easier for CMS people to edit"
}
};
Html.RenderAction("_Main", "Foo", new { vm = myVM });
}
...and just have one argument to the controller method
FooController.cs
namespace My.App.Controllers
{
using System;
using System.Web.Mvc;
public class FooController
{
public ActionResult Main(MainViewModel vm)
{
return this.View("_Main", vm);
}
}
}
And that's where the trouble starts. I get this error:
The view '_Main' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Foo/_Main.aspx
~/Views/Foo/_Main.ascx
~/Views/Shared/_Main.aspx
~/Views/Shared/_Main.ascx
~/Views/Foo/_Main.cshtml
~/Views/Foo/_Main.vbhtml
~/Views/Shared/_Main.cshtml
~/Views/Shared/_Main.vbhtml
~/Views/CMS/_Main.cshtml
~/Views/CMS/Foo/_Main.cshtml
But if I remove the initialisation of the content model, it all works again. Well, okay, it doesn't work work. But the error goes away, leaving me to come up with the obvious solution of adding the content model to the argument list and assigning it to the view model in the controller method.
Main.cshtml
<div>CMS content</div>
#{
var myVM = new MainViewModel() {
Arg1 = "this"
, Arg2 = "that"
};
var myCm = new MainContentModel() {
SomethingUsedFurtherDown = "Easier for CMS people to edit"
};
Html.RenderAction("_Main", "Foo", new { vm = myVM, cm = myCm });
}
FooController.cs
namespace My.App.Controllers
{
using System;
using System.Web.Mvc;
public class FooController
{
public ActionResult Main(MainViewModel vm, MainContentModel cm)
{
vm.Content = cm;
return this.View("_Main", vm);
}
}
}
Which is fine except that there are quite a few child objects of the real view model and I don't want to separate those out into arguments - it defeats the purpose of what is supposed to be a tidying up exercise.
Question
Is MVC4 supposed to be binding the child objects seamlessly and this is a bug? Or does it just not work this way and my only choice is to separate them out into extra parameters as above?
Cheers,
.pd.
Just in case anybody else has fallen into this trap. The problem was not the model binding. MVC 4 binds nested objects just fine. I was missing the subtlety of the error. The standard here is to prefix the "real" view name with an underscore and it was this that was not being found. The failure was occurring here:
return this.View("_Main");
What I didn't include in my post (cuz if I'd remembered, that would've fixed it!) was the fact that in the real situation the RenderAction looks like this:
RenderAction("Main", "Foo", new { area = "SomeArea", ... });
And I had missed off the area in my refactoring. Pretty embarrassing but if it stops somebody else beating their head against the wall then the shame will have been worth it :-)
I am new to MVC 4, i want to create a drop downmenu for listing the gender.I tried a lot but nothing helped me, also i google it but invain.Please help me in it tha thow to create dropdown menu for gender please guide me.
<div class="editor-field">
#Html.DropDownList("Gender", new List<SelectListItem>{
new SelectListItem{ Text="Male", Value="Male"},
new SelectListItem{ Text="Female", Value="Female"}
}, "--- Select ---"
)
</div>
say we use an enum for the gender:
namespace DropdownExample.Models
{
public enum GenderType
{
Male=1,
Female=2
}
}
and we make a model like this:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace DropdownExample.Models
{
public class ActionModel
{
public ActionModel()
{
ActionsList = new List<SelectListItem>();
}
[Display(Name="Gender")]
public int ActionId { get; set; }
public IEnumerable<SelectListItem> ActionsList { get; set; }
}
}
make a controller like so:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using DropdownExample.Models;
namespace DropdownExample.Controllers
{
public class ActionController : Controller
{
public ActionResult Index()
{
ActionModel model = new ActionModel();
IEnumerable<GenderType> GenderType = Enum.GetValues(typeof(GenderType))
.Cast<GenderType>();
model.ActionsList = from action in actionTypes
select new SelectListItem
{
Text = action.ToString(),
Value = ((int)action).ToString()
};
return View(model);
}
}
}
then in your view, you use the DropDownListFor html helper you include the following:
#model DropdownExample.Models.ActionModel
#{
ViewBag.Title = "Index";
}
#Html.LabelFor(model=>model.ActionId)
#Html.DropDownListFor(model=>model.ActionId, Model.ActionsList)
the DropDownListFor html helper uses at leats these two parameters:
the name of the property that will hold the selected value
the List<SelectListItem>() that contains all the options in the dropdownlist.
Create a Class for Gender
public class Gender
{
public int ID { get; set;}
public string Name { get; set; }
}
Create a list for Gender anywhere in the Controller
List<Gender> genderList = new List<Gender> {
new Gender{ Name="Male", ID = 1},
new Gender{ Name="Female", ID = 2}
};
You will have to create a SelectList for genders in the Action that will be passed to the view.
ViewBag.Genders= new SelectList(genderList,"ID","Name");
Finally you'll add a DropDownList to the view
#Html.DropDownList("Genders", null, htmlAttributes: new { #id = "genders", #class = "form-control" })
#Html.ValidationMessageFor(model => model.Gender, "", new { #class = "text-danger" })
I have a ViewModel that i use in a grid.
Lets name it DivisionVm
public class DivisionVm {
public int DivisionId
public string Name
public DateTime StartDate { get; set; }
public string Condition
....
}
When I want to update the model I use a custom editor template.Because Condition takes some predefined string values I use a dropdownlist in the template.
#(Html.Kendo().DropDownListFor(model=>model.Condition)
.DataTextField("Text")
.DataValueField("Condition")
.Events(e => e.Change("change"))
.BindTo(new List<ConditionVm>() {
new ConditionVm() {
Text = "Red",
Condition = "Red"
},
new ConditionVm() {
Text = "Green",
Condition = "Green"
},
new ConditionVm() {
Text = "Green",
Condition = "Green"
}
})
)
ConditionVm is just a viewmodel that i use for binding
public class ConditionVm
{
public string Text { get; set; }
public string Condition { get; set; }
}
My problem is that when the pop up editor opens it shows the current condition value in the dropdownlist. But if i select another value from the list, kendo does not track the change.So if i press the update button viemodel does not update.If i change other fields (eg Name) the viemodel is updating but only for these fields.Condition remains the same even if i have selected another value from the dropdown list.
My controller update method is something like this
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult DivisionGridUpdate([DataSourceRequest] DataSourceRequest request, DivisionVm division)
{
if (division != null && ModelState.IsValid)
{
......
}
return Json(new[] { division }.ToDataSourceResult(request, ModelState));
}
Have you tried in the grid setting the column of the DDL like a foreing Key?
Like this:
columns.ForeignKey(p => p.yourproperty, (System.Collections.IEnumerable)ViewData["myList"], "Text", "Condition");
Controller (here you fill the list wich will be fill the Dropdownlist:
ViewData["myList"] = myList.Select(e => new
{
Text= e.Text,
Condition= e.Condition
});
And in the pop up editor you just simple:
#Html.EditorFor(model=>model.yourproperty)
I have a situation in a new WinRT app where I need to manage an ID property on a collection of objects. Essentially I'm holding the unique ID for each object which I need to increment for each new object added. This is because I'll be serializing to XML to save the data so need to manage this ID myself. If I was using SQL it would be an auto incrementing field.
The best way I could come up with was to set this using a method called from the constructor and then have a collection changed handler help me to update the value each time.
Here is the view model class:
using MM.Models;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
namespace MM.ViewModels
{
public class VehiclesViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public VehiclesViewModel()
{
Vehicles = new ObservableCollection<Vehicle>();
NewVehicle = new Vehicle();
NextVehicleID = CalculateHighestID(Vehicles.AsQueryable()) + 1;
Vehicles.CollectionChanged += new NotifyCollectionChangedEventHandler(VehicleCollectionChanged);
}
private ObservableCollection<Vehicle> _vehicles;
public ObservableCollection<Vehicle> Vehicles
{
get
{
return _vehicles;
}
set
{
if (_vehicles != value)
{
_vehicles = value;
PropertyChanged(this, new PropertyChangedEventArgs("Vehicles"));
}
}
}
void VehicleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
NextVehicleID += 1;
}
}
public Vehicle NewVehicle { get; set; }
private int _nextVehicleID;
public int NextVehicleID
{
get
{
return _nextVehicleID;
}
private set
{
_nextVehicleID = value;
PropertyChanged(this, new PropertyChangedEventArgs("NextVehicleID"));
}
}
private int CalculateHighestID(IQueryable<Vehicle> vehicles)
{
var query = vehicles.OrderByDescending(v => v.VehicleID).FirstOrDefault();
if (query != null)
{
return query.VehicleID;
}
else
{
return 1;
}
}
}
}
and here is a text button click method I added on the xaml page to add an item.
private void Button_Click_1(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
vm.Vehicles.Add(new Vehicle { VehicleID = vm.NextVehicleID });
}
However, the VehicleCollectionChanged is never called. As a test I used the same code to add a vehicle from the constructor method and that did work.
Can anyone explain why the method would not be called with adding a vehicle from the xaml button click?
Also, is there a better overall approach to keep track of an ID value for the next record?
Does your ID have to be an int (or incremental for that matter)? Could it be a GUID? At least then you could leave the creation up to the Vehicle class. As for why the event isn't being called, are you ever re-assigning the "Vehicles" property on your viewmodel? Is there a reason you have a public "set" for that property? You could potentially set a new ObservableCollection to "Vehicles" and not 1) unhook from the old event and 2) hook-up the CollectionChanged event to the new collection.
How about keeping a counter in your Vehicle class?
public class Vehicle
{
static int NextId = 1;
static object IdLock = new Object();
public int VehicleId { get; set; }
...
public Vehicle(int nextId = 0)
{
// can probably use interlocked increment instead
// of keeping a separate lock object
lock (IdLock)
{
if (nextId == 0)
{
VehicleId = NextId++;
}
else
{
NextId = nextId;
VehicleId = nextId;
}
}
}
...
}
Instead of setting NextId = 1, you may want to set it based on what is in your saved XML file. That way, it doesn't always start at 1.
I'm working in VB.NET
I have an ArrayList named Invoices populated with objects of the class Invoice.
I'd like to data bind this to a ListBox so that as the contents of the ArrayList are updated and changed the ListBox updates. I've implemented a .ToString function on the Invoice class, I just don't know how I'd go about binding the ArrayList to the ListBox.
Any suggestions?
I'm going to make the assumption that this is winforms.
If you want two-way data-binding, you need a few things:
to detect addition/removal etc, you need a data-source that implements IBindingList; for classes, BindingList<T> is the obvious choice (ArrayList simply won't do...)
to detect changes to properties of the objects, you need to implement INotifyPropertyChanged (normally you can use the "*Changed" pattern, but this isn't respected by BindingList<T>)
Fortunately, ListBox handles both of these. A full example follows; I've used C#, but the concepts are identical...
using System;
using System.ComponentModel;
using System.Windows.Forms;
class Data : INotifyPropertyChanged{
private string name;
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this,
new PropertyChangedEventArgs(propertyName));
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Button btn1, btn2;
BindingList<Data> list = new BindingList<Data> {
new Data { Name = "Fred"},
new Data { Name = "Barney"},
};
using (Form frm = new Form
{
Controls =
{
new ListBox { DataSource = list, DisplayMember = "Name",
Dock = DockStyle.Fill},
(btn1 = new Button { Text = "add", Dock = DockStyle.Bottom}),
(btn2 = new Button { Text = "edit", Dock = DockStyle.Bottom}),
}
})
{
btn1.Click += delegate { list.Add(new Data { Name = "Betty" }); };
btn2.Click += delegate { list[0].Name = "Wilma"; };
Application.Run(frm);
}
}
}