0

I'm creating an application for educational purposes. How can i use multiple User controls in my "MainWindow.xaml"?

I want to use User controls on my MainWindow so that I wont need multiple windows. So after you press next on the sign up layout,

it should take you to the thank you screen which is also another UserControl class. Although in the same Window.

I've read as many different "solutions" as I could, without any real luck..

Here's the code I have atm.

Main Window.xaml

<Window x:Class="WpfApp1.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:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="700" Width="700"
    WindowStartupLocation="CenterScreen">

<Grid>
    <!--Background image-->
    <Grid.Background >
        <ImageBrush ImageSource="login-page-background-3.jpg"/>
    </Grid.Background>

    <!--Main content scroll-->
    <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
        <local:SignUpControl>

        </local:SignUpControl>
    </ScrollViewer>
</Grid>

MainWindow.xaml.cs has no code...

SignUpControl.Xaml

<UserControl x:Class="WpfApp1.SignUpControl"
         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:WpfApp1"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<StackPanel
            VerticalAlignment="Center"
            HorizontalAlignment="Center"
            TextBlock.TextAlignment="Center">

    <!--Login main content white box-->
    <Border Background="WhiteSmoke" 
                    Opacity="0.4"
                    CornerRadius="30"
                    Padding="15 50 15 15"
                    Width="350" 
                    Margin="50 50 50 0">

        <StackPanel>

            <!--Sign Up header-->
            <TextBlock FontSize="20" 
                           HorizontalAlignment="Center" 
                           VerticalAlignment="Top" 
                           Height="auto" 
                           FontFamily="Goudy Stout" >Sign Up</TextBlock>

            <!--Sign up subtext-->
            <TextBlock FontSize="14" 
                               HorizontalAlignment="Center" 
                               VerticalAlignment="Top"
                               Height="auto" 
                               FontFamily="Ravie" >It's about to get fun!</TextBlock>

            <!--Inner grid for Username & Password-->
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <!--Textbox for username-->
                <TextBox Grid.Row="0" BorderThickness="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontFamily="Arial" FontWeight="Bold" FontSize="14" x:Name="UsernameBox" Margin="5"/>
                <TextBlock IsHitTestVisible="False" Text="Username" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10,0,0,0" FontFamily="Arial" FontWeight="Bold" FontSize="14" Foreground="Black">
                    <TextBlock.Style>
                        <Style TargetType="{x:Type TextBlock}">
                            <Setter Property="Visibility" Value="Collapsed"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Text, ElementName=UsernameBox}" Value="">
                                    <Setter Property="Visibility" Value="Visible"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>

                <!--PasswordBox-->
                <TextBox Grid.Row="1" BorderThickness="0" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontFamily="Arial" FontWeight="Bold" FontSize="14" x:Name="passwordBox" Margin="5"/>
                <TextBlock Grid.Row="1" IsHitTestVisible="False" Text="password" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10,0,0,0" FontFamily="Arial" FontWeight="Bold" FontSize="14" Foreground="Black">
                    <TextBlock.Style>
                        <Style TargetType="{x:Type TextBlock}">
                            <Setter Property="Visibility" Value="Collapsed"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding Text, ElementName=passwordBox}" Value="">
                                    <Setter Property="Visibility" Value="Visible"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>

            </Grid>

            <!--Next Button-->
            <Button Content="Next" 
                            HorizontalAlignment="Center" 
                            FontWeight="Bold"
                            FontSize="14"
                            BorderThickness="0"
                            FontFamily="Goudy Stout"
                            Background="Transparent"
                            Padding="20 10"
                            Margin="0 10"
                            x:Name="NextButton"
                            Click="NextButton_Click"/>

        </StackPanel>

    </Border>

    <!--Border for PreRegistered account-->
    <Border Background="WhiteSmoke" 
                    Opacity="0.4"
                    CornerRadius="50"
                    Padding="0"
                    Width="400" 
                    Height="auto"
                    Margin="0 12.5 0 0">

        <!--Already registered button-->
        <Button Content="I already have an account"  
                    HorizontalAlignment="Center" 
                    Opacity="0.8"
                    FontSize="13"
                    BorderThickness="0" 
                    FontFamily="Goudy Stout" 
                    Background="Transparent"
                    Foreground="Black"
                    x:Name="alreadyRegBtn"
                    Padding="0 10"
                    Margin="0 5 0 5"/>

    </Border>

</StackPanel>

How do I go about doing this solution where I can change between user controls on the same window, Ofcourse after the thank you screen I will be using the same logic to go to "Sign In!" an so on...

FilipE92
  • 43
  • 1
  • 11

2 Answers2

2

When i'm not using Prism or Dependency Injection then I normally use the View Model first approach.

In this scenario we have a property on our Windows ViewModel that is a class that the other UserControls ViewModels inherit from, normally just use a ViewModelBase class that has the implimentation of INotifyPropertyChanged:

