I have created an instance of a window inside a class, but I am unable to access the instance of the window from my other class directly.
Is there a way to reference the window instance I have already created using a C# method, perhaps searching through the open app windows until it finds the Dashboard window I am trying to access?
Application.Current.Windows gives you all windows, shouldn't be hard to find using its type.
(As Ed pointed out this does not sound like very good design, so you might want to think about how you can get things done without messy window references)
System.Reflection.Assembly assemby = System.Reflection.Assembly.GetExecutingAssembly();
System.Type[] types = assemby.GetTypes();
var varWindows = types.ToList()
.Where(current => current.BaseType == typeof(Window));
MessageBox.Show(varWindows.Count().ToString());
Application.Current.Windows gets us all instantiated windows, but the above code get us all windows.
Related
Currently I am working on a project in C# where I have to implement reflection. I have created a WPF application with a GUI. This GUI contains a
combobox which contains all the classnames that implement a specific interface. The classes with the displayed classnames live in the same solution.
Next to the combobox is a button to refresh the content in the combobox. However, when I run my application, modify a classname that implements the interface, and
click on that refresh button the changes don't show up in the combobox. For example, when I change a classname it should display the new classname in stead of the old one.
I have extracted this part of my project to test it in an empty console application. Here I have an interface that is implemented by the classes
QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm. Next I wrote the following, straight forward code, in my main class.
public static List<string> AlgoList = new List<string>();
static void Main(string[] args) {
RefreshAlgorithms();
Print();
Console.WriteLine("\nChange a classname and press a key \n");
Console.ReadKey();
Print();
Console.WriteLine("\nPress a key to exit the program \n");
Console.ReadKey();
}
private static void RefreshAlgorithms() {
AlgoList.Clear();
Type AlgorithmTypes = typeof(IAlgorithms);
foreach (var type in Assembly.GetCallingAssembly().GetTypes()) {
if (AlgorithmTypes.IsAssignableFrom(type) && (type != AlgorithmTypes)) {
AlgoList.Add(type.Name);
}
}
}
private static void Print() {
Console.WriteLine("Algorithm classes:");
foreach (var Algo in AlgoList) {
Console.WriteLine(Algo);
}
}
When I run the application is see the classnames QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm printed. However if I change the name of the, for example,
QuickSortAlgorithm class to QuickSortAlgorithmmmmm I would expect it to print QuickSortAlgorithmmmmm once I press a key. However this is not the case and the name
QuickSortAlgorithm is still being displayed.
I get the feeling that I overlook something in the concept of reflection. Can this even be done after building the solution? If I understood correctly this concept makes it possible to implement changes on runtime. I know that
it will make my application much slower but I'm really eager to learn more about this concept. If one can explain me what I'm doing wrong I would be very happy.
That unfortunately does not work. When your assembly gets loaded, it will stay loaded as it is, changes only applying when you restart your application.
If you are using .NET Framework you can create a new AppDomain and load your assembly into this AppDomain. When you are done, you can unload the AppDomain and with it your assembly. That you can do multiple times in a running application.
void RefreshAlgorithms()
{
var appDomain = AppDomain.CreateDomain("TempDomain");
appDomain.Load(YourAssembly);
appDomain.DoCallback(Inspect);
AppDomain.Unload(appDomain);
}
void Inspect()
{
// This runs in the new appdomain where you can inspect your classes
}
Be careful though, as working with AppDomains has caveats, such as the need to use remoting when communicating with the AppDomain.
In .NET Core there is no such way available, as far as I know
Once you load a compiled .NET assembly into your application, you can't make further changes to the types in that assembly without restarting and rebuilding the application. If this were allowed, then it could lead to all kinds of weird behavior. For example, imagine if the application had a List<Foo> populated with 3 foos and then Foo.Id were changed from an int to a string. What should happen to that live data?
However, if your application doing the reflecting is different than the assembly being reflected over, it is possible to set things up such that you can watch for changes to that assembly file and re-do your reflection. The key is to abandon System.Reflection (which only works on loaded assemblies) and instead use the Mono.Cecil library.
Cecil reads in the assembly metadata without loading the code into the application, so it works well for the "reflection-only" use-case. Of course, what it can't do is actually invoke the code. The Cecil API contains many similarities to System.Reflection. For example:
var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(Path.Combine(projectDirectory, "bin", "Debug", "Something.dll"));
var controllerTypes = assembly.MainModule.Types.Where(t => t.BaseType?.FullName == "System.Web.Mvc.Controller")
.ToArray();
Another note is that .NET Framework (not .NET Core) contains the notion of AppDomains which can be loaded an unloaded. These act like .NET "sub-processes" within the one process and have rules about what can cross their boundaries. If you really need to both reload code and execute it, then this could be a solution.
Another option could be the Roslyn scripting API, which would work well if you want to dynamically load and execute source code (vs. compiled assemblies).
It looks like you're overlooking one small step: building your code. Once you rename the class to QuickSortAlgorithmmmm, you need to save and build that assembly.
Doing so will recreate the assembly (assuming your application doesn't have an open handle on it). After that, clicking the refresh button should show the new name.
If you can't reload the assembly because it has your GUI code in it too (which is running), you may want to separate out the classes that implement the interface into their own assembly, potentially build that separately, and copy it over into a directory where your app can find it (eg. in a Plugins directory).
Currently I am working on a project in C# where I have to implement reflection. I have created a WPF application with a GUI. This GUI contains a
combobox which contains all the classnames that implement a specific interface. The classes with the displayed classnames live in the same solution.
Next to the combobox is a button to refresh the content in the combobox. However, when I run my application, modify a classname that implements the interface, and
click on that refresh button the changes don't show up in the combobox. For example, when I change a classname it should display the new classname in stead of the old one.
I have extracted this part of my project to test it in an empty console application. Here I have an interface that is implemented by the classes
QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm. Next I wrote the following, straight forward code, in my main class.
public static List<string> AlgoList = new List<string>();
static void Main(string[] args) {
RefreshAlgorithms();
Print();
Console.WriteLine("\nChange a classname and press a key \n");
Console.ReadKey();
Print();
Console.WriteLine("\nPress a key to exit the program \n");
Console.ReadKey();
}
private static void RefreshAlgorithms() {
AlgoList.Clear();
Type AlgorithmTypes = typeof(IAlgorithms);
foreach (var type in Assembly.GetCallingAssembly().GetTypes()) {
if (AlgorithmTypes.IsAssignableFrom(type) && (type != AlgorithmTypes)) {
AlgoList.Add(type.Name);
}
}
}
private static void Print() {
Console.WriteLine("Algorithm classes:");
foreach (var Algo in AlgoList) {
Console.WriteLine(Algo);
}
}
When I run the application is see the classnames QuickSortAlgorithm, DynamicSortAlgorithm and MergeSortAlgorithm printed. However if I change the name of the, for example,
QuickSortAlgorithm class to QuickSortAlgorithmmmmm I would expect it to print QuickSortAlgorithmmmmm once I press a key. However this is not the case and the name
QuickSortAlgorithm is still being displayed.
I get the feeling that I overlook something in the concept of reflection. Can this even be done after building the solution? If I understood correctly this concept makes it possible to implement changes on runtime. I know that
it will make my application much slower but I'm really eager to learn more about this concept. If one can explain me what I'm doing wrong I would be very happy.
That unfortunately does not work. When your assembly gets loaded, it will stay loaded as it is, changes only applying when you restart your application.
If you are using .NET Framework you can create a new AppDomain and load your assembly into this AppDomain. When you are done, you can unload the AppDomain and with it your assembly. That you can do multiple times in a running application.
void RefreshAlgorithms()
{
var appDomain = AppDomain.CreateDomain("TempDomain");
appDomain.Load(YourAssembly);
appDomain.DoCallback(Inspect);
AppDomain.Unload(appDomain);
}
void Inspect()
{
// This runs in the new appdomain where you can inspect your classes
}
Be careful though, as working with AppDomains has caveats, such as the need to use remoting when communicating with the AppDomain.
In .NET Core there is no such way available, as far as I know
Once you load a compiled .NET assembly into your application, you can't make further changes to the types in that assembly without restarting and rebuilding the application. If this were allowed, then it could lead to all kinds of weird behavior. For example, imagine if the application had a List<Foo> populated with 3 foos and then Foo.Id were changed from an int to a string. What should happen to that live data?
However, if your application doing the reflecting is different than the assembly being reflected over, it is possible to set things up such that you can watch for changes to that assembly file and re-do your reflection. The key is to abandon System.Reflection (which only works on loaded assemblies) and instead use the Mono.Cecil library.
Cecil reads in the assembly metadata without loading the code into the application, so it works well for the "reflection-only" use-case. Of course, what it can't do is actually invoke the code. The Cecil API contains many similarities to System.Reflection. For example:
var assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(Path.Combine(projectDirectory, "bin", "Debug", "Something.dll"));
var controllerTypes = assembly.MainModule.Types.Where(t => t.BaseType?.FullName == "System.Web.Mvc.Controller")
.ToArray();
Another note is that .NET Framework (not .NET Core) contains the notion of AppDomains which can be loaded an unloaded. These act like .NET "sub-processes" within the one process and have rules about what can cross their boundaries. If you really need to both reload code and execute it, then this could be a solution.
Another option could be the Roslyn scripting API, which would work well if you want to dynamically load and execute source code (vs. compiled assemblies).
It looks like you're overlooking one small step: building your code. Once you rename the class to QuickSortAlgorithmmmm, you need to save and build that assembly.
Doing so will recreate the assembly (assuming your application doesn't have an open handle on it). After that, clicking the refresh button should show the new name.
If you can't reload the assembly because it has your GUI code in it too (which is running), you may want to separate out the classes that implement the interface into their own assembly, potentially build that separately, and copy it over into a directory where your app can find it (eg. in a Plugins directory).
My C#.NET Windows application dynamically creates a bunch of forms with no name and no borders, this works fine, however I later need to find these forms and set them to be the top most forms. My current logic is to write the myForm.Handle to a string at the time of creation so I can refer to that handle later.
And this is where it fails, when I'm ready to set it to be the top most windows, I do this:
Form myForm = Form.FromHandle(sFormHandle);
if (myForm != null) { myForm.TopMost = true; }
The sFormHandle is a string and it expects a IntPtr, how can I convert it, or do this in some other way?
Many thanks.
The Handle property on a form is an IntPtr.
Why have you stored it as a string?
The solution here is to store the handle as an IntPtr, not a string.
Better than that, if this is all .net windows forms code, why not keep a reference to the form rather than the handle?
Edit: added emphasis. Consensus from community seems to be that references to the forms should be retained and the handles should not be relied upon.
Form fr = (Form)Form.FromHandle(new IntPtr(int.Parse("0")));
and beware of direct refrence to a class...
you better try WeakRefrence because of COM class models
if you use a direct refrence to a class,
the class will not unload till all the refrences are removed!
In my WPF project, I have a dll that contains several WPF UserControls. I would like, in runtime, to be able to check a parameter in the database (already implemented) and according to that parameter (which is a string) to be able to load a specific UserControl to my View.
The UserControl is actually a Canvas, so it basically just places the correct Canvas on the View according to the database entry.
I don't know if I was clear, so please ask me if you didn't understand the question.
Thanks to all helpers!
This concept of loading controls or similar things from a dll at runtime is called Reflection and it is a common way of doing things in certain scenarios. Try to google Reflection in C# you will find a lot of tutorials about it.
Basically you will load the dll at runtime. Then you will look for control. Once you find it you will create its instance and use it. All this will happen at runtime
UserControl myControl = null;
Assembly asm = Assembly.LoadFile(Your dll path);
Type[] tlist = asm.GetTypes();
foreach (Type t in tlist)
{
if(t.Name == "Your class name" )
{
myControl = Activator.CreateInstance(t) as UserControl;
break;
}
}
Also see this question for reference
I need a functionality to get all existing (open) instances of some conrete WPF window. I create those windows programatically in few places in code.
Is there a XAML/WPF solution for that? Something like GetInstancesByType(type)?
You can use the Application.Windows property:
foreach( var window in Application.Current.Windows.OfType<MyType>() )
{
// do stuff
}
As H.B. pointed out, you would need to include System.Linq to get the OfType<T> extension method, but it's not necessary.