Как открывать текущее окно в новом окне?

100
15 июня 2021, 14:20

У меня есть приложение и я хочу получить копию текущего окна в другом окне, как мне это сделать. Использую паттерн mvvm light. Можете посоветовать правильный путь?

Это мой xaml файл который надо отобразить в новом окне.

<UserControl>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <hx:Viewport3DX
    </hx:Viewport3DX>
</Grid>
</UserControl>

Это VM этого xaml файла

private async void openNewView()
    {
        Application app = new Application();
        Plot3d plot3D = new Plot3d(); //xaml файл который надо вывести
        Window window1 = Application.Current.Windows.OfType<Window>().FirstOrDefault();
        await app.MainWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate
        {
            Frame frame = new Frame();
            frame.Navigate(plot3D);
            window1.Show();
        });
    }

Пытался делать как в этом примере https://docs.microsoft.com/en-us/windows/uwp/design/layout/application-view, и еще avalondock оказывается не поддерживает Viewport3DX

Answer 1

OK, давайте сделаем это.

Добавьте в проект новый Custom Control (именно custom и именно из ветки WPF, не промахнитесь), я обозвал его EjectControl,

Зададим для него стандартный шаблон в Themes/Generic.xaml:

<Style TargetType="{x:Type local:EjectControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:EjectControl}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
                        <Button x:Name="PART_EjectButton" Content="Eject"
                                HorizontalAlignment="Right" Margin="0,0,0,5"/>
                        <ContentPresenter Grid.Row="1"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Шаблон очень простой: ContentPresenter для отображения контента и кнопка для "выбрасывания" этого контента в дочернее окно.

Теперь код контрола:

[TemplatePart(Name = PartEjectButton, Type = typeof(Button))]
public class EjectControl : ContentControl
{
    static EjectControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(EjectControl),
            new FrameworkPropertyMetadata(typeof(EjectControl)));
    }
    private const string PartEjectButton = "PART_EjectButton";
    private Button EjectButton;
    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        if (EjectButton != null)
        {
            EjectButton.Click -= OnEjectButtonClick;
        }
        EjectButton = GetTemplateChild(PartEjectButton) as Button;
        if (EjectButton != null)
        {
            EjectButton.Click += OnEjectButtonClick;
        }
    }
    private void OnEjectButtonClick(object sender, RoutedEventArgs e)
    {
        var window = new Window
        {
            ContentTemplate = ContentTemplate,
            Content = DataContext,
            Owner = Window.GetWindow(this),
            Height = ActualHeight,
            Width = ActualWidth,
            WindowStartupLocation = WindowStartupLocation.CenterOwner
        };
        window.ShowDialog();
    }
}

Вроде тоже все предельно просто. Контрол готов.

Протестируем его, я добавил в главное окно следующий код:

<local:EjectControl Content="{Binding DataContext, RelativeSource={RelativeSource Self}}">
    <local:EjectControl.ContentTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <TextBlock Text="Prop 1:"/>
                <TextBox Grid.Column="1" Text="{Binding Prop1}"/>
                <TextBlock Grid.Row="1" Text="Prop 2:"/>
                <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Prop2}"/>
            </Grid>
        </DataTemplate>
    </local:EjectControl.ContentTemplate>
</local:EjectControl>

Обратите внимание, чтобы все работало правильно, мы должны устанавливать именно шаблон контента, а не сам контент, т. к. шаблон можно свободно копировать и переиспользовать, а контент, помещенный в визуальное дерево переместить в другое дерево не так просто.

Смотрим что получилось:

Вроде бы работает как вы хотели. Наведение красоты оставляю вам.

READ ALSO
Как убрать повторяющиеся значения в запросе?

Как убрать повторяющиеся значения в запросе?

Всем привет, есть код выборки таблиц

193
Unity c# Не удается преобразовать &ldquo;char&rdquo; в &ldquo;char*&rdquo;

Unity c# Не удается преобразовать “char” в “char*”

Нужно взять первую букву имени объекта

82
Как делать полупрозрачный круг около персонажа, когда тот за объектом(стеной к примеру)

Как делать полупрозрачный круг около персонажа, когда тот за объектом(стеной к примеру)

Можно пустить луч от камеры к персонажу и изменять прозрачность объекта, но при таком способе полупрозрачным делается весь объект, как делать...

75
Ошибка в алгоритме Карацубы для Длинной арифметики

Ошибка в алгоритме Карацубы для Длинной арифметики

Пытаюсь сделать библиотеку с длинными числамиИ возникла проблема, которую я пытался уже неделю исправить

101