private ViewModelBase currentViewModel;
public ViewModelBase CurrentViewModel
{
    get { return currentViewModel; }
    set { currentViewModel = value; NotifyPropertyChanged(); }
}

Now inside of your MainWindow like @Tomtom said you have a ContentControl bound to that property. This means that using DataTemplates You can have a different View display depending on which ViewModel type is currently on that property.

<Window.Resources>
    <DataTemplate DataType="{x:Type viewmodels:ViewModel1}">
        <views:View1/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewmodels:ViewModel2}">
        <views:View2/>
    </DataTemplate>
</Window.Resources>

<ContentControl Content="{Binding CurrentViewModel}"/>

With this in place all you need to do is have some logic that changes the ViewModel on the MainWindow ViewModel and the View will update to display the correct View for that ViewModel.

Edit: One thing to note is there are lots of different ways people use to achieve what you want, none of them are really right or wrong but they all suit different peoples needs and coding styles. Diagram

user8478480
  • 427
  • 3
  • 13
  • Do I create a new class that contains the ViewModelBase part? Cant quite figure out that part.. I am very new to this. – FilipE92 May 09 '19 at 07:13
  • You would yes, Essentially, using `MVVM` you end up with a lot of `ViewModels` these are equivalent of code behind but do not have a direct relation, i.e access to controls directly, to the `View` this level of Separation is good. often `ViewModels` will use similar bits of code, most notably Implementation of `INotifyPropertyChanged`. Therefore we can move that code to a class called somethinglike `ViewModelBase` and have all of our other `ViewModels` inherit from it and use that functionality. This polymorphism means each ViewModel is of it's own type and type ViewModel base. – user8478480 May 09 '19 at 07:18
  • This means that we can have a property of type`ViewModelBase` on our `Windows` `ViewModel` and switch it out to any ViewModel as they will technically be of that type. – user8478480 May 09 '19 at 07:19
  • I cant get my head around it.. I've tried using the way you describe but i can't get it to work... I dont think im fully understanding what you are saying either. – FilipE92 May 09 '19 at 08:56
  • I've updated my answer with a picture, I'm not sure if It will make it more overwhelming though. – user8478480 May 09 '19 at 09:11
  • I dont think it did too much for me.. Although i appreciate the effort. I think I need an working example to be able to read it and understand how I should go forth with this type of issues.. – FilipE92 May 09 '19 at 10:41
  • In this approach. In MainWindowViewModel I will have other ViewModels. Where do I assign the DataContext so I can bind from it for the actual view? Like this: ```` or how? So I can store and swap them back and forward. Thanks for any answer – Tomáš Filip Sep 16 '20 at 09:25
0

I've answered a similar question a while ago.

See this post

You can create a ContentControl in your Window and switch the bound UserControl where the user clicks or something else

Tomtom
  • 9,087
  • 7
  • 52
  • 95
  • I've updated the mainwindow xaml and xaml.cs to look like you mentioned (contentcontrol x:name="contentControl " & this.contentControl.content = "userControl.content") in the other post. Although how do i continue this if i now want to change to another usercontrol after i am done with the first userControl? – FilipE92 May 09 '19 at 06:46
  • @user8478480 Certainly because we don't like link-only answers on StackOverflow. This should have been a comment, and if OP thinks the other question is similar to theirs, the question should be closed as duplicate. It does certainly not deserve an upvote, and your upvoting priviledge is not meant for compensation of a downvote that you don't consider fair. Please upvote only on good posts. – Clemens May 09 '19 at 07:18
  • @Clemens I do understand what you're saying and maybe they haven't exactly done the correct way of answering the question, a comment would have been better. But at the end of the day they have gone ahead to help OP and shouldn't be down voted for that. At the end of the day his answer wasn't wrong so pushing it down isn't helpful either and now we just have 2 answer with a 0. – user8478480 May 09 '19 at 07:23
  • @user8478480 *wasn't wrong* isn't exactly right, because it still is a link-only answer. We just don't want to have that. See e.g. here: https://meta.stackoverflow.com/q/265552/1136211. There is of course the second sentence here, but it isn't very helpful without context. – Clemens May 09 '19 at 07:25
  • @Clemens I agree it shouldn't have been posted and we don't want to see it. Just as a note, for a user who doesn't ask questions much on SO, OP. Having an answer with a down vote may imply "Wrong" to OP which also isn't very good / helpful – user8478480 May 09 '19 at 07:38
  • The answer kind of led me in the right direction, what regards the contentControl part. As I was able to display one of the UserControls by following example. However, I am still figuring out how to continue changing between multiple user controls as my question hasn't been fully answered. (Have not yet fully read @user8478480 comment's on his answer. And even if I understand the policies I dont know if it deserved a downvote as it might have helped me a bit. – FilipE92 May 09 '19 at 07:40