WPF Open a Window by String Name
-
13 เมษายน 2555 23:39
If I only have the name of a window in string format. How can I open that window?
I have tried to use ...
Window win = System.Windows.Application.Current.TryFindResource(myString) as Window;
but I keep getting a null reference.
To be specific I have a control created in a control library. I've referenced that in my project. So it is the control trying to access the window within the application it has been placed in. (Hope that made sense.)
Any help would be greatly appreciated.
~Christine
(Loving the spell check btw. I'm such a horrible typer/speller.)
Edit To Show All the Xaml/Code...
UserControl Xaml...
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfControlLibrary1.myUserControl" x:Name="UserControl" d:DesignWidth="640" d:DesignHeight="480" Width="100" Height="100"> <Grid x:Name="LayoutRoot"> <Grid.Background> <RadialGradientBrush> <GradientStop Color="Black" Offset="1"/> <GradientStop Color="White"/> </RadialGradientBrush> </Grid.Background> <Button Content="New Window" Margin="0" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click"/> </Grid> </UserControl>
UserControl Code-Behind...
using System.ComponentModel; using System.Windows; using System.Windows.Controls; namespace WpfControlLibrary1 { public partial class myUserControl : UserControl { [Category("My Button Settings")] public string WindowName { get { return (string)GetValue(WindowNameProperty); } set { SetValue(WindowNameProperty, value); }} public static readonly DependencyProperty WindowNameProperty = DependencyProperty.Register("WindowName", typeof(string), typeof(myUserControl), null); public myUserControl() { this.InitializeComponent(); } private void Button_Click(object sender, System.Windows.RoutedEventArgs e) { Window win = new Window(); win = Application.Current.TryFindResource(WindowName) as Window; win.Show(); } } }WPF Project I am using the control in...
MainPage...
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfControlLibrary1="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1.MainWindow" x:Name="Window" Title="MainWindow" Width="200" Height="200"> <Grid x:Name="LayoutRoot"> <WpfControlLibrary1:myUserControl HorizontalAlignment="Center" VerticalAlignment="Center" d:LayoutOverrides="Width, Height" WindowName="myWindow"/> </Grid> </Window>
And the second window in that application...
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="WpfApplication1.Window1" x:Name="myWindow" Title="Window1" Width="200" Height="200"> <Grid x:Name="LayoutRoot"> <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="My Second Window" VerticalAlignment="Center"/> </Grid> </Window>
- แก้ไขโดย Christine L. _ 14 เมษายน 2555 1:05
ตอบทั้งหมด
-
14 เมษายน 2555 13:31
To create an object (a window is an object) you must use Reflection.
The steps to create a window are: (examples will be in VB.NET)
1. Get a reference to the assembly that the window is defined in.
Private theAssembly As Assembly = Assembly.GetAssembly(Me.GetType())
2. Now that you have reference to the assembly (and that could be another DLL or your executing EXE)
Dim inter As ITestWindow = theAssembly.CreateInstance("theFullWindowName")theFullWindowName contains both the namespace and window name. Like WPFTestPlatform.TestFolderDialog.
If you have an assembly and would like to see the types you can create use the following:
Dim theTypes As List(Of Type) = theAssembly.GetExportedTypes().ToList
NOTE: the window must have an parameterless constructor for this to work.
Hope this helps,
Lloyd Sheen
Lloyd Sheen
-
14 เมษายน 2555 14:21
SQLGuy shows the "Reflection" methodology.
Note your first attempt will work : Window win = System.Windows.Application.Current.TryFindResource(myString) as Window; if you add the window as a resource under the resources section of any window or control, or you add a reference in App.XAML under the ResourceDictionary section.
xmlns:my="MyAssembley.Folderlocation" <Window.Resources> <my:Win x:key="TheWindow"/> </Window.Resources>
The example above shows how to do it from any window's/control's resources definitionJP Cowboy Coders Unite!
-
14 เมษายน 2555 23:40
I temporarily solved my problem by calling a Window instead of a string. But I would much prefer to be able to call a window by string.
@sqlguy... thank you for responding unfortunately I am totally lost when it comes to VB. I tried once to use it, but I could never figure out who that val guy was. :D I was unfortunately injured today so I've been locked away from my computers with the coding and didn't get to finish trying to make it work. I thought I had it converted correctly, but again got a null refrence. So I tried that list of types as you suggested and it seemed to return all sorts of dll files. So I changed them to type.name.tostring() or something like that, I got a list of controls, properties, etc.. So I don't think I was converting to c# correctly but was pulled away before I could finish. I'll attempt it again when I can return to work.
@Javaman... thank you also for responding and for one of my personal projects your solution will work. However, let's assume my control and my application have no knowledge of each other? Is there a way to tell the application "Hey I'm here and I want to see you're window, so list it in your library for me."? And while my knowledge is very limited, I use C#. So if there is a way to dynamically add the refrence to the library, that would be perfect.
Thanks for your help!
~Christine
-
16 เมษายน 2555 15:50
You ask a very good question which of course has a zillion solutions.
Prism uses Inversion of Control patterns to do this, but the learning curve was a little bit rich for me.
MEF is another framework that allows this to be done. Reed Copsey has written quite a bit about this very topic of "string-only" using MEF.
Finally you may be able to add it as a resource to the application level Resource Dictionary using the Add method. Think in terms of string/value pairs when using ResourceDictionaries. A perfect model for string entries that point to something else.
Finally Reactive Extensions would allow any new Class to "Publish" it's existence using a PUSH based notification method. Learning curve is a bit high, but worth it.
Events of course, are the most familar Visitor pattern implementation as well. The Event listener, would be the MainWindow/Shell (Sink), anyone wanting to notify just sends an Event (Source). The event and delegate themselves can be declared at the application level but usually every application has a MainWindow or Shell. So in my opinion, for GUI, everyone should be able to send an event to the Mainwindow, Shell and or one of it's regions. Is it a strict violation of close coupling? Probably, but how strict should we become? If we program by naming convention, then we set up a universal situation, yet, even if we don't there could be other ways as well. Mr. Eisenberg "one of my favorite MVVM toolkit providers" does just this thing in his excellent MVVM toolkit named Caliburn
You can also use the Singleton pattern and the GetInstance method to get instances of something. To find them generically would be the key.
JP Cowboy Coders Unite!
- ทำเครื่องหมายเป็นคำตอบโดย Annabella LuoModerator 26 เมษายน 2555 5:53
-
16 เมษายน 2555 17:01
Christine,
I have created a C# project for you to illustrate the method I outlined before. The project will read the assembly created by the project, display buttons in a panel which can be clicked to open windows (by string). I have included a second part which is how to identify only the windows you want to react this way, by using a blank Interface.
https://skydrive.live.com/redir.aspx?cid=763348c6ba3a38e3&resid=763348C6BA3A38E3!203&parid=763348C6BA3A38E3!201&authkey=!APKCbHr2sRvg_1o
Hope this helps
Lloyd Sheen
Lloyd Sheen
- ทำเครื่องหมายเป็นคำตอบโดย Annabella LuoModerator 26 เมษายน 2555 5:53
-
27 เมษายน 2555 14:54
Thank you Javaman and Sqlguy for trying to help me. I've been away and not able to try your solutions, but Annabella seems to think they will work so thanks a bunch! I'll dig into them this weekend.
~Christine
-
27 เมษายน 2555 17:57
@Javaman... thank you also for responding and for one of my personal projects your solution will work. However, let's assume my control and my application have no knowledge of each other? Is there a way to tell the application "Hey I'm here and I want to see you're window, so list it in your library for me."? And while my knowledge is very limited, I use C#. So if there is a way to dynamically add the refrence to the library, that would be perfect.
Thanks for your help!
~Christine
This is exactly what MEF does, it allows you to build extendable applications. The idea is that Any dis-similar assembly can add itself to the other main assembly using MEF. Prior to MEF there was quite a bit written on this topic (Extensibility) and the method was to implement known interfaces to get it done. This idea was similar to MEF, but worked like this: At run time of the Main application it would use reflection to get the executing assembly and to search a predetermined folder named appropriatly (like ADDON) for any dlls droped into that folder. Then it would through reflection create an instance of any dll that implemented the said interface. The main application then knew how to handle the new Object just added at run time to the application! Pretty slick but took a bit of work. MEF is the current way to do this.JP Cowboy Coders Unite!
-
27 เมษายน 2555 23:25
I actually changed my thinking of how to go about this. I decided it was really none of the controls business what I wanted it to do when a side was clicked, so I created some "ButtonClick" events for each of the 4 sides of my control... (I was converting my BoxButtons into a control I could use for my WPF applications.)
public event EventHandler ButtonClick; private void onButtonClick() { if (ButtonClick != null) { ButtonClick(this, EventArgs.Empty); }} protected void ButtonClicked(object sender, EventArgs e) { onButtonClick(); } private void UserControl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { onButtonClick(); }But y'all have taught me a ton and I am forever grateful for your time.
~Christine