I have an empty stackpanel on View and I need to add textboxes on ViewModel. Same time I need to set binding to Text property for this textboxes.
VIEW :
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=myBtCollection}"></ItemsControl>
</StackPanel>
VIEWMODEL :
public decimal textExample { get; set; }
public decimal textExample2 { get; set; }
public decimal textExample3 { get; set; }
public ObservableCollection<TextBox> myTxCollection { get; set; }
public ExampleViewModel()
{
myTxCollection = new ObservableCollection<TextBox>();
TextBox txt1 = new TextBox { Text = textExample.ToString() };
TextBox txt2 = new TextBox { Text = textExample2.ToString() };
TextBox txt3 = new TextBox { Text = textExample3.ToString() };
myTxCollection.Add(txt1);
myTxCollection.Add(txt2);
myTxCollection.Add(txt3);
}
public void ExampleCommand()
{
textExample = 123;
textExample2 = 456;
textExample3 = 789;
}
By this codes, I can create the textboxes. But some methods(ExampleCommands) in ViewModel, I change the values textExample properties.
Summary code run first time; textboxes created successfully and text values are 0. And then I trigged the ExampleCommand, properties are changed but View didnt show this changes. Textboxes are showing still 0. How must be set the binding for this?
Thanks
Related
I am trying to figure out how this DropDownListFor works but with no success.
My controller creates a list of SelectListItems where I put all the groups found in the database:
viewModel.Groups = LoadGroups(viewModel.User.AssociatedGroups);
this it the method:
private IList<SelectListItem> LoadGroups(List<String> associatedGroups)
{
var groups = _SecurityService
.LoadGroups()
.Select(e => new SelectListItem
{
Selected = associatedGroups.Contains<System.String>(e.Id.ToString()),
Value = e.Id.ToString(),
Text = e.Name
}).ToList();
return (groups);
}
As you can see I set the Selected element if there are associated groups in the list.
I put this list in a field (Groups) of my custom viewmodel:
public class UsersViewModel
{
public UsersViewModel()
{
this.Groups = new List<SelectListItem>();
}
public Models.User User { get; set; }
public IList<SelectListItem> Groups { get; set; }
}
and send UsersViewModel to the view. I use this code to build a dropdown with multi-selection:
<%=Html.DropDownListFor(m => m.User.AssociatedGroups, (List<System.Web.Mvc.SelectListItem>)Model.Groups, new { #class = "dropDownGroups", multiple = "multiple" })%>
AssociatedGroups is a field the class Users (which is a member of my viewmodel):
public List<String> AssociatedGroups { get; set; }
There's nothing peculiar here.
If I use this code I can I can't see the elements of the dropdown selected (and they have the attribute set, I've double checked), but I can bind the selections with AssociatedGroups when I post the form.
If I change AssociatedGroups (field of the User class) with a string:
public String AssociatedGroups { get; set; }
I have the opposite behaviour:
I can see the elements of the dropdown checked but when I post the form there's no binding, or better, only one element is bound.
I've spend most of my day trying to figure out what the problem and I've tried different combinations but none of them seem to work.
Is there anyone who can try to help me?
Thanks.
You need two properties on your view model: one that will contain the selected group ids and one that will contain the list:
public class UsersViewModel
{
public IEnumerable<SelectListItem> Groups { get; set; }
public IEnumerable<string> SelectedGroupIds { get; set; }
}
and then you would use the ListBoxFor helper to allow for multiple choices:
<%= Html.ListBoxFor(
m => m.SelectedGroupIds,
new SelectList(Model.Groups, "Value", "Text"),
new { #class = "dropDownGroups" }
) %>
Now assuming the following view model is passed to the view:
public ActionResult Index()
{
var model = new UsersViewModel
{
// TODO: Use a repository to fetch those values
// and map them to the view model
Groups = new[]
{
new SelectListItem { Value = "1", Text = "group 1" },
new SelectListItem { Value = "2", Text = "group 2" },
new SelectListItem { Value = "3", Text = "group 3" },
},
// We want to preselect the last two groups in the listbox
SelectedGroupIds = new[] { "2", "3" }
};
return View(model);
}
[HttpPost]
public ActionResult Index(IEnumerable<string> selectedGroupIds)
{
// Here we will get the list of selected ids
// when the form containing the listbox is
// submitted
...
}
Then on the view the last two elements will be automatically preselected.
I am having a problem with a selectlistitem, the values of which are being retrieved from a database.
It is displaying the list of items in the view, but it is not passing through (POSTing) the selected value into the model.
So when the user submits, or the page reloads due to validation, the select value (PositionApplied) is empty.
Can anyone give me some pointers as to where I am going wrong?
In my controller:
[HttpGet]
public ActionResult Index()
{
PopulateJobsDropdown();
return View();
}
private void PopulateJobsDropdown()
{
IEnumerable<SelectListItem> items = _service.GetJobs()
.Select(c => new SelectListItem
{
Value = c.JobID.ToString(),
Text = c.JobTitle
});
ViewData["PositionApplied"] = items;
}
In my ViewModel
public IEnumerable<SelectListItem> PositionApplied { get; set; }
In my View
<%=Html.DropDownList("PositionApplied")%>
Thanks in advance for any pointers!
So, where is the code line that get's the
ViewData["PositionApplied"] = items;
into
public IEnumerable<SelectListItem> PositionApplied { get; set; }
something like:
this.PositionApplied = ViewData["PositionApplied"] as IEnumerable<SelectListItem>;
and you can simple use in your View:
<%
IEnumerable<SelectListItem> PositionApplied =
ViewData["PositionApplied"] as IEnumerable<SelectListItem>;
%>
...
<%= Html.DropDownList("myDropDOwnId", PositionApplied) %>
or is there some of automagical happening under MVC2 that I'm not aware about? As I use the example I give you, all the time.
Added
in order to avoid Linq to Entities error (if you are using it) change your method to
private void PopulateJobsDropdown()
{
IQueryble<Your_Table> jobs = _service.GetJobs();
List<SelectListItem> items = new List<SelectListItem>();
foreach(var job in jobs)
items.add(new SelectListItem
{
Value = c.JobID.ToString(),
Text = c.JobTitle
});
ViewData["PositionApplied"] = items;
}
and all will work fine.
Conclusion in Images, can be found in the bottom
I'm having some trouble to get how Forms work in MVC (as I'm a WebForms Developer and really wanna start using MVC in one big project)
I took the MVC2 Web Project and add a simple ViewModel to it
namespace TestForms.Models
{
public class myFormViewModel
{
public myFormViewModel() { this.Options = new List<myList>(); }
public string Name { get; set; }
public string Email { get; set; }
public List<myList> Options { get; set; }
}
public class myList
{
public myList() { this.Value = this.Name = ""; this.Required = false; }
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
public bool Required { get; set; }
}
}
Created a Strongly Typed View, passed a new object to the view and run it.
When I press submit, it does not return what's in the Options part... how can I bind that as well?
my view
alt text http://www.balexandre.com/temp/2010-10-11_1357.png
filling up the generated form
alt text http://www.balexandre.com/temp/2010-10-11_1353.png
when I press Submit the Options part is not passed to the Model! What am I forgetting?
alt text http://www.balexandre.com/temp/2010-10-11_1352.png
Conclusion
Changing the View loop to allocate the sequential number, we now have
<%= Html.TextBox("model.Options[" + i + "].Value", option.Value)%>
model is the name of our Model variable that we pass to the View
Options is the property name that is of type List
and then we use the property name
Looking at your UI it seems that you did not put the data from the Options member on it.
<% foreach (myList obj in Model.Options) { %>
// Add the object to your UI. they will be serialized when the form is submitted
<% } %>
Also check that you enclose the data in a form element
EDIT:
Sorry! I did'nt realized that you was filling the object inside the controller. Can you please show the code you have in the view?
I have two questions regarding communication between ViewModels.
I am developing a customer management program. I'm using Laurent Bugnion's MVVM Light framework.
In the main page, there's a list of customers. when each customer is clicked, a child windows shows up with information about that customer. the user should be able to open up multiple child windows at the same time and compare information between customers. how do you pass customer object from the main page's ViewModel to the child window's ViewModel in an MVVM-friendly fashion?
In the child window that shows customer information, there are a number of tabs, each showing different areas of information. I've created separate ViewModels for each of the tabs. how can you share the current customer information between each tab's viewmodels?
Thanks a lot!
In my project I'm passing ViewModels to child windows too. I create a dependency property for the ViewModel in my child window's code behind and in the setter of this property I pass the ViewModel along to my child window's ViewModel. This means you're creating a separate ViewModel class just for your child window.
To answer your second question, you could have your child window's ViewModel contain properties that each tab cares about, but have their data context still be the same as the child window's data context so they have access to shared properties. This is actually very easy since they automatically get the child window's data context.
Here's an example illustrating the two concepts above.
The child window view DetailsWindow.xaml (note that I've gotten in the habit of naming my child window views *Window.xaml instead of *View.xaml)
<controls:ChildWindow x:Class="DetailsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
xmlns:Views="clr-namespace:Views"
Title="Details"
DataContext="{Binding DetailsWindowViewModel, Source={StaticResource Locator}}"
>
<Grid>
<sdk:TabControl>
<sdk:TabItem Header="First Tab" Content="{Binding FirstTabContent}" />
<sdk:TabItem Header="Second Tab" Content="{Binding SecondTabContent}" />
</sdk:TabControl>
</Grid>
</controls:ChildWindow>
The child window view's code behind DetailsWindow.xaml.cs and its interface IDetailsWindow.cs
public partial class DetailsWindow : ChildWindow, IDetailsWindow
{
private IDetailsWindowViewModel ViewModel
{
get { return this.DataContext as IDetailsWindowViewModel; }
}
public DetailsWindow()
{
InitializeComponent();
}
#region Customer dependency property
public const string CustomerViewModelPropertyName = "Customer";
public ICustomerViewModel Customer
{
get
{
return (ICustomerViewModel)GetValue(CustomerViewModelProperty);
}
set
{
SetValue(CustomerViewModelProperty, value);
if (ViewModel != null)
{
ViewModel.Customer = value;
}
}
}
public static readonly DependencyProperty CustomerViewModelProperty = DependencyProperty.Register(
CustomerViewModelPropertyName,
typeof(ICustomerViewModel),
typeof(CustomerDetailsWindow),
null);
#endregion
}
public interface IDetailsWindow
{
ICustomerViewModel Customer { get; set; }
void Show();
}
The child window view model DetailsWindowViewModel.cs and its interface IDetailsWindowViewModel
public class DetailsWindowViewModel : ViewModelBase, IDetailsWindowViewModel
{
public DetailsWindowViewModel(IMessenger messenger)
: base(messenger)
{
}
#region Properties
#region Customer Property
public const string CustomerPropertyName = "Customer";
private ICustomerViewModel _customer;
public ICustomerViewModel Customer
{
get { return _customer; }
set
{
if (_customer == value)
return;
var oldValue = _customer;
_customer = value;
RaisePropertyChanged(CustomerPropertyName, oldValue, value, true);
}
}
#endregion
#region FirstTabContent Property
public const string FirstTabContentPropertyName = "FirstTabContent";
private FrameworkElement _firstTabContent;
public FrameworkElement FirstTabContent
{
get { return _firstTabContent; }
set
{
if (_firstTabContent == value)
return;
_firstTabContent = value;
RaisePropertyChanged(FirstTabContentPropertyName);
}
}
#endregion
#region SecondTabContent Property
public const string SecondTabContentPropertyName = "SecondTabContent";
private FrameworkElement _secondTabContent;
public FrameworkElement SecondTabContent
{
get { return _secondTabContent; }
set
{
if (_secondTabContent == value)
return;
_secondTabContent = value;
RaisePropertyChanged(SecondTabContentPropertyName);
}
}
#endregion
#endregion
}
public interface IDetailsWindowViewModel
{
ICustomerViewModel Customer { get; set; }
FrameworkElement FirstTabContent { get; set; }
FrameworkElement SecondTabContent { get; set; }
void Cleanup();
}
And you can show the child window from your MainPageViewModel.cs like this.
public class MainViewModel : ViewModelBase, IMainViewModel
{
private readonly IDetailsWindow _detailsWindow;
public MainViewModel(IMessenger messenger, IDetailsWindow DetailsWindow)
: base(messenger)
{
_detailsWindow = DetailsWindow;
}
private void DisplayCustomerDetails(ICustomerViewModel customerToDisplay)
{
_detailsWindow.Customer = customerToDisplay;
_detailsWindow.Show();
}
}
Note that I create interfaces for all of my view models and child windows and I use an DI/IoC container in my ViewModelLocator so that all of my ViewModels' dependencies are injected for me. You don't have to do this, but I like how it works.
I have the following database schema:
Here's how I populate a DropDownList in my AreaController.cs:
public ActionResult Edit(int id)
{
Area area = areaRepository.GetArea(id);
JefeRepository jefe = new JefeRepository();
ViewData["Jefes"] = new SelectList(jefe.FindAllJefes().ToList(), "ID", "Nombre", area.Jefe.Nombre);
return View(area);
}
Then in my View I display it like so:
<%: Html.DropDownList("IDJefe", (SelectList)ViewData["Jefes"]) %>
The DropDownList loads correctly but only shows the Name of the Jefe. I want to display both name and last name. How can I achieve this?
I've tried doing something like this but it only display the first name.
ViewData["Jefes"] = new SelectList(jefe.FindAllJefes().ToList(), "ID", "Nombre", area.Jefe.Nombre + area.Jefe.Apellido);
This is how it shows:
In your class you can make an property which will combine it for you and also can be bind to your list, f.e. if I have Person class:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
}
Then you can easily bind it like:
ViewData["Persons"] = new SelectList(persons, "Id", "FullName ", ...);
As far as it have just the getter it will not involved into your business logic processes - it will only helps ;)
PS. Sorry for another example, but I really do not understand spanish ;)