I have the following in my project (MVC3) N2CMS 2.2.1 (from nuget). I am able to edit the main page using the "manage parts" functionality and drag an image part onto the page and set it's content. However, when it renders the page it renders my Image.cshtml file inside of the _layout.cshtml (like it would for a page, not a part)... this is causing the site to have multiple head/footer etc tags and breaking the layout. How can i get the DroppableZones to render the partials properly (without having to set Layout = "" in every partial view manually). If you would like to test this yourself, you can check out the code from https://github.com/robbihun/N2CMSBaseStarterSite run it, go through the N2CMS setup with the sqlite db and use the manage parts feature (http://screencast.com/t/w9q5a49Ei8) to drag an image part onto the home page.
_layout.cshtml
<body>
#{ Html.ControlPanel().Render(); }
#RenderBody()
<footer>© #DateTime.Now.Year</footer>
#RenderSection("scripts", false)
</body>
StartHome.cshtml
<div>
#{ Html.DroppableZone(Zones.ImageSlider).Render(); }
</div>
Image.cshtml
#model ImagePart
<div class="image">
<img src="#Model.Image" alt="#Model.Title" />
<span class="title">#Model.Title</span>
<span class="description">#Model.ShortDescription</span>
</div>
StartHomePage.cs
[PageDefinition("Start Page", Description = "The start or home page of the website.", SortOrder = 1, InstallerVisibility = InstallerHint.PreferredRootPage | InstallerHint.PreferredStartPage)]
[WithEditableTitle("Title", 1, Focus = true, ContainerName = Tabs.Content)]
[RestrictParents(typeof(IRootPage))]
public class StartHomePage : PageBase
{
[EditableFreeTextArea("Main Content", 2, ContainerName = Tabs.Content)]
public virtual string MainContent { get; set; }
}
ImagePart.cs
[PartDefinition("Image Part", Description = "Image with title and description.")]
[WithEditableTitle("Title", 10)]
public class ImagePart : PartBase
{
[FileAttachment, EditableImageUpload("Image", 5)]
public virtual string Image { get; set; }
[EditableTextBox("Short Description", 15, TextMode = TextBoxMode.MultiLine, Rows = 5, Columns = 15)]
public virtual string ShortDescription { get; set; }
}
Add a _ViewStart.cshtml in the Views/Shared/Parts folder, and it'll override the Layout setting in that folder. In the new _ViewStart, set Layout = null; and don't set the Layout in your partial views.
Here's a pull request for you: https://github.com/robbihun/N2CMSBaseStarterSite/pull/1
Related
with MVC 4 I was able to put a view's editor templates into the view's folder: AwesomeApp/Views/UserMgmt/EditorTemplates/UserSettings.cshtml.
Now I am using ASP.NET Core MVC 6 and it does not find the editor template. I have to put them into AwesomeApp/Views/Shared/EditorTemplates/UserSettings.cshtml. What needs to be configured so I do not have to put all of my editor templates in this one folder?
I am using the latest version of Telerik's Kendo UI for ASP.NET MVC. But I guess it's something in the application itself.
Best regards,
Carsten
This works out of the box in (at least) core 2.2. In one of the demos they have put the EditorTemplates folder underneath a views folder, not the shared folder.
I tested this myself using the following code...
public class TestEditorForModel
{
[Display(Name = "Testing a string property")]
public string StringProp { get; set; }
[Display(Name = "Testing an integer property")]
[Range(100, 1000)]
public int IntProp { get; set; }
[Display(Name = "Testing a decimal property")]
public decimal DecProp { get; set; }
}
HomeController.cs
public IActionResult Index()
{
return View(new TestEditorForModel
{
StringProp = "testing editorfor",
IntProp = 123,
DecProp = 123.456m
});
}
Home/EditorTemplates/TestEditorForModel.cshtml
#model TestEditorForModel
<div>
<label asp-for="StringProp"></label>
<input asp-for="StringProp" placeholder="Testing" />
</div>
<div>
<label asp-for="IntProp"></label>
<input asp-for="IntProp" placeholder="123" />
</div>
<div>
<label asp-for="DecProp"></label>
<input asp-for="DecProp" placeholder="100.00" />
</div>
Home/Index.cshtml
#model TestEditorForModel
#Html.EditorFor(m => m)
Output
I am trying to get image files from the database and bind it to a KendoUI ListView. The problem is that it is not showing images at all.
This is what I have done:
View
<script type="text/x-kendo-tmpl" id="template">
<div class="product">
<img src="#Url.Content("#:PhotoID# + #:MIMEType#")" />
</div>
</script>
<div id="imageListView2" class="demo-section">
#(Html.Kendo().ListView<WorcesterMarble.ViewModels.PhotosViewModel>()
.Name("listView")
.TagName("div")
.ClientTemplateId("template")
.DataSource(dataSource =>
{
dataSource.Read(read => read.Action("GetImages", "StockReceiptsGrid").Data("passStockIDToListView"));
dataSource.PageSize(1);
})
.Pageable()
.Selectable(selectable => selectable.Mode(ListViewSelectionMode.Multiple))
//.Events(events => events.Change("onChange").DataBound("onDataBound"))
)
</div>
Controller
public JsonResult GetImages([DataSourceRequest] DataSourceRequest request, int stockReceiptID)
{
var photos = _stockPhotosRepository.GetStocReceiptkPhotos(stockReceiptID).ToList();
var photosList = new List<PhotosViewModel>();
//var photosList = new List<FileContentResult>();
if (photos.Count != 0)
{
foreach (var stockPhoto in photos)
{
var photoVm = new PhotosViewModel();
photoVm.PhotoID = stockPhoto.PhotoID;
photoVm.Image = stockPhoto.ImageData;
photoVm.MIMEType = stockPhoto.MIMEType;
// FileContentResult file = File(stockPhoto.ImageData, stockPhoto.MIMEType);
photosList.Add(photoVm);
}
return Json(photosList.ToList(), JsonRequestBehavior.AllowGet);
}
else
{
return null;
//FilePathResult file = this.File("/Content/Images/80.jpeg", "image/jpeg");
//return file;
}
return null;
}
Photo View Model:
public class PhotosViewModel
{
public int PhotoID { get; set; }
public byte[] Image { get; set; }
public string MIMEType { get; set; }
public int StockReceiptID { get; set; }
}
I am not sure if the problem is caused by the image url setting in the template. as you see it is not actually a url because the image is not saved anywhere except from the database. this is a screenshot of how the listview looks like; simply blank even though there must 15 images displayed!
Please let me know any clues or solutions to this problem.
I know this is a bit older, but what you need to do is change the line return Json(photosList.ToList(), JsonRequestBehavior.AllowGet); to the following:
return Json(photosList.ToDataSourceResult(request),
JsonRequestBehavior.AllowGet);
If the method ToDataSourceResult is not recognized, you have to add
using Kendo.Mvc.Extensions;
on top of your document.
It looks like you're missing a return in your controller (just before the end of your if)
return Json(photosList.ToList(), JsonRequestBehavior.AllowGet);
EDIT
Also, I noticed this:
<img src="#Url.Content("#:PhotoID# + #:MIMEType#")" />
Shouldn't that be:
<img src="#Url.Content("#:ImageData#")" />
or something similar?
It might be to late to answer, but your issue is that the json data being sent back to your view is to large so your images are not showing, rather save your images to a file and then render your images via a URL.
Well, this newbie is doing something wrong when displaying images uploaded to the server:
model:
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
}
controller (upload - called by the [HttpPost] public ActionResult Create):
public void Upload(Person person)
{
var image = WebImage.GetImageFromRequest();
var filename = Path.GetFileName(image.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/Uploads/Fotos"), filename);
image.Save(path);
person.ImageUrl = Url.Content(Path.Combine("~/App_Data/Uploads/Fotos", filename));
}
create view:
...
#using (Html.BeginForm("Create", "Person", FormMethod.Post, new { #encType = "multipart/form-data" }))
{
...
#FileUpload.GetHtml(initialNumberOfFiles: 1, allowMoreFilesToBeAdded: false, includeFormTag: false, uploadText: "image")
...
<div>
<input type="submit" value="Create" /> |
#Html.ActionLink("Back", "Index")
</div>
}
So far, so good, the image is uploaded to the folder and the url is saved
Now, I want to see it in the Detail View
detail view:
<div class="display-foto">
<img src="#Url.Content(Server.MapPath(Model.ImageUrl))" alt="IMAGE" />
</div>
Viewing the generated code, everything seems to be alright:
<img src="D:\Users\x\Documents\Visual Studio 2010\Projects\CMI_AD\CMI_AD\App_Data\Uploads\Fotos\_nofoto.jpg" alt="IMAGE" />
But the fact is that nothing appears on the screen except the text "IMAGE".
What am I doing wrong?
P.S. I've tried without the Server.MapPath, using the relative address "~\App_Data\Uploads\Fotos_nofoto.jpg" and the result is the same.
--- EDIT ---
#kmcc049: I've tried your suggestion creating a helper
public static class MyHelpers
{
public static IHtmlString MyImage(this HtmlHelper htmlHelper, string url)
{
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var img = new TagBuilder("img");
img.Attributes["alt"] = "[IMAGE]";
img.Attributes["src"] = UrlHelper.GenerateContentUrl(url, htmlHelper.ViewContext.HttpContext);
return MvcHtmlString.Create(img.ToString(TagRenderMode.SelfClosing));
}
}
the call in the view:
#Html.MyImage(Model.ImageUrl)
the generated code is
<img alt="[IMAGE]" src="/App_Data/Uploads/Fotos/_nofoto.jpg" />
but the result is the same: no image :(
--- SOLVED ---
Apparently the App_Data is not a good location to save uploaded files because accessing them will result an Error 403 - Forbidden. I move the files to ~/Uploads/Fotos and it works.
That's not a valid HTTP path. That's the path to the folder on your computer.
try the UrlHelper.GenerateContentUrl() method instead
http://msdn.microsoft.com/en-us/library/system.web.mvc.urlhelper.generatecontenturl.aspx
I am becoming more familiar with MVC 3 and the RAZOR view engine. I have a question regarding layouts and shared controls on pages.
Let’s say I have a header section defined in my main layout. In that header is a dropdown I need to populate with project names. This dropdown will serve as a context for the entire site and is present on all pages. As an example, if the user selects “Project A” from the drop down, all of the views for the site will be based on “Project A”. Since this dropdown control is rather static and is used by the entire site, where is the best place to put the code to pull all the projects to display in the dropdown? In a Partial View? In a HTML helper? Another thought is, if a user selects a new value, they would be taken to a dashboard or similar page for that newly selected project. I am trying to figure out how to reuse this control on every page in the site without having to keep wiring it up in every possible controller.
You could use a child action along with the Html.Action helper. So you start by defining a view model:
public class ProjectViewModel
{
[DisplayName("Project name")]
public string ProjectId { get; set; }
public IEnumerable<SelectListItem> ProjectNames { get; set; }
}
then a controller:
public class ProjectsController: Controller
{
private readonly IProjectsRepository _repository;
public ProjectsController(IProjectsRepository repository)
{
_repository = repository;
}
public ActionResult Index(string projectId)
{
var projects = _repository.GetProjects();
var model = new ProjectViewModel
{
ProjectId = projectId,
ProjectNames = projects.Select(x => new SelectListItem
{
Value = x.Id,
Text = x.Name
})
};
return PartialView(model);
}
}
then the corresponding view (~/views/projects/index.cshtml):
#model ProjectViewModel
#Html.LabelFor(x => x.ProjectId)
#Html.DropDownListFor(
x => x.ProjectId,
Model.ProjectNames,
new {
id = "projects",
data_url = Url.Action("SomeAction", "SomeController")
}
)
Now all that's left is to render this widget inside the _Layout.cshtml:
#Html.Action("Index", "Products", new { projectid = Request["projectId"] })
And now we could put some javascript so that when the user decides to change the selection he is redirected to some other action:
$(function() {
$('#projects').change(function() {
var url = $(this).data('url');
var projectId = encodeURIComponent($(this).val());
window.location.href = url + '?projectid=' + projectId;
});
});
Another possibility is to put the dropdown inside an HTML form:
#model ProjectViewModel
#using (Html.BeginForm("SomeAction", "SomeController", FormMethod.Get))
{
#Html.LabelFor(x => x.ProjectId)
#Html.DropDownListFor(
x => x.ProjectId,
Model.ProjectNames,
new {
id = "projects",
}
)
}
so that inside the javascript we don't have to worry about building urls when the selection changes and simply trigger the containing form submission:
$(function() {
$('#projects').change(function() {
$(this).closest('form').submit();
});
});
We just did a similiar thing on a project.
First, you can't really put it in a section because you have to put that section on every view, you could put it in a partial but you would still have to call it from every view.
Second, you can't really put it in the Layout page because the layout page isn't passed any kind of model. So I created an html helper and referenced that in the layout page. There are lots of tutorials on creating html helpers so I won't put the code here. But essentially in your html helper you can make a database call to get all of your projects. Then you can create a select list using string builder in the html helper and return that to the layout page. We then used jquery to add an on change event to the select list. When the select list changed it loaded a new page. So for example, in your select list the value of each item could be the project id, then on change it redirects them to a page like /Projects/View?id=234 where 234 is your project id.
So things to research. 1. Creating HTML Helpers 2. JQUERY change event.
That should get you in the right direction. Let me know if you need any other help and I can post some code.
One again Microsoft poor documentation has left me confused. I am trying to use the new features of the .NET 4.0 framework. I am using the following code to populate the Title and Director but it keeps getting blank.
The service returns the result correctly like
[d: { title = "ss, director ="" } something like that but the li never gets populated.
<script language="javascript" type="text/javascript">
Sys.require([Sys.components.dataView, Sys.components.dataContext,Sys.scripts.WebServices], function () {
Sys.create.dataView("#moviesView",
{
dataProvider: "MovieService.svc",
fetchOperation: "GetMovies",
autoFetch: true
});
});
</script>
And here it the HTML code:
<ul id="moviesView">
<li>
{{Title}} - {{Director}}
</li>
</ul>
IS THIS THE LATEST URL TO Start.js file.
<script src="http://ajax.microsoft.com/ajax/beta/0911/Start.js"></script>
Here is the Ajax-Enabled WCF Service:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MovieService
{
[OperationContract]
public Movie GetMovies()
{
return new Movie() { Title = "SS", Director = "SSSSS" };
}
}
[DataContract]
public class Movie
{
[DataMember]
public string Title { get; set; }
[DataMember]
public string Director { get; set; }
}
You need to add the sys-template class attribute to the unordered list tag.
<ul id="moviesView" class="sys-template">
Here's an excerpt from Client-side Data Binding in ASP.NET AJAX 4.0
The one other requirement for defining
a template is the parent element must
have the sys-template CSS class
applied, and that class must be
defined with display set to none, as
shown in the example above. This
convention serves two purposes – it
helps the parser identify which
elements are part of a template on
your page (which will become important
when we use declarative
instantiation), and it keeps the
template markup hidden until ASP.NET
Ajax has completed the binding (it
will toggle the display to be
visible).