简体   繁体   中英

Having Trouble Setting Window's Owner in Parent's Constructor

Is there anything wrong in WPF with setting the Owner property of a window to its parent in that parent's constructor? There shouldn't be, right? So why am I getting an XamlParseException from the following code?

public partial class MainView : Window
{
    private readonly OwnedWindow owned;

    public MainView()
    {
        InitializeComponent();
        owned = new OwnedWindow();

        owned.DataContext = DataContext;

        var window = GetWindow(this);
        owned.Owner = this;  //Setting to window causes the same error

        ...
    }

I should clarify that removing the owned.Owner = this; also removes the runtime error.

The details of the exception:

XamlParseException was unhandled

The invocation of the constructor on type '...MainView' that matches the specified binding constraints threw an exception.

Actually , I looked at the Inner Exception, and it says:

Cannot set Owner property to a Window that has not been shown previously.

So I'm looking into that now.

The problem is that because WPF only creates the native window the first time a WPF Window is shown, you can't be setting a not-yet-shown Window as an Owner (since that establishes a native window "owner -> owned" relationship, but the native handle doesn't yet exist.)

You can handle the StateChanged event on the owner window, ensure that the new state is "shown", and then set the owned window's Owner at that point. Alternatively, you could create and show the owned window at that point.

I ended up subscribing to Window.Activated , not Window.StateChanged . Be sure to unsubscribe to it in the handler, as advised in the comments.

    private void OnActivated(object sender, EventArgs eventArgs)
    {
        owned.Owner = this;
        Activated -= OnActivated;
    }

I accepted dlev's answer because it led me directly to finding the answer, even if his didn't work for my exact situation.

You need the WPF equivalent of HandleCreated event, which is SourceInitialized . This should work:

public OwnerWindow()
{
    InitializeComponent();

    SourceInitialized += (s, a) =>
        {
            var owned = new OwnedWindow();
            owned.Owner = this;
        };
}

Note that you don't have to Show either OwnerWindow or OwnedWindow for this to work.

如果由于某种原因需要先于正常创建的句柄,或者无法显示窗口,只需添加另一个选项:

new WindowInteropHelper(myWindow).EnsureHandle();

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