简体   繁体   中英

How to create layout in WPF where the middle is a placeholder for other windows?

I am trying to create a app with WPF. I would like to create a main window with large button on the top and on the right. When a button is clicked, I would like to render the corresponding window in the middle Like this. 在此处输入图片说明

I am not sure how to make that look and how to assign the layout as a parent where other windows open inside of it.

Here is my failed XAML attempt

```

    <Menu DockPanel.Dock="Top" Height="50" VerticalAlignment="Center">
        <MenuItem Header="File" Height="50" VerticalAlignment="Center"></MenuItem>
        <MenuItem Header="View"></MenuItem>
    </Menu>

    <Menu DockPanel.Dock="Right" Width="50"></Menu>


</DockPanel>

```

Is it possible to achieve a layout with a place holder for other windows in WPF? How can I do such a thing?

I would recommend using UserControls for your child windows. DataTemplate binding would be the ideal setup for this.

The content control will bind to the CurrentView property. The CurrentView content is resolved by the associated DataTemplate. This will render the selected view in the placeholder depending on which data type instance CurrentView is referencing.

MainWindow.xaml.cs

public MainWindow()
{
    this.DataContext = new MainWindowViewModel();
}

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{ 
    ... Implement INotifyPropertyChanged
}

FirstViewModel.cs

public class FirstViewModel : ViewModel 
{ 
    ... 
}

SecondViewModel.cs

public class SecondViewModel : ViewModel 
{ 
    ... 
}

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModel
{
    public ICommand Button1Command { get; }
    public ICommand Button2Command { get; }

    private ViewModel _currentView { get; }

    protected ViewModel FirstView { get; }
    protected ViewModel SecondView { get; }

    public ViewModel CurrentView
    {
        get { return _currentView; }
        set { _currentView = value; NotifyPropertyChanged(); }
    }

    public MainWindowViewModel() 
    {
        this.FirstView = new FirstViewModel();
        this.SecondView= new SecondViewModel();
        this.Button1Command = new RelayCommand(OnButton1);
        this.Button2Command = new RelayCommand(OnButton2);
    }

    public void OnButton1()
    {
        this.CurrentView = this.FirstView;
    }

    public void OnButton2()
    {
        this.CurrentView = this.SecondView;
    }
}

MainWindow.xaml

<Window.Resources>
    <ResourceDictionary>
        <DataTemplate DataType="{x:Type vm:FirstViewModel}">
            <Label>Menu View</Label>
            <!-- Or you could embed a User Control -->
            <views:MenuView />
        </DataTemplate>

        <DataTemplate DataType="{x:Type vm:SecondViewModel}">
            <Label>Other View</Label>
            <!-- Or you could embed a User Control -->
            <views:OtherView />
        </DataTemplate>
    </ResourceDictionary>
</Window.Resources>

<DockPanel LastChildFill="True">

    <StackPanel DockPanel.Dock="Top">
        <Button Command="{Binding Button1Command}">Menu Button</Button>
        <Button Command="{Binding Button2Command}">Other Button</Button>
    </StackPanel>

    <ContentControl Content="{Binding CurrentView}"></ContentControl>
</DockPanel>

There's an attribute you can use in the code behind when defining UserControl s. First, define a property and DependencyProperty for the inner content of your custom view.

public static readonly DependencyProperty InnerContentProperty = DependencyProperty.Register(nameof(InnerContent), typeof(UIElement), typeof(YourCustomControl));

public UIElement InnerContent
{
    get => (UIElement)GetValue(InnerContentProperty);
    set => SetValue(InnerContentProperty, value);
}

Once you've got that, Add the ContentProperty attribute to your class.

[ContentProperty(nameof(InnerContent))]
public class YourCustomControl : UserControl

In your UserControl 's XAML file, put a ContentPresenter with its Content property set to a binding that points to the content property.

<UserControl x:Class="YourNamespace.YourCustomControl" 
             xmlns:local="clr-namespace:YourNamespace.YourCustomControl"
             ...>
    <DockPanel>
        <Menu DockPanel.Dock="Top" Height="50" VerticalAlignment="Center">
        <MenuItem Header="File" Height="50" VerticalAlignment="Center"></MenuItem>
            <MenuItem Header="View"></MenuItem>
        </Menu>
        <Menu DockPanel.Dock="Right" Width="50"></Menu>
        <ContentPresenter Content="{Binding InnerContent, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:YourCustomControl}}}">
    </DockPanel>
</UserControl>

With this, you can change the layout container for the inner content and place it wherever you want.

Now you can use your custom control like any control.

<YourCustomControl>
    <Grid /> <!-- Your inner view -->
</YourCustomControl>

What I get from your Question is: You try to have an Area in your 'Main'-Window that holds 'Sub'-Windows, with a frame and minimize button and such.

Actual Windows are not can not do this.

Instead, you'd need to put a special UserControl in that Area. I'm not sure if there is such a control but let's just pretend there is one called "WindowManagerControl". This Control would be capable of holding and displaying UserControls in Window-Like Frames. You'd then go ahead and create your Sub-Windows as UserControls.

Now if you Click on Button1, all you have to do is Add the demanded UserControl (Sub-Window) to the "WindowManagerControl", which would then Initialize and display the UserControl as Content in a WindowFrame.

The Crucial part is the "WindowManagerControl". There are probably third Party libraries for this that you could use but everything else might be a bit of work.

A simpler solution would be to use a TabControl and add and remove Tabs with your Sub-Window-UserControls as you click the buttons.

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