Getting custom type from TempData asp.net mvc 2 - asp.net-mvc-2

I have a custom class MyCustomType. In that class I have a property MyCustomProperty of type bool and another property MyCustomProperty1 of type bool also.
I need to check if MyCustomProperty is true in my View. I`m doing the following thing:
<%if ( TempData[ViewDataConstants.MyCustomTypeKey] != null && ((MyCustomType)TempData[ViewDataConstants.MyCustomTypeKey]).MyCustomProperty %>show some custom content.
But for some reason when Im running it I see error message that MyCustomTYpe could not be found are you missing an assembly reference bla-bla-bla. MyCustomType is in my controller its public and to check I even added a reference to the view. But it keep saying that there`s no MyCustomType class. What am I doing wrong?
Interesting, for some reason when I moved it to Common from Controllers namespace it suddenly worked. Still dont see why its not working while in Controllers namespace.
Both namespaces were included explicitly in the view.

No idea why it didn't work but quite honestly having all this code in a view looks wrong to me. Maybe it's just like me, Visual Studio doesn't like writing C# code in a view :-).
This should be a property on your view model:
public class MyViewModel
{
public bool MyCustomProperty { get; set; }
}
and inside your controller:
public ActionResult Foo()
{
var model = TempData[ViewDataConstants.MyCustomTypeKey] as MyCustomType ?? new MyCustomType();
var viewModel = Mapper.Map<MyCustomType, MyViewModel>(model);
return View(viewModel);
}
and finally inside your view:
<% if (Model.MyCustomProperty) { %>
show some custom content.
<% } %>
Now you no longer need any usings, castings, ... in the view.

Related

Return PartialView in JsonResult

I think about migrating from .net core mvc to razor pages so I am building demo application where I try the features from mvc i used and i stucked a little when I am trying to reload some part of the page based on ajax request using partial view. Sometimes partial view is very simple, like in the following example and sometimes very complex (it can contains additional nested partial views with forms etc. and suprisingly its working well).
My CustomersModel : PageModel handler looks like
it has return JsonResult because i need feedback about errors
sometimes I return more than one partial view
public JsonResult OnGetCustomerDetailPartialView(int id)
{
PopulateCustomers();
var model = new PartialViews.CustomerDetailViewModel()
{
Customer = Customers.Where(x => x.Id == id).FirstOrDefault()
};
var partialView = PartialViewHelper.PartialView("/PartialViews/CustomerDetailViewModel.cs", model, ViewData, TempData);
return new JsonResult(new { success = true, html = partialView.ToStringExtension() });
}
Partial View helper
public static class PartialViewHelper
{
public static PartialViewResult PartialView(string viewName, object model,
ViewDataDictionary viewData, ITempDataDictionary tempData)
{
viewData.Model = model; <-- this line throws error
return new PartialViewResult()
{
ViewName = viewName,
ViewData = viewData,
TempData = tempData
};
}
}
and the problem here is that i got an error
System.InvalidOperationException: 'The model item passed into the
ViewDataDictionary is of type
'RazorPages.PartialViews.CustomerDetailViewModel', but this
ViewDataDictionary instance requires a model item of type
'RazorPages.Pages.CustomersModel'.'
So the ViewData are bind to the CustomerModel, it is possible to return partial view specific ViewModel ?
The bottom line question is, should I approach Razor Pages as an replacement for the MVC or they are intended for less complicated projects than MVC ?
In response to the technical issue, try this version of your method:
public static class PartialViewHelper
{
public static PartialViewResult PartialView<T>(string viewName, object model, ViewDataDictionary viewData, ITempDataDictionary tempData)
{
return new PartialViewResult()
{
ViewName = viewName,
ViewData = new ViewDataDictionary<T>(viewData, model),
TempData = tempData
};
}
}
Then call it as follows (although the name of the partial view doesn't look right to me):
var partialView = PartialViewHelper.PartialView<PartialViews.CustomerDetailViewModel>("/PartialViews/CustomerDetailViewModel.cs", model, ViewData, TempData);
And in reply to the bottom line question, Razor Pages builds on MVC. Anything that you can do with MVC, you can also do with Razor Pages. It is intended to replace MVC for server-side generation of HTML. You can build as complicated an application as you like with it. But your code will likely be a lot simpler than an equivalent MVC application, which is a good thing, right?

freshmvvm access PageModel from Page code behind

Im using xamarin forms with freshmvvm framework.
I would like to know how I can skip using xaml, and just access binding data from code behind in c#.
Are there any code samples that could help?
Although this goes against the principles of MVVM there is of course a way to do it.
Without a MVVM framework you would just create a ViewModel by hand and set the BindingContext (documentation) yourself. The 'only' thing (in regard to this) a MVVM framework does for you is set that binding up automatically so you're not bothered with writing the same code over and over again.
So, imagine you have this ViewModel, note I user PageModel to match the FreshMvvm naming:
// SamplePageModel.cs
public class SamplePageModel
{
public string Foo { get; set; } = "Bar";
}
Now in my Page, I set the BindingContext like this:
// SamplePage.cs
// ... Skipped code, just constructor here:
public SamplePage()
{
InitializeComponent();
BindingContext = new SamplePageModel();
}
Now you can bind to any property of SamplePageModel.
FreshMvvm does this part automagically.
If, for whatever reason, you would like to access the ViewModel/PageModel directly, just do the reverse. Somewhere in your Page or code-behind you can do:
// ... Some code here
var pageModel = BindingContext as SamplePageModel;
// ... More code here
Now if pageModel isn't null there you have your data-bound and filled PageModel!
I found Gerald's answer helpful, but I found that you need to override this event in your page vs doing the as in the constructor:
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
var pageModel = BindingContext as YourFreshMVVMPageModel;
// Modify the page based on the pageModel
}
The PageModel construction seems to take place after the page Constructor, and this Event seems to fire at the right time and still make the page do what you want.

