I previously used Caliburn.Micro for my projects before universal windows application. Now I'm porting my apps to universal windows and decided to use Prism Library. Because there are lots of uwp sample for that. But I'm too beginner and don't know how to convert my old viewmodels.
I'm using webview to show some generated html. In caliburn I can find webview in viewmodel using OnViewLoaded event;
protected override void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
var frameworkElement = view as FrameworkElement;
if (frameworkElement == null)
throw new ArgumentException();
var browser = frameworkElement.FindName("browser") as WebView;
if (browser == null)
throw new ArgumentException();
_webBrowser = browser;
}
But I didn't find any event can provide this. In prism there are only OnNavigatedTo and OnNavigatingFrom events.
Do prism have workaround for that?
Sorry about late reply,
I aggree with Igor and Tseng that will break MVVM pattern. But I'm trying to do something complex. Maybe there is a way of doing with it MVVM but I don't want to lose too much time on this.
What I found solution for the problem is as following. I wrote a VisualHelper
public class VisualHelper
{
public static T FindVisualChildInsideFrame<T>(DependencyObject depObj) where T : DependencyObject
{
var frame = FindVisualChild<Frame>(depObj);
if (frame != null && frame.Content is Page)
return FindVisualChild<T>(frame.Content as Page);
return null;
}
public static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null)
return childItem;
}
}
return null;
}
}
In my viewmodel, using following code finds WebView control. I'm using SplitView control thats why I'm using FindVisualChildInsideFrame method.
public override void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
{
base.OnNavigatedTo(e, viewModelState);
var browser = VisualHelper.FindVisualChildInsideFrame<WebView>(Window.Current.Content);
}
In the top of the Hierarchy window of the Unity Editor there is a field for filtering the hierarchy:
My question is if you can set that filter from an editor script and how. I can barely find anything according to this on the web.
Thanks in advance.
UnityEditor.SceneModeUtility.SearchForType seems to be a step in the right direction.
The good news is, that you can see the implementation of that method in MonoDevelop..
Taking a closer look at it tells us the methods we'd need.
public static void SearchForType (Type type)
{
Object[] array = Resources.FindObjectsOfTypeAll (typeof(SceneHierarchyWindow));
SceneHierarchyWindow sceneHierarchyWindow = (array.Length <= 0) ? null : (array [0] as SceneHierarchyWindow);
if (sceneHierarchyWindow)
{
SceneModeUtility.s_HierarchyWindow = sceneHierarchyWindow;
if (type == null || type == typeof(GameObject))
{
SceneModeUtility.s_FocusType = null;
sceneHierarchyWindow.ClearSearchFilter ();
}
else
{
SceneModeUtility.s_FocusType = type;
if (sceneHierarchyWindow.searchMode == SearchableEditorWindow.SearchMode.Name)
{
sceneHierarchyWindow.searchMode = SearchableEditorWindow.SearchMode.All;
}
sceneHierarchyWindow.SetSearchFilter ("t:" + type.Name, sceneHierarchyWindow.searchMode, false);
sceneHierarchyWindow.hasSearchFilterFocus = true;
}
}
else
{
SceneModeUtility.s_FocusType = null;
}
}
And now the bad news, due to their protection level, you can neither access the hierarchy window directly, nor can you use the SetSearchFilter method.
Maybe you could write an editor script, similar to the hierarchy view, where you have full control, and can do whatever you want.
Thanks to d4RK I found out how to do it using Reflection:
public const int FILTERMODE_ALL = 0;
public const int FILTERMODE_NAME = 1;
public const int FILTERMODE_TYPE = 2;
public static void SetSearchFilter(string filter, int filterMode) {
SearchableEditorWindow[] windows = (SearchableEditorWindow[])Resources.FindObjectsOfTypeAll (typeof(SearchableEditorWindow));
foreach (SearchableEditorWindow window in windows) {
if(window.GetType().ToString() == "UnityEditor.SceneHierarchyWindow") {
hierarchy = window;
break;
}
}
if (hierarchy == null)
return;
MethodInfo setSearchType = typeof(SearchableEditorWindow).GetMethod("SetSearchFilter", BindingFlags.NonPublic | BindingFlags.Instance);
object[] parameters = new object[]{filter, filterMode, false};
setSearchType.Invoke(hierarchy, parameters);
}
This may not be the most elegant way, but it works like a charm and can easily be extended to apply the same filter to the SceneView.
As of Unity 2018 there is an additional boolean parameter required for the SetSearchFilter method.
So change this line
object[] parameters = new object[]{filter, filterMode, false};
to
object[] parameters = new object[]{filter, filterMode, false, false};
This should resolve the TargetParameterCountException Ugo Hed mentioned.
I've run into a bit of a design issue, and I'm curious if anyone else has run into something similar.
I have a fairly complex model which I have an Edit action method for. Each individual entity has two images associated with it, along with other, more mundane data. These images are [Required] upon creation. When editing an entity, however, these images already exist, since, again, they were required upon creation. Thus, I don't need to mark them as required.
Adding a bit of a monkey wrench to the whole thing is my custom image validation attribute:
public class ValidateFileAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
var file = value as HttpPostedFileBase;
if (file == null)
{
return false;
}
string[] validExtensions = { "jpg", "jpeg", "gif", "png" };
string[] validMimeTypes = { "image/jpeg", "image/pjepeg", "image/gif", "image/png" };
string[] potentialFileExtensions = file.FileName.Split('.');
string lastExtension = potentialFileExtensions[(potentialFileExtensions.Length - 1)];
string mimeType = file.ContentType;
bool extensionFlag = false;
bool mimeFlag = false;
foreach (string extension in validExtensions)
{
if (extension == lastExtension)
{
extensionFlag = true;
}
}
foreach (string mt in validMimeTypes)
{
if (mt == mimeType)
{
mimeFlag = true;
}
}
if (extensionFlag && mimeFlag)
{
return true;
}
else
{
return false;
}
}
}
What I'd ideally like to do would be to create some kind of [Optional] attribute which would bypass the image validator altogether if new files aren't POSTed along with the rest of the form data.
Is something like this possible? If not, how would the collective wisdom of Stack Overflow address the problem?
you might be interested in following article...
but i have to say i do agree with most in the article.
mainly the part : conditional validation
http://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/
hope this will helps.
Like several other people, I'm having problems serializing Entity Framework objects, so that I can send the data over AJAX in a JSON format.
I've got the following server-side method, which I'm attempting to call using AJAX through jQuery
[WebMethod]
public static IEnumerable<Message> GetAllMessages(int officerId)
{
SIBSv2Entities db = new SIBSv2Entities();
return (from m in db.MessageRecipients
where m.OfficerId == officerId
select m.Message).AsEnumerable<Message>();
}
Calling this via AJAX results in this error:
A circular reference was detected while serializing an object of type \u0027System.Data.Metadata.Edm.AssociationType
Which is because of the way the Entity Framework creates circular references to keep all the objects related and accessible server side.
I came across the following code from (http://hellowebapps.com/2010-09-26/producing-json-from-entity-framework-4-0-generated-classes/) which claims to get around this problem by capping the maximum depth for references. I've added the code below, because I had to tweak it slightly to get it work (All angled brackets are missing from the code on the website)
using System.Web.Script.Serialization;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System;
public class EFObjectConverter : JavaScriptConverter
{
private int _currentDepth = 1;
private readonly int _maxDepth = 2;
private readonly List<int> _processedObjects = new List<int>();
private readonly Type[] _builtInTypes = new[]{
typeof(bool),
typeof(byte),
typeof(sbyte),
typeof(char),
typeof(decimal),
typeof(double),
typeof(float),
typeof(int),
typeof(uint),
typeof(long),
typeof(ulong),
typeof(short),
typeof(ushort),
typeof(string),
typeof(DateTime),
typeof(Guid)
};
public EFObjectConverter( int maxDepth = 2,
EFObjectConverter parent = null)
{
_maxDepth = maxDepth;
if (parent != null)
{
_currentDepth += parent._currentDepth;
}
}
public override object Deserialize( IDictionary<string,object> dictionary, Type type, JavaScriptSerializer serializer)
{
return null;
}
public override IDictionary<string,object> Serialize(object obj, JavaScriptSerializer serializer)
{
_processedObjects.Add(obj.GetHashCode());
Type type = obj.GetType();
var properties = from p in type.GetProperties()
where p.CanWrite &&
p.CanWrite &&
_builtInTypes.Contains(p.PropertyType)
select p;
var result = properties.ToDictionary(
property => property.Name,
property => (Object)(property.GetValue(obj, null)
== null
? ""
: property.GetValue(obj, null).ToString().Trim())
);
if (_maxDepth >= _currentDepth)
{
var complexProperties = from p in type.GetProperties()
where p.CanWrite &&
p.CanRead &&
!_builtInTypes.Contains(p.PropertyType) &&
!_processedObjects.Contains(p.GetValue(obj, null)
== null
? 0
: p.GetValue(obj, null).GetHashCode())
select p;
foreach (var property in complexProperties)
{
var js = new JavaScriptSerializer();
js.RegisterConverters(new List<JavaScriptConverter> { new EFObjectConverter(_maxDepth - _currentDepth, this) });
result.Add(property.Name, js.Serialize(property.GetValue(obj, null)));
}
}
return result;
}
public override IEnumerable<System.Type> SupportedTypes
{
get
{
return GetType().Assembly.GetTypes();
}
}
}
However even when using that code, in the following way:
var js = new System.Web.Script.Serialization.JavaScriptSerializer();
js.RegisterConverters(new List<System.Web.Script.Serialization.JavaScriptConverter> { new EFObjectConverter(2) });
return js.Serialize(messages);
I'm still seeing the A circular reference was detected... exception being thrown!
I solved these issues with the following classes:
public class EFJavaScriptSerializer : JavaScriptSerializer
{
public EFJavaScriptSerializer()
{
RegisterConverters(new List<JavaScriptConverter>{new EFJavaScriptConverter()});
}
}
and
public class EFJavaScriptConverter : JavaScriptConverter
{
private int _currentDepth = 1;
private readonly int _maxDepth = 1;
private readonly List<object> _processedObjects = new List<object>();
private readonly Type[] _builtInTypes = new[]
{
typeof(int?),
typeof(double?),
typeof(bool?),
typeof(bool),
typeof(byte),
typeof(sbyte),
typeof(char),
typeof(decimal),
typeof(double),
typeof(float),
typeof(int),
typeof(uint),
typeof(long),
typeof(ulong),
typeof(short),
typeof(ushort),
typeof(string),
typeof(DateTime),
typeof(DateTime?),
typeof(Guid)
};
public EFJavaScriptConverter() : this(1, null) { }
public EFJavaScriptConverter(int maxDepth = 1, EFJavaScriptConverter parent = null)
{
_maxDepth = maxDepth;
if (parent != null)
{
_currentDepth += parent._currentDepth;
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
return null;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
_processedObjects.Add(obj.GetHashCode());
var type = obj.GetType();
var properties = from p in type.GetProperties()
where p.CanRead && p.GetIndexParameters().Count() == 0 &&
_builtInTypes.Contains(p.PropertyType)
select p;
var result = properties.ToDictionary(
p => p.Name,
p => (Object)TryGetStringValue(p, obj));
if (_maxDepth >= _currentDepth)
{
var complexProperties = from p in type.GetProperties()
where p.CanRead &&
p.GetIndexParameters().Count() == 0 &&
!_builtInTypes.Contains(p.PropertyType) &&
p.Name != "RelationshipManager" &&
!AllreadyAdded(p, obj)
select p;
foreach (var property in complexProperties)
{
var complexValue = TryGetValue(property, obj);
if(complexValue != null)
{
var js = new EFJavaScriptConverter(_maxDepth - _currentDepth, this);
result.Add(property.Name, js.Serialize(complexValue, new EFJavaScriptSerializer()));
}
}
}
return result;
}
private bool AllreadyAdded(PropertyInfo p, object obj)
{
var val = TryGetValue(p, obj);
return _processedObjects.Contains(val == null ? 0 : val.GetHashCode());
}
private static object TryGetValue(PropertyInfo p, object obj)
{
var parameters = p.GetIndexParameters();
if (parameters.Length == 0)
{
return p.GetValue(obj, null);
}
else
{
//cant serialize these
return null;
}
}
private static object TryGetStringValue(PropertyInfo p, object obj)
{
if (p.GetIndexParameters().Length == 0)
{
var val = p.GetValue(obj, null);
return val;
}
else
{
return string.Empty;
}
}
public override IEnumerable<Type> SupportedTypes
{
get
{
var types = new List<Type>();
//ef types
types.AddRange(Assembly.GetAssembly(typeof(DbContext)).GetTypes());
//model types
types.AddRange(Assembly.GetAssembly(typeof(BaseViewModel)).GetTypes());
return types;
}
}
}
You can now safely make a call like new EFJavaScriptSerializer().Serialize(obj)
Update : since version Telerik v1.3+ you can now override the GridActionAttribute.CreateActionResult method and hence you can easily integrate this Serializer into specific controller methods by applying your custom [GridAction] attribute:
[Grid]
public ActionResult _GetOrders(int id)
{
return new GridModel(Service.GetOrders(id));
}
and
public class GridAttribute : GridActionAttribute, IActionFilter
{
/// <summary>
/// Determines the depth that the serializer will traverse
/// </summary>
public int SerializationDepth { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="GridActionAttribute"/> class.
/// </summary>
public GridAttribute()
: base()
{
ActionParameterName = "command";
SerializationDepth = 1;
}
protected override ActionResult CreateActionResult(object model)
{
return new EFJsonResult
{
Data = model,
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
MaxSerializationDepth = SerializationDepth
};
}
}
and finally..
public class EFJsonResult : JsonResult
{
const string JsonRequest_GetNotAllowed = "This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.";
public EFJsonResult()
{
MaxJsonLength = 1024000000;
RecursionLimit = 10;
MaxSerializationDepth = 1;
}
public int MaxJsonLength { get; set; }
public int RecursionLimit { get; set; }
public int MaxSerializationDepth { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(JsonRequest_GetNotAllowed);
}
var response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
var serializer = new JavaScriptSerializer
{
MaxJsonLength = MaxJsonLength,
RecursionLimit = RecursionLimit
};
serializer.RegisterConverters(new List<JavaScriptConverter> { new EFJsonConverter(MaxSerializationDepth) });
response.Write(serializer.Serialize(Data));
}
}
You can also detach the object from the context and it will remove the navigation properties so that it can be serialized. For my data repository classes that are used with Json i use something like this.
public DataModel.Page GetPage(Guid idPage, bool detach = false)
{
var results = from p in DataContext.Pages
where p.idPage == idPage
select p;
if (results.Count() == 0)
return null;
else
{
var result = results.First();
if (detach)
DataContext.Detach(result);
return result;
}
}
By default the returned object will have all of the complex/navigation properties, but by setting detach = true it will remove those properties and return the base object only. For a list of objects the implementation looks like this
public List<DataModel.Page> GetPageList(Guid idSite, bool detach = false)
{
var results = from p in DataContext.Pages
where p.idSite == idSite
select p;
if (results.Count() > 0)
{
if (detach)
{
List<DataModel.Page> retValue = new List<DataModel.Page>();
foreach (var result in results)
{
DataContext.Detach(result);
retValue.Add(result);
}
return retValue;
}
else
return results.ToList();
}
else
return new List<DataModel.Page>();
}
I have just successfully tested this code.
It may be that in your case your Message object is in a different assembly? The overriden Property SupportedTypes is returning everything ONLY in its own Assembly so when serialize is called the JavaScriptSerializer defaults to the standard JavaScriptConverter.
You should be able to verify this debugging.
Your error occured due to some "Reference" classes generated by EF for some entities with 1:1 relations and that the JavaScriptSerializer failed to serialize.
I've used a workaround by adding a new condition :
!p.Name.EndsWith("Reference")
The code to get the complex properties looks like this :
var complexProperties = from p in type.GetProperties()
where p.CanWrite &&
p.CanRead &&
!p.Name.EndsWith("Reference") &&
!_builtInTypes.Contains(p.PropertyType) &&
!_processedObjects.Contains(p.GetValue(obj, null)
== null
? 0
: p.GetValue(obj, null).GetHashCode())
select p;
Hope this help you.
I had a similar problem with pushing my view via Ajax to UI components.
I also found and tried to use that code sample you provided. Some problems I had with that code:
SupportedTypes wasn't grabbing the types I needed, so the converter wasn't being called
If the maximum depth is hit, the serialization would be truncated
It threw out any other converters I had on the existing serializer by creating its own new JavaScriptSerializer
Here are the fixes I implemented for those issues:
Reusing the same serializer
I simply reused the existing serializer that is passed into Serialize to solve this problem. This broke the depth hack though.
Truncating on already-visited, rather than on depth
Instead of truncating on depth, I created a HashSet<object> of already seen instances (with a custom IEqualityComparer that checked reference equality). I simply didn't recurse if I found an instance I'd already seen. This is the same detection mechanism built into the JavaScriptSerializer itself, so worked quite well.
The only problem with this solution is that the serialization output isn't very deterministic. The order of truncation is strongly dependent on the order that reflections finds the properties. You could solve this (with a perf hit) by sorting before recursing.
SupportedTypes needed the right types
My JavaScriptConverter couldn't live in the same assembly as my model. If you plan to reuse this converter code, you'll probably run into the same problem.
To solve this I had to pre-traverse the object tree, keeping a HashSet<Type> of already seen types (to avoid my own infinite recursion), and pass that to the JavaScriptConverter before registering it.
Looking back on my solution, I would now use code generation templates to create a list of the entity types. This would be much more foolproof (it uses simple iteration), and have much better perf since it would produce a list at compile time. I'd still pass this to the converter so it could be reused between models.
My final solution
I threw out that code and tried again :)
I simply wrote code to project onto new types ("ViewModel" types - in your case, it would be service contract types) before doing my serialization. The intention of my code was made more explicit, it allowed me to serialize just the data I wanted, and it didn't have the potential of slipping in queries on accident (e.g. serializing my whole DB).
My types were fairly simple, and I didn't need most of them for my view. I might look into AutoMapper to do some of this projection in the future.
Does the ASP.NET MVC 2 Default View Model Binding support binding a multi-value cookie to a custom object? Before I write a custom Value Provider, I would like to be sure that the functionality didn't already exist.
So given an action like:
public ActionResult SomeAction(CustomObject foo)
where CustomObject is something like:
public class CustomObject
{
public string Name { get; set; }
public int Rank { get; set; }
}
and a cookie that is part of the request like:
foo=Name=John&Rank=10
Could I get the Default View Model Binding to map the cookie to the parameter with some clever tweaks to the naming of the cookie or cookie values like posting "foo.Name=John" and "foo.Rank=10" would do?
Well, there's one way to do it would be to implement IModelBinder
public class CustomObjectModelBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
HttpCookie c = controllerContext.HttpContext.Request.Cookies["foo"]
CustomObject value = new CustomObject() {
foo.Name = c.Values["Name"],
foo.Rank = c.Values["Rank"]
}
return CustomObject
}
}
Then just add this to your Application_Start()
ModelBinders.Binders.Add(typeof(CustomObject), new CustomObjectModelBinder());
you can add the cookie object to any action as far as i know and it will attempt to bind it for you
In the end I created something to do this. Based on the work posted by Mehdi Golchin, I created a value provider that allows this kind of binding to happen.
For those interrested, the following are the custom changes I made to Mehdi's work linked above. See the link for full details on implementation. This doesn't support binding to nested objects (e.g., Foo.Cell.X) because I didn't need that level of complexity, but it would be possible to implement with a bit of recursion.
protected virtual bool ContainsPrefix(string prefix)
{
try
{
var parts = prefix.Split(new char[] { '.' }, 2, StringSplitOptions.RemoveEmptyEntries);
switch (parts.Length)
{
case 0:
return false;
case 1:
return this._context.HttpContext.Request.Cookies.AllKeys.Contains(parts[0]);
default:
var cookie = this._context.HttpContext.Request.Cookies[parts[0]];
if (cookie == null) { return false; }
return cookie.Values.AllKeys.Contains(parts[1]);
}
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "Controller Policy");
return false;
}
}
protected virtual ValueProviderResult GetValue(string key)
{
try
{
var parts = key.Split(new char[] { '.' }, 2, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 2) { return null; }
var cookie = this._context.HttpContext.Request.Cookies[parts[0]];
if (cookie == null) { return null; }
var value = cookie.Values[parts[1]];
if (value == null) { return null; }
return new ValueProviderResult(value, value, CultureInfo.CurrentCulture);
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "Controller Policy");
return null;
}
}