I want to display all the images in my image's folder.
This is my code :
<%
string dir = Server.MapPath("Content/slideshow/images");
string[] files;
int numFiles;
files = System.IO.Directory.GetFiles(dir);
numFiles = files.Length;
for (int i = 1; i < numFiles; i++)
{
%>
<i><a href="#">
<img src="/Content/slideshow/images/image<%= i %>.jpg" alt="" height="239px" width="930px" />
</a></i>
<% }%>
When I code like this, it display only the images that have the name "image"+blah blah blah . But I want to render all images in different name in a folder.
Can anyone solve this?
I would suggest you using view models to achieve this. So let's start by defining such:
public class ImageViewModel
{
public string Url { get; set; }
}
then we could have a controller action which will populate this view model (or precisely a collection of it):
public class ImagesController: Controller
{
[ChildActionOnly]
public ActionResult Images()
{
var appData = Server.MapPath("~/Content/slideshow/images");
var images = Directory.GetFiles(appData).Select(x => new ImageViewModel
{
Url = Url.Content("~/Content/slideshow/images/" + Path.GetFileName(x))
});
return PartialView(images);
}
}
then we could define a corresponding partial view (~/Views/Shared/Images.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<ImageViewModel>>"
%>
<%= Html.DisplayForModel() %>
next a corresponding display template which will be rendered for each image (~/Views/Shared/DisplayTemplates/ImageViewModel.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<ImageViewModel>"
%>
<img src="<%= Model.Url %>" alt="" height="239px" width="930px" />
and the final part that's left is to include this child action somewhere in a view or a master page:
<%= Html.Action("Images", "Images") %>
public DisplayImages()
{
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(Location);
foreach (System.IO.FileInfo f in dir.GetFiles("*.*"))
{
//Do Something
}
}
Related
I'm experiencing current error in my view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ProjectenII.Models.Domain.StudentModel>"%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
IndexStudents
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>IndexStudents</h2>
<%using (Html.BeginForm()) { %>
<%=Html.ListBoxFor(model => model.NormalSelected, new MultiSelectList(Model.NormalStudentsList, "StudentNummer", "Naam", Model.NormalSelected), new { size = "6" }); %>
<input type="submit" name="add"
id="add" value=">>" /><br />
<input type="submit" name="remove"
id="remove" value="<<" />
<%=Html.ListBoxFor(model => model.NoClassSelected, new MultiSelectList(Model.StudentsNoClassList, "StudentNummer", "Naam", Model.NoClassSelected)); %>
<% } %>
<%=Html.HiddenFor(model => model.Save) %>
<input type="submit" name="apply" id="apply" value="Save!" />
</asp:Content>
It gives me an error at the listboxfor() method... saying ") expected".
But I close all the opening tags... very strange though!
What I want to use it for: I want to move items from one listbox to the other and then update the database. So I'd like to do it using formCollection, unless there is another way?
Students have a field named "classID", when I update the database, that value needs to change from the current value to "0". I think the best way is using formCollections? Isn't it?
This is my StudentModel
public class StudentModel
{
public IEnumerable<Student> NormalStudentsList { get; set; }
public IEnumerable<Student> StudentsNoClassList { get; set; }
public string[] NormalSelected { get; set; }
public string[] NoClassSelected { get; set; }
public string Save { get; set; }
}
Controller:
public ActionResult IndexStudents(Docent docent, int id, int klasgroepid)
{
var studentModel = new StudentModel
{
NormalStudentsList = docent.GeefStudenten(id, klasgroepid),
StudentsNoClassList = docent.GeefStudenten(id, klasgroepid)
};
return View(studentModel);
}
I have two questions: how can I fix the error? AND how can I update the database?
I suggest using "UpdateModel()" ... ?
Thanks in advance!!
Not sure what your second question is because you didn't include the code you're using to persist your model to the database.
The ")" expected error is because you have a semicolon at the end of your ListBoxFor method call.
It should look like this:
<%=Html.ListBoxFor(model => model.NormalSelected, new MultiSelectList(Model.NormalStudentsList, "StudentNummer", "Naam", Model.NormalSelected), new { size = "6" }) %>
When you use <%= you don't need the semicolon.
I have a timesheet application that has a View where the user can select customers and tasks and add them to a dynamic table. This table is filled with the tasks and input fields for filling in hours worked.
For adding the new tasks in the dynamic table I use jQuery, so the savenewtask button is not a submit button. Instead I have a proper submit button for saving the hours when filled in.
The View is strongly typed to a model called TimesheetViewModel (see below). The controller passes the model to the View, and then the input fields are bound to properties in the model.
However, when I submit with the submit button and try to update the model in the Controller it doesn't update. It seemed from the Nerddinner tutorial (which I am using to learn MVC) that the model should automatically be updated using the values from the forms fields it had been bound to when you use UpdateModel(). But it doesn't. What am I doing wrong?
Here is all the relevant code:
View:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script src="../../Scripts/jquery-1.4.1.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
//Hook onto the MakeID list's onchange event
$("#CustomerId").change(function () {
//build the request url
var url = "Timesheet/CustomerTasks";
//fire off the request, passing it the id which is the MakeID's selected item value
$.getJSON(url, { id: $("#CustomerId").val() }, function (data) {
//Clear the Model list
$("#TaskId").empty();
//Foreach Model in the list, add a model option from the data returned
$.each(data, function (index, optionData) {
$("#TaskId").append("<option value='" + optionData.Id + "'>" + optionData.Name + "</option>");
});
});
}).change();
});
</script>
<h2>Index</h2>
<% using (Html.BeginForm())
{%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div>
<label for="Customers">
Kund:</label>
<%:Html.DropDownListFor(m => m.Customers, new SelectList(Model.Customers, "Id", "Name"), "Välj kund...", new { #id = "CustomerId" })%>
<label for="Tasks">
Aktiviteter:</label>
<select id="TaskId">
</select>
</div>
<p>
<input type="button" value="Save new task" id="savenewtask" />
</p>
<table width="100%">
<%--<% foreach (var task in Model.Tasks)--%>
<% foreach (var task in Model.WeekTasks)
{ %>
<tr>
<td>
<%: task.Customer.Name %>
</td>
<td>
<%: task.Name %>
</td>
<td>
<% foreach (var ts in task.TimeSegments)
{ %>
<input class="hourInput" type="text" size="2" id="<%: ts.Task.CustomerId + '_' + ts.TaskId + '_' + ts.Date %>"
value="<%: ts.Hours %>" />
<% } %>
</td>
</tr>
<% } %>
</table>
<input type="submit" value="Save hours" id="savehours" />
</fieldset>
<% } %>
</asp:Content>
From the Controller:
private TimesheetViewModel _model;
public TimesheetController()
{
_model = new TimesheetViewModel();
}
public ActionResult Index()
{
return View(_model);
}
[HttpPost]
public ActionResult Index(FormCollection collection)
{
try
{
UpdateModel(_model);
_model.Save();
return View(_model);
//return RedirectToAction("Index");
}
catch
{
return View();
}
}
The ViewModel:
public class TimesheetViewModel
{
private TimesheetContainer _model; //TimesheeContainer is an Entity Framework model
public TimesheetViewModel()
{
_model = new TimesheetContainer();
}
public IList<Customer> Customers
{ get { return _model.Customers.ToList(); } }
public IList<Task> Tasks
{ get { return _model.Tasks.ToList(); } }
public IList<Task> WeekTasks
{
get
{
//Get the time segments for the current week
DateTime firstDayOfWeek = DateTime.Parse("2010-12-05");
DateTime lastDayOfWeek = DateTime.Parse("2010-12-13");
List<TimeSegment> timeSegments = new List<TimeSegment>();
foreach (var timeSegment in _model.TimeSegments)
{
if(timeSegment.DateTimeDate > firstDayOfWeek && timeSegment.DateTimeDate < lastDayOfWeek)
timeSegments.Add(timeSegment);
}
//Group into tasks
var tasks = from timeSegment in timeSegments
group timeSegment by timeSegment.Task
into t
select new { Task = t.Key };
return tasks.Select(t => t.Task).ToList();
}
}
public IList<TimeSegment> TimeSegments
{ get { return _model.TimeSegments.ToList(); } }
public void Save()
{
_model.SaveChanges();
}
public void AddTimeSegments(Task task)
{
_model.AddToTasks(task);
_model.SaveChanges();
}
}
Partial class to get tasks for a specific week (only dummy week at this time for testing):
public partial class TimeSegment
{
public DateTime DateTimeDate
{ get { return DateTime.Parse(Date); } }
}
Why is the model not updating, and what can I change to make it work?
Put a breakpoint on your first ActionResult Index(), is that getting called when you do the submit? you may need [HttpGet] on it, otherwise I think it gets both.
I'm quite new to both ASP.Net and MVC.
I got the following code in my master page:
<div id="main-menu" class="menu">
<%
var items = (IList<CompanyName.Framework.Web.MenuItem>)ViewData["MainMenu"];
if (items.Count > 0)
{
%><ul><%
foreach (var item in items)
{
if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole))
continue;
%><li><%= item.Title %></li><%
}
%></ul><%
}
%>
</div>
Can I move the code to another file or refactor the code in any way?
edit:
My ApplicationController that all controllers derive:
public class ApplicationController : Controller
{
List<MenuItem> _mainMenu = new List<MenuItem>();
List<MenuItem> _contextMenu = new List<MenuItem>();
protected IList<MenuItem> MainMenu
{
get { return _mainMenu; }
}
protected IList<MenuItem> ContextMenu
{
get { return _contextMenu; }
}
protected string PageTitle { get; set; }
protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
ViewData["PageTitle"] = PageTitle;
ViewData["MainMenu"] = MainMenu;
ViewData["ContextMenu"] = ContextMenu;
base.OnResultExecuting(filterContext);
}
}
Here are a couple of suggestions:
Improvement number 1: use view models and strongly typed views instead of ViewData
public ActionResult Index()
{
// TODO: Fetch this data from a repository
var menus = new[] {
new MenuItem(), new MenuItem()
}.ToList();
return View(menus);
}
and then in your view:
<div id="main-menu" class="menu">
<%
if (Model.Count > 0)
{
%><ul><%
foreach (var item in Model)
{
if (!string.IsNullOrEmpty(item.RequiredRole) && !System.Threading.Thread.CurrentPrincipal.IsInRole(item.RequiredRole))
continue;
%><li><%= item.Title %></li><%
}
%></ul><%
}
%>
</div>
Still horrible and completely unreadable tag soup.
Improvement number 2: use editor/display templates:
In ~/Views/Home/DisplayTemplates/MenuItem.ascx:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<% if (!string.IsNullOrEmpty(Model.RequiredRole) &&
System.Threading.Thread.CurrentPrincipal.IsInRole(Model.RequiredRole)) { %>
<li>
<%= Model.Title %>
</li>
<% } %>
And then in your main view:
<div id="main-menu" class="menu">
<ul>
<%= Html.DisplayForModel() %>
</ul>
</div>
Improvement number 3: Avoid coding business rules in a view. So in your view model add a property:
public bool IsLinkVisible
{
get
{
return !string.IsNullOrEmpty(RequiredRole) &&
Thread.CurrentPrincipal.IsInRole(RequiredRole);
}
}
so that your display template now looks like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<% if (Model.IsLinkVisible) { %>
<li>
<%= Model.Title %>
</li>
<% } %>
Improvement number 4: Write a custom HTML helper to render this anchor because writing C# in a view is still ugly and untestable:
public static class HtmlExtensions
{
public static MvcHtmlString MenuItem(this HtmlHelper<MenuItem> htmlHelper)
{
var menuItem = htmlHelper.ViewData.Model;
if (!menuItem.IsLinkVisible)
{
return MvcHtmlString.Empty;
}
var li = new TagBuilder("li");
var a = new TagBuilder("a");
a.MergeAttribute("href", menuItem.Uri);
a.SetInnerText(menuItem.Title);
li.InnerHtml = a.ToString();
return MvcHtmlString.Create(li.ToString());
}
}
and finally your display template:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<CompanyName.Framework.Web.MenuItem>" %>
<%= Html.MenuItem() %>
Yes, you can just put that block into an .ascx file and use:
<% html.RenderPartial("myPartialFile.asx"); %>
The above assumes that myPartialFile.ascx is located in the same folder as your master page, usually, the Views/Shared folder.
Ok, I've been going at this for several hours and I simply cannot find the solution.
I want to get some data from my user. So first, I use a controller to create a view which receives a Model:
public ViewResult CreateArticle()
{
Article newArticle = new Article();
ImagesUploadModel dataFromUser = new ImagesUploadModel(newArticle);
return View(dataFromUser);
}
Then, I have the view:
<asp:Content ID="Content1" ContentPlaceHolderID="MainContentPlaceHolder" runat="server">
<h2>AddArticle</h2>
<% using (Html.BeginForm("CreateArticle", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" })){ %>
<%= Html.LabelFor(model => model.newArticle.Title)%>
<%= Html.TextBoxFor(model => model.newArticle.Title)%>
<%= Html.LabelFor(model => model.newArticle.ContentText)%>
<%= Html.TextBoxFor(model => model.newArticle.ContentText)%>
<%= Html.LabelFor(model => model.newArticle.CategoryID)%>
<%= Html.TextBoxFor(model => model.newArticle.CategoryID)%>
<p>
Image1: <input type="file" name="file1" id="file1" />
</p>
<p>
Image2: <input type="file" name="file2" id="file2" />
</p>
<div>
<button type="submit" />Create
</div>
<%} %>
</asp:Content>
and finally - the original controller, but this time configured to accept the data:
[HttpPost]
public ActionResult CreateArticle(ImagesUploadModel dataFromUser)
{
if (ModelState.IsValid)
{
HttpPostedFileBase[] imagesArr;
imagesArr = new HttpPostedFileBase[2];
int i = 0;
foreach (string f in Request.Files)
{
HttpPostedFileBase file = Request.Files[f];
if (file.ContentLength > 0)
imagesArr[i] = file;
}
The rest of this controller does not matter since no matter what I do, the count attribute of Request.Files (or Request.Files.Keys) remains 0. I simply can't find a way to pass the files from the form (the Model passes just fine).
You might want to consider not posting the files with the rest of the form- there are good reasons and other ways you can achieve what you want.
Also, check out this question and this advice regarding file uploads in MVC.
You could add the files to your view model:
public class ImagesUploadModel
{
...
public HttpPostedFileBase File1 { get; set; }
public HttpPostedFileBase File2 { get; set; }
}
And then:
[HttpPost]
public ActionResult CreateArticle(ImagesUploadModel dataFromUser)
{
if (ModelState.IsValid)
{
// Use dataFromUser.File1 and dataFromUser.File2 directly here
}
return RedirectToAction("index");
}
Im at a loss for words, as I must be missing something. Just finished ASP.NET MVC 1.0 (WROX) and Im trying to implement a view that performs a simple search then renders the results in a table. I would then like to be able to page thru the results.
So I have a search action from ListingsController, takes some values from FormCollection and filters the results accordingly:
//
//POST: /Listings/Search
// /Listings/Page/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Search(FormCollection collection,int? page)
{
var listings = listingRepository.GetListings();
//filter
if (collection["TypeOfHouse"] != null)
{
string[] typeList = collection["TypeOfHouse"].Split(',');
foreach (string type in typeList)
{
listings = from l in listings
where l.TypeOfHouse == type
select l;
}
}
//display the first page of results
int pageSize = 25;
var paginatedListings = new PriviledgeV1.Helpers.PaginatedList<Listing>(listings, 0, pageSize);
return View("Results", paginatedListings);
}
Initially the Results view will be rendered with the first 25 records for page 1. Then I have a Results action that handles the "pagination":
public ActionResult Results(int? page)
{
int pageSize = 25;
var listings = listingRepository.GetListings();
var paginatedListings = new PriviledgeV1.Helpers.PaginatedList<Listing>(listings, page ?? 0, pageSize);
return View(listings);
}
Trouble is because I no longer have the FormCollection, I cannot properly filter results. So if I tried to move from say page 1 to page 2 using /Listings/Results?page=2, the results action would fire and it would return ALL results instead of the filtered result set from the Search action.
I'm really confused as to what to do here, and as to why there are no blogs/tutorials explaining this, which normally flags me that I am missing something.
Thanks!
I suppose there are a few ways to try and accomplish this.
Pass the search parameters via query string instead of post. Understandably, this could be complicated and messy for advanced search parameters
Store the results of the POST to hidden elements. Have your paging control POST to the same action each time, instead of the separate Results action.
Store the query parameters in an object that is persisted in your session.
I'm sure we could get more creative from there, but that should give you a start. It seems like you only care about one field from the search form, TypeOfListing. You should be able to persist that via query string pretty easily, so that'd be method #1 above.
Update
Here's something simple I put together to maintain your search at the client. The technique involves three parts:
Maintain the form between page requests.
Manage the page state with a hidden element in the form.
Have JavaScript intercept your Paging links, update the page number hidden element, and resubmit the form.
Here's the code for all the various pieces. Note that I use jQuery, in case you prefer something else. I fudged the data source, just sub in real data. Also, I included PagedList and PaginationHelper. Substitute with your own if you wish.
\Controllers\HomeController.cs (Search is the relevant part):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication2.Controllers
{
[HandleError]
public class HomeController : Controller
{
List<String> _data;
public HomeController()
{
_data = new List<String>();
_data.Add("Merry");
_data.Add("Metal");
_data.Add("Median");
_data.Add("Medium");
_data.Add("Malfunction");
_data.Add("Mean");
_data.Add("Measure");
_data.Add("Melt");
_data.Add("Merit");
_data.Add("Metaphysical");
_data.Add("Mental");
_data.Add("Menial");
_data.Add("Mend");
_data.Add("Find");
}
public ActionResult Search()
{
Int32 pageNumber, pageSize = 5, total, first;
String typeOfListing;
PagedList<String> results;
if (Request.HttpMethod == "GET")
{
return View();
}
if (!Int32.TryParse(Request.Form["PageNumber"], out pageNumber)) pageNumber = 1;
typeOfListing = Request.Form["TypeOfListing"];
first = (pageNumber - 1) * pageSize;
total = (from s in _data
where s.Contains(typeOfListing)
select s).Count();
results = new PagedList<String>(
(from s in _data
where s.Contains(typeOfListing)
select s)
.Skip(first)
.Take(pageSize),
total, pageNumber, pageSize);
return View(results);
}
}
}
\Helpers\PaginationHelper.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Web.Routing;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace MvcApplication2.Helpers
{
public static class PaginationHelper
{
public static String Pager(this HtmlHelper helper, Int32 pageSize, Int32 pageNumber, Int32 total, String actionName, RouteValueDictionary values)
{
StringBuilder output = new StringBuilder();
Int32 totalPages = (Int32)Math.Ceiling((Double)total / pageSize);
if (values == null)
values = helper.ViewContext.RouteData.Values;
if (pageNumber > 1)
output.Append(CreatePageLink(helper, values, "< Previous ", pageNumber - 1, pageSize));
for (Int32 i = 1; i <= totalPages; i++)
{
if (i == pageNumber)
output.Append(i);
else
output.AppendFormat(CreatePageLink(helper, values, i.ToString(), i, pageSize));
if (i < totalPages)
output.Append(" | ");
}
if (pageNumber < totalPages)
output.Append(CreatePageLink(helper, values, " Next >", pageNumber + 1, pageSize));
return output.ToString();
}
private static String CreatePageLink(HtmlHelper helper, RouteValueDictionary values, String text, Int32 pageNumber, Int32 pageSize)
{
RouteValueDictionary routeDictionary = new RouteValueDictionary(values);
routeDictionary.Add("page", pageNumber);
routeDictionary.Add("pageSize", pageSize);
return helper.ActionLink(text, null, routeDictionary);
}
}
}
\PagedList.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplication2
{
public class PagedList<T> : List<T>
{
public Int32 TotalCount { get; protected set; }
public Int32 PageNumber { get; protected set; }
public Int32 PageSize { get; protected set; }
public PagedList(IEnumerable<T> items, Int32 total, Int32 pageNumber, Int32 pageSize)
: base(items)
{
TotalCount = total;
PageNumber = pageNumber;
PageSize = pageSize;
}
}
}
\Views\Home\Search.aspx:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<PagedList<String>>" %>
<%# Import Namespace="MvcApplication2" %>
<%# Import Namespace="MvcApplication2.Helpers" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Search
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript">
$(function() {
var results = $("#searchResults");
if (results && results.children().length > 2) {
$("#searchForm").hide();
$("#searchResults .pager>a").click(submitForm);
}
});
function submitForm() {
var m = this.href.match(/page=(\d+)/i);
if (m) {
$("#PageNumber").attr("value", m[1]);
$("#searchForm").submit();
}
return false;
}
</script>
<form id="searchForm" action="<%= Url.Action("Search") %>" method="post">
<input type="hidden" value="1" id="PageNumber" name="PageNumber" />
<fieldset>
<legend>Search</legend>
<label for="TypeOfListing">Type of Listing</label>
<%= Html.TextBox("TypeOfListing", Request.Form["TypeOfListing"]) %>
<input type="submit" id="btnSubmit" name="btnSubmit" value="Search" />
</fieldset>
</form>
<% if (Model != null)
{
%>
<div id="searchResults">
<div class="results-count">Displaying <%=this.Model.Count %> of <%=this.Model.TotalCount %> results. <%=Html.ActionLink("Start a new search", "Search") %>.</div>
<%
foreach (String result in Model)
{
%>
<div class="result"><%=result %></div>
<% }
%>
<div class="pager"><%= Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalCount, null, null) %></div>
</div>
<%
}
%>
</asp:Content>
Basically change your form to do an HTTP GET as suggested by others, then download PagedList with Nuget, and use Model Binding in your action method to the submit button and page number coming from the PagedList's HTML helper function (and set the route values using a RouteValuesDictionary). This way everything gets persisted in the querystring, which is what you want with a search page anyway most likely. MVC will do the coersion to and from your ViewModel class. I prefer to use a ViewModel class instead of a bunch of arguments because I think it is cleaner that way, but just my $.02.
I have an example that I blogged about here.
Also, I went ahead and posted the code on a different thread