Finding a View with IViewFor<InterfaceClass> from a class VM that implements InterfaceClass?

I have the following class which is my view model (this is very simple right now, but it will contain a chunk more logic eventually):
public class IndicoTalk : ITalk
{
private Talk _talk;
public IndicoTalk(Talk t)
{
this._talk = t;
}
public string Title
{
get { return _talk.Title; }
}
}
Now, I have a reactive ui view for this guy:
public sealed partial class TalkView : UserControl, IViewFor<ITalk>
{
public TalkView()
{
this.InitializeComponent();
this.Bind(ViewModel, x => x.Title, y => y.TalkTitle.Text);
}
Note that the IViewFor is for ITalk, not IndicoTalk. This is because I can have other types of talk, and they will all fit into the same view.
And I register this ViewModel in my App start up:
Locator.CurrentMutable.Register(() => new TalkView(),
typeof(IViewFor<IWalker.DataModel.Inidco.IndicoMeetingRef.IndicoTalk>));
Finally, in another viewmodel I have a ReactiveList which contains a bunch of these IndicoTalks's. Of course, when I bind this to a ListBox, ReactiveUI fails to find the view. If I switch to IViewFor then everything works just fine.
What is the proper way to gently redirect the view resolution in this case?
A half-way solution: leave all code above the same, but put in the IViewFor ITalk instead of IndicoTalk. This works, but means I will have to register with Splat (the CurrentMutable call above) every ViewModel that inherrits from ITalk. I'd love to avoid that if possible!
Many thanks!
So, why not just do:
Locator.CurrentMutable.Register(() => new TalkView(), typeof(IViewFor<ITalk>));

how to parametrize an import in a View?

I am looking for some help and I hope that some good soul out there will be able to give me a hint :)
I am building a new application by using MVVM Light. In this application, when a View is created, it instantiates the corresponding ViewModel by using the MEF import.
Here is some code:
public partial class ContractEditorView : Window
{
public ContractEditorView ()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
[Import(ViewModelTypes.ContractEditorViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
}
And here is the export for the ViewModel:
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(ViewModelTypes.ContractEditorViewModel)]
public class ContractEditorViewModel: ViewModelBase
{
public ContractEditorViewModel()
{
_contract = new Models.Contract();
}
}
Now, this works if I want to open a new window in order to create a new contract... or in other words, it is perfect if I don't need to pass the ID of an existing contract.
However let's suppose I want to use the same View in order to edit an existing contract. In this case I would add a new constructor to the same View, which accepts either a model ID or a model object.
"Unfortunately" the ViewModel is created always in the same way:
[Import(ViewModelTypes.ContractEditorViewModel)]
public object ViewModel
{
set
{
DataContext = value;
}
}
As far as I know, this invokes the standard/no-parameters constructor of the corresponding ViewModel at composition-time.
So what I would like to know is how to differentiate this behavior? How can I call a specific constructor during composition time? Or how can I pass some parameters during the Import?
I really apologize if this question sounds silly, but I have only recently started to use MEF!
Thanks in advance,
Cheers,
Gianluca.
You CAN do this. Check out the Messenger implementation in MVVM-Light. You can pass a NotificationMessage(Of Integer) to send the right ID to the view model. The view model has to register for that type of message, and load it when a message is sent.
MEF Imports by default only have a parameterless constructor.

ASP.NET MVC2: Getting textbox data from a view to a controller

I'm having difficulty getting data from a textbox into a Controller. I've read about a few ways to accomplish this in Sanderson's book, Pro ASP.NET MVC Framework, but haven't had any success.
Also, I've ran across a few similiar questions online, but haven't had any success there either. Seems like I'm missing something rather fundamental.
Currently, I'm trying to use the action method parameters approach. Can someone point out where I'm going wrong or provide a simple example? Thanks in advance!
Using Visual Studio 2008, ASP.NET MVC2 and C#:
What I would like to do is take the data entered in the "Investigator" textbox and use it to filter investigators in the controller. I plan on doing this in the List method (which is already functional), however, I'm using the SearchResults method for debugging.
Here's the textbox code from my view, SearchDetails:
<h2>Search Details</h2>
<% using (Html.BeginForm()) { %>
<fieldset>
<%= Html.ValidationSummary() %>
<h4>Investigator</h4>
<p>
<%=Html.TextBox("Investigator")%>
<%= Html.ActionLink("Search", "SearchResults")%>
</p>
</fieldset>
<% } %>
Here is the code from my controller, InvestigatorsController:
private IInvestigatorsRepository investigatorsRepository;
public InvestigatorsController(IInvestigatorsRepository investigatorsRepository)
{
//IoC:
this.investigatorsRepository = investigatorsRepository;
}
public ActionResult List()
{
return View(investigatorsRepository.Investigators.ToList());
}
public ActionResult SearchDetails()
{
return View();
}
public ActionResult SearchResults(SearchCriteria search)
{
string test = search.Investigator;
return View();
}
I have an Investigator class:
[Table(Name = "INVESTIGATOR")]
public class Investigator
{
[Column(IsPrimaryKey = true, IsDbGenerated = false, AutoSync=AutoSync.OnInsert)]
public string INVESTID { get; set; }
[Column] public string INVEST_FNAME { get; set; }
[Column] public string INVEST_MNAME { get; set; }
[Column] public string INVEST_LNAME { get; set; }
}
and created a SearchCriteria class to see if I could get MVC to push the search criteria data to it and grab it in the controller:
public class SearchCriteria
{
public string Investigator { get; set; }
}
}
I'm not sure if project layout has anything to do with this either, but I'm using the 3 project approach suggested by Sanderson: DomainModel, Tests, and WebUI. The Investigator and SearcCriteria classes are in the DomainModel project and the other items mentioned here are in the WebUI project.
Thanks again for any hints, tips, or simple examples!
Mike
try strongly typing the page to use SearchCriteria to autopost the data like that ex:
public partial class Search: ViewPage<SearchDetails>
This should do it for you (unable to verify this is perfect - typed this from memory):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SearchDetails(FormCollection formValues)
{
var txtContents = formValues["Investigator"];
// do stuff with txtContents
return View();
}
1.) Have you looked into ViewModels for your View? In essence that is what your SearchCriteria class is. Make sure you strongly type your view with that model:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MyMaster.Master" Inherits="System.Web.Mvc.ViewPage<SearchCritieria>"
Also make sure that you use the HtmlHelper.TextBoxFor method to map this Investigator property to the SearchCritiera model. On Post back your text box value should be there:
'<%=Html.TextBoxFor(model => model.Invesigator)%>'
Good luck!
Also here is a great reference on using ViewModels that I have looked at a lot recently:
http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
Thanks for the tips everyone. For learning purposes, I need to go back and follow the strongly typed route. I'm curious if I would have run into this problem if I would have done that from the beginning.
Until then, the following worked:
Use a submit button
Use this code for the form:
<% using(Html.BeginForm(new { Action = "SearchResults"})) { %> <% } >
Thanks again for you help!
Mike