Creating instances of classes in a particular folder - c#

I have a certain folder with a couple of view classes (XAML files).
Right now i am instantiating these by code:
engineRoomView = new EngineRoomView()
{
DataContext = new ProcessViewModel()
};
and then further down:
item = new TabItem();
item.Contents = engineRoomView;
item.Name = "Engine Room";
views.Add(item);
What I want to achieve is some kind of dynamic code for creating one instance of each view in that particular folder without knowing about them during programming.
If a developer adds another xaml file to that folder. Then this gets created in run-time.
Something imaginary like:
Foreach(file in folder)
{
magicInstance = createInstanceFromFile(file);
MainViewModel.addView(magicInstance);
}
Is this possible?

If I understand you correctly, this could be archived with the build in Xaml Reader. The Xaml Reader can read a xaml file and will generate the objects based on the xaml.
Have a look here:
Loading XAML at runtime?

It sounds like you have a "Parent View" that you want to automatically attach a child view for each file in the same folder.
If the classes in each folder have a namespace consistent with the folder structure, this code should allow you to create a list of an instances of each class in the same folder as an example instance that inherit from a base class (could modify easily for interface also).
static class NamespaceHelper
{
public static List<Type> FindTypesInSameNamespaceAs(object instance)
{
string ns = instance.GetType().Namespace;
Type instanceType = instance.GetType();
List<Type> results = instance.GetType().Assembly.GetTypes().Where(tt => tt.Namespace == ns &&
tt != instanceType).ToList();
return results;
}
public static List<T> InstantiateTypesInSameNamespaceAs<T>(object instance)
{
List<T> instances = new List<T>();
foreach (Type t in FindTypesInSameNamespaceAs(instance))
{
if (t.IsSubclassOf(typeof(T)))
{
T i =(T) Activator.CreateInstance(t);
instances.Add(i);
}
}
return instances;
}
}
Just call NamespaceHelper.InstantiateTypesInSameNamespaceAs<YourBaseViewType>(instanceOfParentViewInSameFolder), loop through the results, and add them to your Parent.
Foreach(ViewBase v in NamespaceHelper.InstantiateTypesInSameNamespaceAs<ViewBase>(this))
{
MainViewModel.addView(v);
}

Related

Access hidden dynamic Property in COM-object with C#

I need to access a specific property inside a COM object (the iTunes COM Library). You can access this property with the dynamic view of the Visual Studio debugger.
I tried to get this property using Reflection but I don't get any private properties or fields back.
I can access all the Properties that I also see in the debugger using this line:
new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(myObject).Items
However, I would rather not use this call because I believe an easier solution exists.
If you have iTunes installed this would be a simple example of what I'm trying to achieve:
iTunesAppClass app;
if (Process.GetProcessesByName("iTunes").Any())
{
app = new iTunesAppClass();
}
else
{
return;
}
foreach (IITPlaylist playlist in app.LibrarySource.Playlists)
{
// This does not work. There is no "Parent".
//var parent = playlist.Parent;
Type playListType = playlist.GetType();
// both contain 0 results
var fields = playListType.GetFields(BindingFlags.NonPublic);
var properties = playListType.GetFields(BindingFlags.NonPublic);
// works but only during runtime
//var parent2 = new Microsoft.CSharp.RuntimeBinder.DynamicMetaObjectProviderDebugView(playlist).Items[4];
}

Remove metadata from Excel file using C#?

