简体   繁体   中英

Syntax for opening a new window and passing a parameter to it in C#/WPF

In my C#/WPF app the user can click a button to create a new window to display some graphics. Currently the code in the button handler looks like this . . .

var window = (Window)System.Windows.Application.LoadComponent(new Uri("ShowGraphics.xaml", UriKind.Relative));
window.Owner = this;  // keeps the Window on top of the parent window
window.Title = "Show Graphics";
window.Left = 700;
window.Top = 500;
window.Show();

Now I want to pass a parameter to the constructor of my new window using constructor syntax, something like this (pseudocode . . . )

  Window myWindow = new Window("ParameterValue");
  myWindow.Show();

... but I don't know what the right syntax is for declaring the window with its associated XAML file and other properties and passing a parameter to be read in the constructor of the new window.

PS - and while we're on the subject, how do I return a value back to the main window where the button was?

An Answer to the first part I think this is what Roman Ko was trying to get at when he wrote

"public partial class TestDialog : Window"

but instead of deriving it from the .Net Window class what I needed to do was derive it from my specific wizard-created class (Add > New Item... in VS2010). Because Visual Studio creates both the .cs file, and the .xaml file at that time, the window is associated with its XAML layout through that means. Then to pass the parameter, just do it via the constructor. Thus invoking it . . .

    var window = new TheNameSpace.ShowGraphics("parameter"); 
    window.Owner = this;  // keeps the Window on top of the parent window
    window.Title = "Show Graphics";
    window.Left = 700;
    window.Top = 500;
    window.Show();

... and consuming it in the constructor . . .

public ShowGraphics(String sParam)
{
    InitializeComponent();
    // do stuff
}

An Answer to the PS One way is to override a method of the child window, eg, show()

// Override Show()
public void Show (out string sResult)
{
    Show();  // call the base class method
    sResult = "foo";
    return;
}

... then, in the caller ...

string sReturnVal;
window.Show(out sReturnVal); 

Sorry, I should have been clearer, you cannot create an instance via Application.LoadComponent , StartupUri , or any other XAML based instantiation method available without a parameter-less constructor (it relies on there being one). If you would like to provide a constructor with parameters you can create your window as you did in your second snippet:

var window = new ShowGraphics("parameter-value");
window.Show( );

Try something like this (if you don't want to follow the MVVM pattern):

public partial class MainWindow : Window
{
    public MainWindow() {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e) {
        string inputParam = "some value";
        string outputValue;
        TestDialog dlg = new TestDialog(inputParam);
        if (dlg.ShowDialog() == true)
            outputValue = dlg.OutputParam;
    }
}

public partial class TestDialog : Window
{
    public TestDialog() {
        InitializeComponent();
    }

    public TestDialog(string inputParam) {
        InitializeComponent();
        OutputParam = inputParam.ToUpper(); // for example
    }

    public string OutputParam { get; private set; }

    private void btnOK_Click(object sender, RoutedEventArgs e) {
        DialogResult = true;
    }

}

In 99% of cases, you do not need to explicitly tell WPF where or what the XAML is for a Window control you create. The code to do this is generated for you and executed by the InitializeComponent method defined in the generated code

Here is a cut and paste of the generated code created for the MainWindow in a WPF application.

MainWindow.gics

/// <summary>
/// MainWindow
/// </summary>
public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {

    private bool _contentLoaded;

    /// <summary>
    /// InitializeComponent
    /// </summary>
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
    public void InitializeComponent() {
        if (_contentLoaded) {
            return;
        }
        _contentLoaded = true;
        System.Uri resourceLocater = new System.Uri("/WpfApplication1;component/mainwindow.xaml", System.UriKind.Relative);

        #line 1 "..\..\MainWindow.xaml"
        System.Windows.Application.LoadComponent(this, resourceLocater);

        #line default
        #line hidden
    }

    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
    [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
    void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {
        this._contentLoaded = true;
    }
}

I repeat, you do not write/edit this code, it is generated for you automatically. All you need to do is call the constructor for your custom Window - ShowGraphics - and be sure the constructor you do call invokes the InitializeComponent method.

If you want to take a look at your own generated code, you can find it in the $(ProjectDirectory)/obj/$(Configuration)/ folder.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM