0

I have MainWindow with ContentControl like this:

<Window x:Class="Prog.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Prog"
        mc:Ignorable="d"
        Title="MainWindow" Height="700" Width="800" Background="Black">
    <Grid>
        <ContentControl x:Name="contentControl" />
    </Grid>
</Window>

Now in constructor i assign my UserControl to "contentControl" which contains one button. What i want to achieve is after clicking on this button another UserControl is assigned to "contentControl". I've tried to create public function in MainWindow where it changes "contentControl", but I dont know how to reference MainWindow object in c#. I could only see static functions but I want to change value so i need object reference. I would appreciate any help

Fake
  • 131
  • 2
  • 10
  • Possible duplicate of [WPF - How do I get the MainWindow instance?](https://stackoverflow.com/questions/19647375/wpf-how-do-i-get-the-mainwindow-instance) – Fang Apr 29 '18 at 15:40
  • You can pass 'this' for main but MVVM in the posted answer is a better approach I think. – paparazzo Apr 29 '18 at 19:09

2 Answers2

1

The usual pattern used for wpf development is mvvm.

The way I'd approach this is viewmodel first navigation.
Define a viewmodel for the window.
That would expose a property of type object ( or baseviewmodel ).
The contentcontrol would bind it's content to that property.
This would then be templated into whichever usercontrol is appropriate using the datatype mechanism to match viewmodel to view.
Changing usercontrol is then a matter of newing up a different viewmodel and setting this property to that instance.
Expose a command from the window viewmodel to do this navigation and use relativesource binding to that from your usercontrol.

This is a simple example of viewmodel first navigation:

<Window.DataContext>
    <local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <StackPanel>
        <Button Content="Login Page"
                Command="{Binding NavigateCommand}"
                CommandParameter="{x:Type local:LoginViewModel}"
                />
        <Button Content="User Page"
                Command="{Binding NavigateCommand}"
                CommandParameter="{x:Type local:UserViewModel}"
                />
    </StackPanel>
    <ContentControl Grid.Column="1"
                    Content="{Binding CurrentViewModel}"
                    />
</Grid>

The viewmodel uses mvvmlight for relaycommand:

public class MainWindowViewModel : INotifyPropertyChanged
{
    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));
        }
    }
}

Your button would of course be in one of these usercontrols.
A relativesource binding looks like:

{Binding DataContext.NameOfCommandInWindowViewModel,
    RelativeSource={RelativeSource AncestorType={x:Type MainWindow}}}

Let's say you really really don't want to learn MVVM for now.

You can get a reference to the window your usercontrol is in from it using:

Window.GetWindow(this);

There is a problem though.
The controls in a window are private members.
You can't just dip into some other object's private members and change stuff. This means you'd have to add a public method to your window so you can call that. This method in turn could take some other usercontrol as a parameter and set the content of one of it's controls as necessary.

Before you think "That sounds easier, I'll just do that" you should be aware that this is widely considered to be bad practice.

Andy
  • 11,864
  • 2
  • 17
  • 20
1

If using standard code behind you would access the MainWindow in your methods as such.

var mainWindow = (MainWindow)Application.Current.MainWindow;

From there you can access public properties and methods from the mainWindow variable.

Then in your UserControl you can change the ContentControl content as follows.

mainWindow.contentControl.Content=new UserControl2();

I have included a full sample showing how to access a method and a property in MainWindow from several UserControls here. https://gist.github.com/DaveCS1/1caca548c0c0caa2e34854074976e609

Hope that helps.