Copy an object in universal Windows Application (c#) - c#

In want to add a copy of an object to a List in a universal Windows Application. I tried several ways and found IClonable,BinaryFormatter,IFormatter which are all not available in WinRT applications. Please advice me a suitable way to copy a object to a new object. Find my code below.
foreach (var ctrls in _listctrldata)
{
for (int index = 0; index < ctrls.Controls.Control.Count; )
{
listofcontrolvalues.Add(ctrls.Controls.Control[index]);
index++;
}
SetControlvalues(null, _vcontainer, listofcontrolvalues);
//_vcontainer changes everytime the loop rotates and Should create a copy of _vcontainer here//
VerticalContainer vcont = new VerticalContainer ();
vcont = _vcontainer;
_listcontrols.Add(vcont);
}

I don’t know what the class VerticalContainer is.
If it is a .NET class defined by you self, you can just defined a clone method to create a new object and copy all of the build-in data type fields.
If it is a Windows Runtime class, I’m afraid you cannot easily copy it because there are some internal and private data members you cannot access.
In your code.
VerticalContainer vcont = new VerticalContainer (); vcont = _vcontainer;
You only changed the vcont reference from new created object to the old _vcontainer, this will not work, you need to copy all of fields from _vcontainer to vcont one by one.

Related

Code working in one Addin but doing nothing in another

FilteredElementCollector Lincoln = new FilteredElementCollector(doc);
Lincoln.OfCategory(BuiltInCategory.OST_RvtLinks); Autodesk.Revit.DB.View CurrentView = uiDoc.ActiveView;
ICollection<ElementId> Toggle_On = Lincoln.ToElementIds(); Toggle_On.Clear();
ICollection<ElementId> Toggle_Off = Lincoln.ToElementIds(); Toggle_Off.Clear();
List<Element> Processed = new List<Element>();
List<string> Revit_On = new List<string>(); List<string> Revit_Off = new List<string>();
List<string> Revit_Names = new List<string>();
foreach (Element One_Link in Lincoln)
{
string Revit_Name = One_Link.Name;
if (!Revit_Names.Contains(Revit_Name))//prevents processing same link twice;/but does NOT change anyway!!!!
{
Revit_Names.Add(Revit_Name);
Boolean Is_Hidden = One_Link.IsHidden(CurrentView);//
if (Is_Hidden)
{
Toggle_On.Add(One_Link.Id); Revit_On.Add(One_Link.Name);
}//this apparently does detect what is hidden;
else
{
Toggle_Off.Add(One_Link.Id); Revit_Off.Add(One_Link.Name);
}
}
}
Transaction Do_Toggle = new Transaction(doc, "DoToggle");
Do_Toggle.Start();
if (!Toggle_Off.Count.Equals(0)) { CurrentView.HideElements(Toggle_Off); }
if (!Toggle_On.Count.Equals(0)) { CurrentView.UnhideElements(Toggle_On); }
Do_Toggle.Commit();
Is somehow the transaction failing? Undo is not available, so it doesn't think it has done anything that might need to be undone. Note that this EXACT code is used in another one of my addins (in which multiple optional sub-programs are controlled by picking radio options on a form). But when I am trying to use the code in a standalone version, it fails (without errors). Note also that I've inserted multiple TaskDialog entries to verify that it is indeed finding the RvtLinks that are either visible or hidden in the current view. But it is simply refusing to actually change their visibility. If I run the dialog controlled version, everything toggles, but if I immediately run the standalone, nothing toggles (proving it isn't uneditable pinned links). I have made this option available to users by making "Toggle Links" the default so they can call up my collected program and just hit a carriage return, but I need this to be a true standalone.
You code confuses me. For instance, why do you initialise the Toggle_On and Toggle_Off collections with member values, only to clear them immediately afterwards?
In any case, you use of the transaction does not follow the recommended pattern of enclosing it in a using statement.
Please refer to The Building Coder topic group on Handling Transactions and Transaction Groups for more information on using transactions in the Revit API.

How can I access UD fields in Epicor10 business objects outside of Epicor?

In Epicor 9 it was fairly easy to open Visual Studio and create a project and use the Epicor libraries to access its Business Objects (BOs). So, for instance the Part could be accessed by including the library Epicor.Mfg.Part and newing up a Part object. Then it was easy to get information for a part by calling Part.GetByID("partnum");. This would return a PartDataSet.
It is different but not so difficult to do the same thing in Epicor 10. However, I have noticed that the PartDataSet does not contain any UD fields, even UD fields that have been properly set up in Epicor10.
How can the UD fields be accessed when tapping into Epicor 10 through its business objects?
EDIT:
using Erp.BO;
using Erp.Proxy.BO;
// ...
var binding = Epicor.ServiceModel.StandardBindings.NetTcp.UsernameWindowsChannel();
var cc = new ClientCredentials();
var cred = cc.UserName;
cred.UserName = "****";
cred.Password = "****";
DnsEndpointIdentity ep = new DnsEndpointIdentity("****");
var quoteBo = new QuoteImpl(binding, new Uri("net.tcp://****/Erp/BO/Quote.svc"), cc, ep);
var qds = new QuoteDataSet();
var hed = qds.QuoteHed.NewQuoteHedRow(); // type: QuoteDataSet.QuoteHedRow
// I am not getting UserDefinedColumns as a member of hed.
// This gives me a compiler error.
qds.QuoteHed[0].UserDefinedColumns["Custom_c"] = "value";
It is still fairly easy, the DS returned by the call to the BO will be defined in the contract DLL found on both the client and the server, as this file needs to be distributed to the client machines the UD fields are not added to it. It would cause too many client updates.
This means the Visual Studio cannot look at the contract assembly to determine the field names. Instead, you access the field using the columnName indexer i.e:
class Program
{
static void Main(string[] args)
{
// Hard-coded LogOn method
// Reference: Ice.Core.Session.dll
Ice.Core.Session session = new Ice.Core.Session("manager", "manager", "net.tcp://AppServer/MyCustomerAppserver-99999-10.0.700.2");
// References: Epicor.ServiceModel.dll, Erp.Contracts.BO.ABCCode.dll
var abcCodeBO = Ice.Lib.Framework.WCFServiceSupport.CreateImpl<Erp.Proxy.BO.ABCCodeImpl>(session, Erp.Proxy.BO.ABCCodeImpl.UriPath);
// Call the BO methods
var ds = abcCodeBO.GetByID("A");
var row = ds.ABCCode[0];
System.Console.WriteLine("CountFreq is {0}", row.CountFreq);
System.Console.WriteLine("CustomField_c is {0}", row["CustomField_c"]);
System.Console.ReadKey();
}
}
UserDefinedColumns is defined in Epicor.ServiceModel but is inaccessible as it is an internal property of Ice.IceRow which Erp.Tablesets.QuoteHedRow inherits from.
When you've found the specific record your looking for and have an object containing all of the columns for the record you should see an additional object named UserDefinedColumns. It works like a dictonary that is of type <string, object>. So for instance to set a value out you would do something like this:
myPartDs.Part[0].UserDefinedColumns["MyUdColumn_c"] = "some value";
If you need to pull a value out then you will have to parse it to whatever type it needs to be because they are stored as objects.

How to dispose resources in third-party dll?

I have a console application that needs to create multiple objects of type <T> and T is inside another dll that I don’t own.
When an object of type T is created, it loads a XML in memory, but it never releases it.
So if you create too many objects of type T, an OutOfMemoryException is thrown.
The dll doesn't provide a dispose method for that Object and I can’t interact with the XML directly.
Is there a way to dispose of objects of a certain type that were created by a dll that I don’t own ?
I'm using .NET 4.6
The third-party dll is the dll of Trados Studio, for the people who know the program.
Just set the instance of the 3rd part object to null and create a new instance. The garbage collector will eventually clean up the object that you set to null and you wont get an out of memory exception anymore.
public class Class1
{
private StringBuilder sb = new StringBuilder();
public void loadFile()
{
using(StreamReader sr = new StreamReader("C:\\test.txt")) // Loads large text file.
{
sb.Append(sr.ReadToEnd());
}
}
}
static void Main()
{
fileloader.Class1 inst = new fileloader.Class1(); // Assume this is the instance of your 3rd party object.
do
{
if(inst == null)
{
inst = new fileloader.Class1();
}
for (int i = 0; i < 100; i++)
{
inst.loadFile();
}
inst = null; // allows the object to be GC'ed. Without this i get the OutOfMemoryException
Thread.Sleep(1000);
} while (true);
}
Calling GC.Collect() during runtime might solve the problem.
Ref: https://learn.microsoft.com/en-us/dotnet/api/system.gc.collect?view=net-5.0

Use variable value to check if particular instance exists, if not - create it

I have a list of images like this:
public List<Image> imageList = new List<Image>();
I also have a picture class in order to collect and manipulate data about the images in the list:
public Class Pic {
// properties and stuff
}
And then I have a function that takes an integer as an argument. That integer corresponds to an image in the image list. What I want to do in the function is to check if an instance of the Pic class has been created for that particular image. If not, I want to create it, using the value of the variable passed into the function. The following code obviously doesn't work, but it shows what I want:
public void doStuffWithImage(int picNumber) {
// Check if instance called pic + picNumber exists
if(pic + picNumber.toString() == null) {
// Create an instance
Pic pic + picNumber.toString() = new Pic();
}
}
Suggestions on how to accomplish this?
It seems like you're trying to create individual variables pic1, pic2, etc. you'd be better off using a dictionary:
Dictionary<int, Pic> pics = new Dictionary<int, Pic>();
public void doStuffWithImage(int picNumber) {
// Check if instance called pic + picNumber exists
if(!pics.ContainsKey(picNumber)) {
// Create an instance
pics[picNumber] = new Pic();
}
}
You need to create a "registry" of known Pics. DIctionary<int,Pic> would be good collection to hold this registry. You need to store the registry itself somewhere - perhaps in the "factory" object that registers your pictures.
class PicFactory {
private readonly IDictionary<int,Pic> knownPics = new Dictionary<int,Pic>();
public Pic GetOrCreate(int id) {
Pic res;
if (knownPics.TryGetValue(id, out res)) {
return res;
}
res = new Pic(id.ToString()); // This assumes that Pic(string) exists
knownPics.Add(id, res);
return res;
}
}
This way of implementing a registry may be too primitive for your purposes - for example, if you need your registry to be concurrent, you would need to set up some sort if a locking scheme to protect the knownPics dictionary. The class that accesses pictures would need to create an instance of PicFactory, so that it could access pictures through the GetOrCreate(id) call.
If you are using .net 4.0 or more you can use Lazy type which:
Provides support for lazy initialization.
Which means that the object will be constructed not in the moment of declaration, but when first accessed.
So you can basically declare them like
List<Lazy<Pic>> ....
See Lazy<T> and the Lazy Loading Pattern in general - this is actually a common optimization technique as it defers what can add up to a lot at startup to microdelays during runtime.
Be wary about making sure the microdelays are worth it, and I advise leaving methods about which can force loading.
If you're grabbing from a list, preface with a .Any or .Contains check, and since you're looking up by name like that, consider using a Dictionary instead

Assigning value to class method with parameters in C#

I'm working in an assembly in C# that will replace an old DLL registered as COM. That old DLL allowed COM enabled applications (like VB or Perl) or do things like in the following VBS example:
dim All_Domains
set All_Domains = WScript.CreateObject("MailServerX.LocalDomains")
dim Specific_Domain
set Specific_Domain = All_Domains.Items(3)
dim Domain_Aliases
set Domain_Aliases = WScript.CreateObject("MailServerX.Lines")
Domain_Aliases.Add "one.com"
Domain_Aliases.Add "two.com"
Specific_Domain.Domain_Aliases = Domain_Aliases
All_Domains.Items(3) = Specific_Domain
As you can see in the last line, the property/method LocalDomains.Items is being assigned while passing the parameter "3".
I need to maintain the same interface in the new assembly in order to keep compatibility with all existing scripts that access the old DLL. I have this (very summarized) C# class:
public class LocalDomains
{
private List<LocalDomain> itemsList = new List<LocalDomain>();
# Assume the list is now loaded
public LocalDomain Items(int index)
{
return itemsList[index];
}
}
How can I write the method Items in the class LocalDomains so it can not only return a value from the list, but also receive a value assignment so it can do some processing with itemsList[index] including assigning the new value to it?
By that I mean, keeping the last line of my first code block valid with the new code.
Thanks in advance for any advice!

Categories

Resources