How to open a child window without needing to update app.axaml? #19115
-
public interface IWindowManager
{
public void ShowWindow (ViewModelBase viewModel);
public void CloseWindow (ViewModelBase viewModel);
public void ToggleWindow (ViewModelBase viewModel);
public void ActivateWindow(ViewModelBase viewModel);
public void ShowDialog (ViewModelBase viewModel);
}
public interface IWindowFactory
{
Window CreateWindow(ViewModelBase viewModel);
}
public abstract partial class ViewModelBase : ObservableObject
{
} I am trying to do mvvm child window's. |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 4 replies
-
In your concrete implementation, one will have a constructor to take the other. Likely
You can create a mapping in your View layer. Cleanup to prevent leaks may be difficult. You can also use DI scoping to create a scope per window and register certain services as scoped. When the service is injected, it will be associated with the right window behind-the-scenes as long as the ViewModel doesn't get transferred across windows. I found that approach to be very challenging, but I also had several other wiring concerns. It does work very well though.
It's hard to resolve which
When you setup of your IoC container: before
You'll only have one
Without passing the
You can try a third-party library like https://github.com/mysteryx93/HanumanInstitute.MvvmDialogs. https://github.com/irihitech/Ursa.Avalonia has a decent-looking in-app / external dialog system. I've written a few and it's painful every time for me. The wiring can get really tricky. The current system I wrote is the only one that really handles external Windows well. As in, if I open a dialog with multiple windows open, it will open above the correct Window. If that's not a big issue, just grab the app lifetime and then the |
Beta Was this translation helpful? Give feedback.
-
If you are following MVVM strictly, you don't. View Models are not allowed to directly interact (or even be aware of) with the view. Instead you can use something like a view interaction/raising an event to the view. I explained this sort of thing a long time ago here: #13484 (reply in thread)
I assume you are talking about a template? They need to be defined somewhere. You can either do that with a view locator or by manually specifying the template somewhere. |
Beta Was this translation helpful? Give feedback.
-
So what about something like this instead of a window manager? public partial class WindowHost : UserControl
{
private Window? _window;
public WindowHost()
{
Loaded += (sender, args) =>
{
if (_window == null && DataContext is WindowHostViewModel context)
{
_window = new() {
Content = Content,
IsVisible = false
};
_window.DataContext = context;
_window.Bind(Window.IsVisibleProperty, new Binding()
{
Source = context,
Path = nameof(WindowHostViewModel.Visible)
});
_window.Activate();
}
};
}
} public partial class WindowHostViewModel : ViewModelBase, IWindowHost
{
[ObservableProperty] private bool _visible;
public void Toggle()
{
Visible = !Visible;
}
public void Show()
{
Visible = true;
}
public void Hide()
{
Visible = false;
}
}
public interface IWindowHost
{
public void Toggle();
public void Show();
public void Hide();
} And then putting this into the main view... <local:WindowHost>
<local:CheckBoxListView DataContext ="{Binding Layers}"/>
</local:WindowHost> The only issue with this approach is views can only have one content item. |
Beta Was this translation helpful? Give feedback.
-
@thevortexcloud Is it possible to register control content in the view without specifically putting it in the content/layout section of the axaml? Like maybe putting it as a resource instead? <Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Quest.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Quest.Views.MainView"
x:DataType="vm:MainViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="Quest">
<Window.Resources>
<WindowHost Title="My Window" Width="320" Height="240">
<!-- Content here -->
</WindowHost>
</Window.Resources> public class WindowHost : ???
{
private Window? _window;
// Bind or set these in parent window
public string Title { get; set; } = "New Window";
public uint Width { get; set; } = 600;
public uint Height { get; set; } = 480;
// Bind viewmodel isvisble to these
private void ShowWindow()
{
if (_window == null)
{
_window = new Window();
_window.Content = ???;
_window.Title = Title;
_window.Width = Width;
_window.Height = Height;
}
_window.Show();
}
private void HideWindow()
{
_window?.Hide();
}
}
public partial class WindowHostModel : BaseViewModel
{
[ObservableProperty] private bool _isVisible = false;
[RelayCommand]
private void Show()
{
IsVisible = true;
}
[RelayCommand]
private void Hide()
{
IsVisible = false;
}
[RelayCommand]
private void Toggle()
{
IsVisible = !IsVisible;
}
} |
Beta Was this translation helpful? Give feedback.
1. How do I connect IWindowManager to IWindowFactory?
In your concrete implementation, one will have a constructor to take the other. Likely
public WindowManager(IWindowFactory windowFactory)
.2. How do I get the view from the view model?
You can create a mapping in your View layer. Cleanup to prevent leaks may be difficult.
You can also use DI scoping to create a scope per window and register certain services as scoped. When the service is injected, it will be associated with the right window behind-the-scenes as long as the ViewModel doesn't get transferred across windows. I found that approach to be very challenging, but I also had several other wiring concerns. It does work very well …