I have a GraphicalViewer instance in my GEF application,
which becomes null when called inside a local method.
public FlowChart getModel()
{
Object topLevelModelElement = null;
if ( model == null )
{
EditPart topLevelEditPart = viewer.getContents();
topLevelModelElement = topLevelEditPart.getModel();
model = ( FlowChart )topLevelModelElement;
}
return model;
}
A full source code and project is uploadede at
http://www.eclipse.org/forums/index.php/t/643039/
I already inserted
configureGraphicalViewer();
initializeGraphicalViewer();
where viewer is not null.
Why is the viewer inside getModel() null when called in different method?
Related
I need some advice on how to proceed with the mvc app I'm building. On my page I type out who is logged in to the page. This I first did by creating a base class where I created a user class which contained the users name and a image representing the user. Then I passed this class on to my views. But I also need to pass other models to my views depending on what view I'm in. Sure I could build a class that contain all different models I need to use on each page but there should be a easy way to pass name and image values across the pages and be persistant? I tried TempData together with TempData.Keep() but that was not persistant. How can I pass theses values between pages?
public ActionResult Validate(AccountModels.LoginModel model)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
var mu = _repo.GetUser(Membership.GetUser().ProviderUserKey.ToString());
TempData["Name"] = mu.Name;
TempData["Image"] = mu.Image;
TempData.Keep();
FormsAuthentication.RedirectFromLoginPage(model.UserName, model.RememberMe);
}
}
return View("Index");
}
As #Jyoti said, you could use of Keep() method.
To make it easy to work with TempData, I wrote these methods in my BaseController, and I use it in every controller when I need to transfer data between actions or between view and controller.
protected TReturnType GetTempDataValue<TReturnType>(PsmConstants.TempDataKey sessionName, bool peekData =false )
{
object value = peekData ? TempData.Peek(sessionName.ToString()) : TempData[sessionName.ToString()];
return (TReturnType) value;
}
protected void RemoveTempData(PsmConstants.TempDataKey sessionName)
{
if (TempData.ContainsKey(sessionName.ToString()) && TempData[sessionName.ToString()] == null) return;
TempData[sessionName.ToString()] = null;
}
protected void SetTempDataValue(PsmConstants.TempDataKey sessionName, object value)
{
if(TempData.ContainsKey(sessionName.ToString()))
TempData[sessionName.ToString()]=null;
TempData[sessionName.ToString()] = value;
}
protected void KeepTempDataValue(PsmConstants.TempDataKey sessionName)
{
if (TempData.ContainsKey(sessionName.ToString()))
TempData.Keep(sessionName.ToString());
}
And this is the Keys enumeration :
public enum TempDataKey
{
PageError = 1,
PageInfo = 2
}
And this is, the usage of these methods(Set value and Get value from TempData):
SetTempDataValue(PsmConstants.TempDataKey.PageError , 'your error message' );
var originalValues = GetTempDataValue<MyModel>(PsmConstants.TempDataKey.Info, true);
Use session instead of Temp if it is not working.but i think it should work.
TempData["Name"] = mu.Name;TempData["Image"] = mu.Image;TempData.Keep();
How you are passing this into other models,Please share the source code so that it will easy to identify.
I currently have a view model looking like this:
public class PhrasesFrameViewModel : ObservableProperty
{
bool customPointsSwitch;
public PhrasesFrameViewModel()
{
var aButtonClickedCommand = new Command(() =>
{
App.DB.IncrementScore(App.cfs, App.phrase, (int)App.aBtn);
App.correctButtonPressed = (int)App.aBtn;
ResetTimer2();
});
var wordGridClickedCommand = new Command(() =>
{
if (App.Timer1Running)
ResetTimer1();
else
ResetTimer2();
});
}
private static void ResetTimer1()
{
if (App.tokenSource1 != null)
{
App.Timer1Seconds = 0;
App.tokenSource1.Cancel();
}
}
private static void ResetTimer2()
{
if (App.tokenSource2 != null)
{
App.Timer2Seconds = 0;
App.tokenSource2.Cancel();
}
}
public bool CustomPointsSwitch
{
get
{
return customPointsSwitch;
}
set
{
if (value != customPointsSwitch)
{
customPointsSwitch = value;
NotifyPropertyChanged("CustomPointsSwitch");
App.DB.UpdateBoolSetting(Settings.Cp, customPointsSwitch);
}
}
}
I believe most view models would have code similar to that for CustomPointsSwitch but how about the code for the gesture recognizers and the commands plus the small method for reset (used by a few other methods in the view model). Does that all belong in the view model or should it be in another class?
Short answer: In this particular case, as per code shared in question, they belong in view model.
Long answer:
It depends. If your command handler needs to interact with UI - it should stay in view; If it is anything else, i.e. presentation or business logic - it should be defined in view model.
Commands are integral part of MVVM pattern - as they allow for decoupling of view model from view, which in turn makes it easier to unit test, maintain and extend. They are the recommended channel for communication between view and view-model (other than data-binding).
In most of the cases, the command interface is used when a user-interaction/event in view needs to trigger various actions in the view-model - and in these cases command is defined in view-model itself and exposed as a property.
I have this call on one view model
ShowViewModel<MyViewModel>(
new MyParams { ... }
);
On MyViewModel I have this Init method which works perfect
public void Init(MyParams params)
{
if (params != null)
{
// some logic
}
else
{
// some other logic
}
}
On another view model I have
ShowViewModel<MyViewModel>();
I expect to receive null on MyViewModel init method, instead of that I get an instance of 'MyParams'. That's generating problems since I have specific logic to handle the call with no parameters
I have custom presenter logic that might responsible for this, but at first sight I couldn't identify any custom logic as responsible. Is this the standard behavior for complex params?
Unfortunately, no there isn't a way to pass null using a parameters object.
The reason is that when Mvx creates the ViewModel and attempts to call the Init method, it will first convert your object instance into a simple dictionary (key/value pairs). If you use the no arg version, then it creates an empty dictionary. At this point, it creates an MvxBundle which includes the dictionary.
When Mvx is finally ready to call your Init method, it takes this dictionary and attempts to create an actual object.
It's this method that creates the instance to pass to Init.
MvxSimplePropertyDictionaryExtensionMethods.Read()
https://github.com/MvvmCross/MvvmCross/blob/8a824c797747f74716fc64c2fd0e8765c29b16ab/MvvmCross/Core/Core/Platform/MvxSimplePropertyDictionaryExtensionMethods.cs#L54-L72
public static object Read(this IDictionary<string, string> data, Type type)
{
var t = Activator.CreateInstance(type);
var propertyList =
type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy).Where(p => p.CanWrite);
foreach (var propertyInfo in propertyList)
{
string textValue;
if (!data.TryGetValue(propertyInfo.Name, out textValue))
continue;
var typedValue = MvxSingletonCache.Instance.Parser.ReadValue(textValue, propertyInfo.PropertyType,
propertyInfo.Name);
propertyInfo.SetValue(t, typedValue, new object[0]);
}
return t;
}
Notice how it calls Activator.CreateInstance(type) which will always return an instance.
So that is why you'll never get an null value in Init.
My recommendation is to simply add a property to your MyParams object and set that in your no-arg version. Then in Init you can check the property to determine what to do.
Something like:
ShowViewModel<MyViewModel>(new MyParams { HasNoParams = true });
public void Init(MyParams myParams)
{
if (myParams.HasNoParams)
{
// do null flow here
}
else
{
// do non-null flow here
}
}
You can use Dictionary< TKey, TValue> as your params.
I am building a solution with Sitecore 7 and ASP.NET-MVC 3 and trying to use a custom model class as described in this blog post by john west.
I have seen several other questions here on SO reporting a similar error with ASP.NET-MVC (without Sitecore), usually related to passing the wrong type of object in controller code, or there being a configuration error with the \Views\web.config file, but neither seem to be the issue here.
this issue is caused when you create a view rendering (possibly others but i haven't tried it) and you have not set up the model in sitecore, so sitecore is passing in its default model.
To fix this you have to go to the layouts section and create a model.
this is the path in sitecore '/sitecore/layout/Models/', in this folder create a 'Model' item and in the model type field you add the reference to your model in the format 'my.model.namespace, my.assembly' without the quotes.
your model needs to inherit 'Sitecore.Mvc.Presentation.IRenderingModel' which forces you to implement the 'Initialize' method, in here you populate data from the sitecore item into the properties of the model. here is an example model...
namespace Custom.Models.ContentBlocks
{
using Sitecore.Data.Fields;
using Sitecore.Mvc.Presentation;
public class BgImageTitleText : IRenderingModel
{
public string Title { get; set; }
public string BgImage { get; set; }
public string BgImageAlt { get; set; }
public string BgColour { get; set; }
public string CtaText { get; set; }
public string CtaLink { get; set; }
public void Initialize(Rendering rendering)
{
var dataSourceItem = rendering.Item;
if (dataSourceItem == null)
{
return;
}
ImageField bgImage = dataSourceItem.Fields[Fields.ContentBlocks.BgImageTitleTextItem.BgImage];
if (bgImage != null && bgImage.MediaItem != null)
{
this.BgImageAlt = bgImage.Alt;
this.BgImage = Sitecore.Resources.Media.MediaManager.GetMediaUrl(bgImage.MediaItem);
}
var title = dataSourceItem.Fields[Fields.ContentBlocks.BgImageTitleTextItem.Title];
if (title != null)
{
this.Title = title.Value;
}
var link = (LinkField)dataSourceItem.Fields[Fields.ContentBlocks.BgImageTitleTextItem.CtaLink];
if (link != null)
{
this.CtaLink = link.GetLinkFieldUrl();
}
var ctaText = dataSourceItem.Fields[Fields.ContentBlocks.BgImageTitleTextItem.CtaText];
if (ctaText != null)
{
this.CtaText = ctaText.Value;
}
var bgColour = dataSourceItem.Fields[Fields.ContentBlocks.BgImageTitleTextItem.BgColour];
if (bgColour != null)
{
this.BgColour = bgColour.Value;
}
}
}
}
Then you have to go to your view rendering (or possibly other types of rendering) and in the 'Model' field you click insert link and click on your newly created model.
This error can be caused when a controller rendering invokes a controller method which returns an ActionResult object instead of a PartialViewResult. In my case I had a rendering model associated with the layout which I believe Sitecore was trying to pass to my controller rendering.
RenderingModel is used when you create a Rendering based on the View Rendering template. This model is created by the sitecore MVC pipelines and is automatically assigned to the view.
To have control over what model to bind to the view, you probably want to use a Controller Rendering, then you can pass in your own model from your controller.
I'm using SPMetal in order to generate entity classes for my sharepoint site and I'm not exactly sure what the best practice is to use when there are multiple content types for a single list. For instance I have a task list that contains 2 content types and I'm defining them via the config file for SPMetal. Here is my definition...
<List Member="Tasks" Name="Tasks">
<ContentType Class="LegalReview" Name="LegalReviewContent"/>
<ContentType Class="Approval" Name="ApprovalContent"/>
</List>
This seems to work pretty well in that the generated objects do inherit from WorkflowTask but the generated type for the data context is a List of WorkflowTask. So when I do a query I get back a WorkflowTask object instead of a LegalReview or Approval object. How do I make it return an object of the correct type?
[Microsoft.SharePoint.Linq.ListAttribute(Name="Tasks")]
public Microsoft.SharePoint.Linq.EntityList<WorkflowTask> Tasks {
get {
return this.GetList<WorkflowTask>("Tasks");
}
}
UPDATE
Thanks for getting back to me. I'm not sure how I recreate the type based on the SPListItem and would appreciate any feedback.
ContractManagementDataContext context = new ContractManagementDataContext(_url);
WorkflowTask task = context.Tasks.FirstOrDefault(t => t.Id ==5);
Approval a = new Approval(task.item);
public partial class Approval{
public Approval(SPListItem item){
//Set all properties here for workflowtask and approval type?
//Wouldn't there be issues since it isn't attached to the datacontext?
}
public String SomeProperty{
get{ //get from list item};
set{ //set to list item};
}
Linq2SharePoint will always return an object of the first common base ContentType for all the ContentTypes in the list. This is not only because a base type of some description must be used to combine the different ContentTypes in code but also it will then only map the fields that should definitely exist on all ContentTypes in the list. It is however possible to get access to the underlying SPListItem returned by L2SP and thus from that determine the ContentType and down cast the item.
As part of a custom repository layer that is generated from T4 templates we have a partial addition to the Item class generated by SPMetal which implements ICustomMapping to get the data not usually available on the L2SP entities. A simplified version is below which just gets the ContentType and ModifiedDate to show the methodology; though the full class we use also maps Modified By, Created Date/By, Attachments, Version, Path etc, the principle is the same for all.
public partial class Item : ICustomMapping
{
private SPListItem _SPListItem;
public SPListItem SPListItem
{
get { return _SPListItem; }
set { _SPListItem = value; }
}
public string ContentTypeId { get; internal set; }
public DateTime Modified { get; internal set; }
public virtual void MapFrom(object listItem)
{
SPListItem item = (SPListItem)listItem;
this.SPListItem = item;
this.ContentTypeId = item.ContentTypeId.ToString();
this.Modified = (DateTime)item["Modified"];
}
public virtual void MapTo(object listItem)
{
SPListItem item = (SPListItem)listItem;
item["Modified"] = this.Modified == DateTime.MinValue ? this.Modified = DateTime.Now : this.Modified;
}
public virtual void Resolve(RefreshMode mode, object originalListItem, object databaseObject)
{
SPListItem originalItem = (SPListItem)originalListItem;
SPListItem databaseItem = (SPListItem)databaseObject;
DateTime originalModifiedValue = (DateTime)originalItem["Modified"];
DateTime dbModifiedValue = (DateTime)databaseItem["Modified"];
string originalContentTypeIdValue = originalItem.ContentTypeId.ToString();
string dbContentTypeIdValue = databaseItem.ContentTypeId.ToString();
switch(mode)
{
case RefreshMode.OverwriteCurrentValues:
this.Modified = dbModifiedValue;
this.ContentTypeId = dbContentTypeIdValue;
break;
case RefreshMode.KeepCurrentValues:
databaseItem["Modified"] = this.Modified;
break;
case RefreshMode.KeepChanges:
if (this.Modified != originalModifiedValue)
{
databaseItem["Modified"] = this.Modified;
}
else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue)
{
this.Modified = dbModifiedValue;
}
if (this.ContentTypeId != originalContentTypeIdValue)
{
throw new InvalidOperationException("You cannot change the ContentTypeId directly");
}
else if (this.ContentTypeId == originalContentTypeIdValue && this.ContentTypeId != dbContentTypeIdValue)
{
this.ContentTypeId = dbContentTypeIdValue;
}
break;
}
}
}
Once you have the ContentType and the underlying SPListItem available on your L2SP entity it is simply a matter of writing a method which returns an instance of the derived ContentType entity from a combination of the values of the base type and the extra data for the missing fields from the SPListItem.
UPDATE: I don't actually have an example converter class as we don't use the above mapping extension to Item in this way. However I could imagine something like this would work:
public static class EntityConverter
{
public static Approval ToApproval(WorkflowTask wft)
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = wft.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = wft.SPListItem["field-name"];
return a;
}
}
Or you could put a method on a partial instance of WorkflowTask to return an Approval object.
public partial class WorkflowTask
{
public Approval ToApproval()
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = this.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = this.SPListItem["field-name"];
return a;
}
public LegalReview ToLegalReview()
{
// Create and return LegalReview as for Approval
}
}
In either situation you would need to determine the method to call to get the derived type from the ContentTypeId property of the WorkflowTask. This is the sort of code I would normally want to generate in one form or another as it will be pretty repetitive but that is a bit off-topic.