-2

I get this error:- System.NullReferenceException: 'Object reference not set to an instance of an object.' objectPlacement was null.

private void Button_Click(object sender, RoutedEventArgs e)
 {
    ObjectPlacement w = new ObjectPlacement() {Topmost = };// ObjectPlacement is new WPF window
    objectPlacement.WindowStyle = WindowStyle.None;
    settingpanel.Children.Add(objectPlacement);//settingpanel stack is panel name
    w.Show();
 }    
Ridhdhi
  • 1
  • 1
  • 3
    The property would be `Children`, not `Controls`. However, a Window can not be a child element of a Panel. Make yourself familiar with the absolute basics of WPF, for example by reading a book. – Clemens Jan 12 '23 at 07:11
  • LIke clemens said you have to understand a bit more about basic WPF layout and controls. If you want to add UI to your stackpanel try adding it as a UserControl. Even better if you could learn Prism or other MVVM frameworks to best understand how to dynamically load UI in WPf. – Aabid Ali Jan 12 '23 at 07:15
  • If you changed that so it would actually work, it would error "InvalidOperationException: Window must be the root of the tree. Cannot add Window as a child of Visual." – Andy Jan 12 '23 at 08:36

1 Answers1

2

It would be much more usual to define a usercontrol or datatemplate for whatever you're trying to show in your window. A window is a kind of content control. One way to think of a window ( or contentcontrol ) is something that shows you some UI. All the UI in a window is that content.

When you add window to a project it is templated out with a grid in it. This is the content and everything you want to see in that window goes in it. You could replace that grid with something else instead.

If you made that a contentpresenter then you can bind or set what that'll show to some encapsulated re-usable UI.

Usually the best way to encapsulate re-usable UI is as a usercontrol.

A datatemplate can reference a usercontrol.

It is not usually your entire UI for a window you want to switch out. But you can and that is occasionally useful - say if you want a generic way to show dialogs.

The usual way to write wpf is mvvm so most devs will want some mvvm way of switching out UI.

I'll show you some code might make the description clearer.

There are some corners cut in what follows, so this is illustrative. Don't just run with this for your next lead developer interview at a stock traders. But, basically you click a button for Login you "navigate" to a LoginUC view. Click a button for User and you "navigate" to UserUC.

My mainwindow.

    <Window.Resources>
        <DataTemplate DataType="{x:Type local:LoginViewModel}">
            <local:LoginUC/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:UserViewModel}">
            <local:UserUC/>
        </DataTemplate>
    </Window.Resources>
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <ItemsControl ItemsSource="{Binding NavigationViewModelTypes}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Content="{Binding Name}"
                        Command="{Binding DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                        CommandParameter="{Binding VMType}"
                    />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <ContentPresenter Grid.Column="1"
                          Content="{Binding CurrentViewModel}"
                        />
    </Grid>
</Window>

Notice the datatemplates which associate the type of a viewmodel with a usercontrol. https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/data-templating-overview?view=netframeworkdesktop-4.8

What will happen is you present your data in a viewmodel to the UI via that contentpresenter and binding. That viewodel is then templated out into UI with your viewmodel as it's datacontext. The datacontext of a UserUC view will therefore be an instance of UserViewModel. Change CurrentViewModel to an instance of LoginViewModel and you get a LoginUC in your mainwindow instead.

The main viewmodel.

public class MainWindowViewModel : INotifyPropertyChanged
{
    public string MainWinVMString { get; set; } = "Hello from MainWindoViewModel";

    public ObservableCollection<TypeAndDisplay> NavigationViewModelTypes { get; set; } = new ObservableCollection<TypeAndDisplay>
        (
        new List<TypeAndDisplay>
        {
           new TypeAndDisplay{ Name="Log In", VMType= typeof(LoginViewModel) },
           new TypeAndDisplay{ Name="User", VMType= typeof(UserViewModel) }
        }
        );

    private object currentViewModel;

    public object CurrentViewModel
    {
        get { return currentViewModel; }
        set { currentViewModel = value; RaisePropertyChanged(); }
    }
    private RelayCommand<Type> navigateCommand;
    public RelayCommand<Type> NavigateCommand
    {
        get
        {
            return navigateCommand
              ?? (navigateCommand = new RelayCommand<Type>(
                vmType =>
                {
                    CurrentViewModel = null;
                    CurrentViewModel = Activator.CreateInstance(vmType);
                }));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Type and display relates the type for a viewmodel with text displayed in the UI.

public class TypeAndDisplay
{
    public string Name { get; set; }
    public Type VMType { get; set; }
}

This is "just" quick and dirty code to illustrate a principle which is usually called viewmodel first navigation. Google it, you should find a number of articles explaining it further.

For completeness:

<UserControl x:Class="wpf_Navigation_ViewModelFirst.LoginUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:wpf_Navigation_ViewModelFirst"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel Background="Yellow">
        <TextBlock Text="This is the Login User Control"/>
        <TextBox>
            <TextBox.InputBindings>
                <KeyBinding Key="Return" Command="{Binding LoginCommand}"/>
            </TextBox.InputBindings>
        </TextBox>
    </StackPanel>
</UserControl>

public  class LoginViewModel
{

private RelayCommand loginCommand;
public RelayCommand LoginCommand
{
    get
    {
        return loginCommand
          ?? (loginCommand = new RelayCommand(

            () =>
            {
                string s = "";
            }));
    }
}
}

<UserControl x:Class="wpf_Navigation_ViewModelFirst.UserUC"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:wpf_Navigation_ViewModelFirst"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid Background="pink">
        <TextBlock Text="This is the User module Control"
                   VerticalAlignment="Top"
                   />
        <TextBlock Text="{Binding Path=DataContext.MainWinVMString, RelativeSource={RelativeSource  AncestorType={x:Type Window}}}"
                   VerticalAlignment="Bottom"
                   />
    </Grid>
</UserControl>

public class UserViewModel
{

}

I put this together some years ago, I would now recommend the community mvvm toolkit with it's code generation, base classes, messenger etc.

Andy
  • 11,864
  • 2
  • 17
  • 20