I'm currently using C# to set the custom attributes of multiple excel files. I'm using an imported library from Microsoft known as DSOFile to write to the CustomProperties property. One issue that I'm running into is whenever the code attempts to write to an excel file that already has custom properties written to it, such as the Company and Year, a COMException exception is thrown to indicate the custom properties of the file already has a field with that name. Exact Message: "An item by that name already exists in the collection". I would like to be able to delete that item in the collection so that I can rewrite to the file. For example, if I accidentally added the wrong year to the year attribute in the file, I would like the ability to clear that field and write a new value to it. I was unable to find a method in the DSOFile class that removes metadata. Is there anyway to "programmatically" clear metadata from a file without doing it through the file properties window?
Sample Code:
DSOFILE.OleDocumentProperties dso = new DSOFile.OleDocumentProperties();
dso.Open(#"c\temp\test.xls", false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
//add metadata
dso.CustomProperties.Add("Company", "Sony");
dso.Save();
dso.Close(false);
If you want to change the default properties used by Office like Company or Author, you can just update them via the SummaryProperties object:
OleDocumentProperties dso = new DSOFile.OleDocumentProperties();
dso.Open(#"c:\temp\test.xls", false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
//Update Company
dso.SummaryProperties.Company = "Hello World!";
dso.Save();
dso.Close(false);
Note, that you cannot change the default properties of documents that you can access via the SummaryProperties object via the CustomProperties object in dso. The CustomProperties are meant for additional properties used by the user, not the ones already introduced by Microsoft Office.
In order to change the custom properties, you have to be aware that CustomProperties is a collection that you can iterate over via foreach. So you can use the following two methods:
private static void DeleteProperty(CustomProperties properties, string propertyName)
{
foreach(CustomProperty property in properties)
{
if (string.Equals(property.Name, propertyName, StringComparison.InvariantCultureIgnoreCase))
{
property.Remove();
break;
}
}
}
private static void UpdateProperty(CustomProperties properties, string propertyName, string newValue)
{
bool propertyFound = false;
foreach (CustomProperty property in properties)
{
if (string.Equals(property.Name, propertyName, StringComparison.InvariantCultureIgnoreCase))
{
// Property found, change it
property.set_Value(newValue);
propertyFound = true;
break;
}
}
if(!propertyFound)
{
// The property with the given name was not found, so we have to add it
properties.Add(propertyName, newValue);
}
}
Here is an example on how to use UpdateProperty:
static void Main(string[] args)
{
OleDocumentProperties dso = new DSOFile.OleDocumentProperties();
dso.Open(#"c:\temp\test.xls", false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
UpdateProperty(dso.CustomProperties, "Year", "2017");
dso.Save();
dso.Close(false);
}

How To Use Entity Data Model In Class Library

I was successfully able to save data to the Sql Server database, using an Entity Data Model, as follows:
MEDIANEntities db = new MEDIANEntities();
tblCountry objTable = new tblCountry();
objTable.Name= txtName.Text.Trim();
objTable.CreatedDate = System.DateTime.Now;
db.AddTotblCountries(objTable);
db.SaveChanges();
The idea now, is to use the EDM in a class library, so that it can be consumed in other projects (a tier architecture basically). I have created a Class library - 'MedianContext' and then created a new edmx file inside it - 'MedianModel'. And then another class library - 'MedianDAL'. Added the reference of MedianContext to it.
Unable to access properties of objcontext and tb. How can I proceed further.
If it helps, when adding the reference to MedianDAL, the MediaContext.dll was inside the debug folder instead of Release folder, as seen in many examples.
Have you tried it with Linq2Entities?
e.g.:
try
{
using (var medianEntities = new MedianModel.MEDIANEntities())
{
//Do any LinqToEntity-Expressions
}
}
catch(Exception)
{
//ErrorHandling
}
That works for me.
I also have my .edmx files in a different project and just added a reference to this.
Edit:
Of course you have to put this code into a method-body.
Here is a simple example:
public List<Map> GetAllMaps()
{
var Maps = new System.Collections.Generic.List<Map>();
try
{
using (var mapEntities = new Model.MapEntities())
{
var MyMaps= (from M in mapEntities.Maps
orderby M.Description
select M.MapID, M.Description);
foreach (var Map in MyMaps)
{
Maps.Add(Map);
}
}
return Maps;
}
catch (System.Exception Exc)
{
Log.Err(string.Format("Error: {0}", Exc));
throw new System.Exception(Exc.ToString());
}
}
Probably because you are trying to access the properties while in the context of the class ? Create constructor for this class and access the properties from there:
public Test
{
tb....
}

Duplicating content on save for a multilingual umbraco site

[Edit] I have actually been allowed to use the doc names, which makes it much easier but I still think it would be interesting to find out if it is possible.
I have to set a trigger to duplicate content to different branches on the content tree as the site will be in several languages. I have been told that I cannot access the documents by name(as they may change) and I shouldn't use node IDs either(not that I would know how to, after a while it would become difficult to follow the structure).
How can I traverse the tree to insert the new document in the relevant sub branches in the other languages? Is there a way?
You can use the Document.AfterPublish event to catch the specific document object after it's been published. I would use this event handler to check the node type alias is one that you want copied, then you can call Document.MakeNew and pass the node ID of the new location.
This means you don't have to use a specific node ID or document name to trap an event.
Example:
using umbraco.cms.businesslogic.web;
using umbraco.cms.businesslogic;
using umbraco.BusinessLogic;
namespace MyWebsite {
public class MyApp : ApplicationBase {
public MyApp()
: base() {
Document.AfterPublish += new Document.PublishEventHandler(Document_AfterPublish);
}
void Document_AfterPublish(Document sender, PublishEventArgs e) {
if (sender.ContentType.Alias == "DoctypeAliasOfDocumentYouWantToCopy") {
int parentId = 0; // Change to the ID of where you want to create this document as a child.
Document d = Document.MakeNew("Name of new document", DocumentType.GetByAlias(sender.ContentType.Alias), User.GetUser(1), parentId)
foreach (var prop in sender.GenericProperties) {
d.getProperty(prop.PropertyType.Alias).Value = sender.getProperty(prop.PropertyType.Alias).Value;
}
d.Save();
d.Publish(User.GetUser(1));
}
}
}
}

Programmatically rendering a web UserControl

I have a load of UserControl objects (ascx files) in their own little project. I then reference this project in two projects: The REST API (which is a class library project) and the main website.
I'm sure this would be easy in the website, simply use Controls.Add in any Panel or ASP.NET control would work.
However, what about the API? Is there any way I can render the HTML of this control, simply by knowing the type of the control? The RenderControl method doesn't write any HTML to the writer as the control's life cycle hasn't even started.
Please bare in mind that I don't have the controls in the web project, so I don't have a virtual path to the ascx file. So the LoadControl method won't work here.
All the controls actually derive from the same base control. Is there anything I can do from within this base class that will allow me to load the control from a completely new instance?
This is what I have done recently, works well, but understand postbacks will not work if you use it inside your ASP.NET app.
[WebMethod]
public static string GetMyUserControlHtml()
{
return RenderUserControl("Com.YourNameSpace.UI", "YourControlName");
}
public static string RenderUserControl(string assembly,
string controlName)
{
FormlessPage pageHolder =
new FormlessPage() { AppRelativeTemplateSourceDirectory = HttpRuntime.AppDomainAppVirtualPath }; //allow for "~/" paths to resolve
dynamic control = null;
//assembly = "Com.YourNameSpace.UI"; //example
//controlName = "YourCustomControl"
string fullyQaulifiedAssemblyPath = string.Format("{0}.{1},{0}", assembly, controlName);
Type type = Type.GetType(fullyQaulifiedAssemblyPath);
if (type != null)
{
control = pageHolder.LoadControl(type, null);
control.Bla1 = "test"; //bypass compile time checks on property setters if needed
control.Blas2 = true;
}
pageHolder.Controls.Add(control);
StringWriter output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return output.ToString();
}
public class FormlessPage : Page
{
public override void VerifyRenderingInServerForm(Control control)
{
}
}

Categories