canton7 / Stylet

A very lightweight but powerful ViewModel-First MVVM framework for WPF for .NET Framework and .NET Core, inspired by Caliburn.Micro.
MIT License
996 stars 144 forks source link

Stylet.StyletInvalidViewTypeException #22

Closed Splinterjke closed 7 years ago

Splinterjke commented 7 years ago

Hello. I get this exception says that View doesn't derive from the Window class. But I call .ShowDialog from Conductor.Collection.OneActive derives from Window. Window's ViewModel:

public class MainViewModel : Conductor<IScreen>.Collection.OneActive
    {
        private ErrorBoxViewModel errorBox;
        private readonly IWindowManager windowManager;

        public MainViewModel(IWindowManager windowManager)
        {
            this.windowManager = windowManager;
        }

        public void ShowError(string message)
        {
            if (errorBox != null)
                errorBox.RequestClose();
            errorBox = new ErrorBoxViewModel(message);
            this.windowManager.ShowDialog(errorBox);
        }
    }

In another view model derives from UserControl I call: (Conductor as MainViewModel).ShowError("some string");

ErrorBoxViewModel view model derives from UserControl as well:

public class ErrorBoxViewModel : Screen
    {
        public string Message { get; private set; }

        public ErrorBoxViewModel(string message)
        {
            this.Message = message;
        }

        protected override void OnActivate()
        {
            base.OnActivate();
        }

        protected override void OnDeactivate()
        {
            base.OnDeactivate();
        }

        public void CloseWithSuccess()
        {
            this.RequestClose(true);
        }
    }

Any Idea what's wrong?

canton7 commented 7 years ago

ErrorBoxView doesn't derive from Window.

When you call ShowWindow(someViewModel), the view for someViewModel must inherit from Window (otherwise it can't be shown as a Window).

Splinterjke commented 7 years ago

Well, than how to add custom usercontrol to MainViewModel from Conductor or ActiveItem of Conductor?

canton7 commented 7 years ago

I'm afraid I don't understand the question.

Splinterjke commented 7 years ago

I have a custom usercontrol that I want to display over ActiveItem of Conductor. I'm looking for a way to dynamically create the usercontrol from all of Conductor items? All ActiveItems derives from UserControl.

canton7 commented 7 years ago

What do you mean, "display over ActiveItem of Conductor"? What does "over" mean, exactly?

What do you mean by "dynamically create the usercontrol from all Conductor items"? What UserControl? How do you create a UserControl "dynamically"?

canton7 commented 7 years ago

Also, in your question:

But I call .ShowDialog from Conductor.Collection.OneActive derives from Window.

I don't understand. Conductor does not derive from Window. Views should derive from Window or UserControl. ViewModels should derive from Screen.

ErrorBoxViewModel view model derives from UserControl as well:

No it doesn't? It derives from Screen, as it should.

Splinterjke commented 7 years ago

Okay, forget about dynamic. I have a Conductor (Window) and an ActiveItem (UserControl) as TabItem. I wan't to display another 'custom usercontrol' on Window (w/o deactivating ActiveItem). I guess I can add ths 'custom control'to mainview xaml and change the visibility from ActiveItem, but there is an Message property in ctor of 'customcontrol' that i want to change as well.

canton7 commented 7 years ago

I wan't to display another 'custom usercontrol' on Window

What do you mean, "on Window"? Do you mean display it as a new Window? Do you mean display it in the MainView, but on top of the TabControl? Something else?

Splinterjke commented 7 years ago

Yes, displaying as UserControl but on top of a TabItem.

canton7 commented 7 years ago

So not as a Window at all?

You'll want to put both the TabControl and the overlay in the same Grid, so that the overlay is placed on top of the TabControl. Something like this (untested, might have errors):

<Window x:Class="Your.MainView" ....>
    <Grid>
        <!-- Display both the overlay and the TabControl, with the overlay on top of the TabControl -->
        <TabControl .....>
        </TabControl>
        <ContentControl s:View.Model="{Binding Overlay}"/>
    </Grid>
</Window>

public class MainViewModel : Conductor<IScreen>.Collection.OneActive
{
    private IScreen _overlay;
    public IScreen Overlay
    {
        get { return this._overlay; }
        private set { this.SetAndNotify(ref this._overlay, value); }
    }

    public void ShowOverlay()
    {    
        this.Overlay = new SomeViewModel();
    }
}
Splinterjke commented 7 years ago

Thank you. That's exactly what I want. Issue is resolved.

canton7 commented 7 years ago

Cool!