Search code examples
c#wpfxaml

Put Page as Content for ScrollViewer or ContentControl etc


Is there a way to put a Page inside a <Grid/>, <StackPanel/>, <ContentControl/> or <ScrollViewer/> as content from code using a constructor call?

I expect such things:

XAML:

<Grid>
     <ScrollViewer Content="{Binding Panel0}"/>
</Grid>

C#:

public class TestWindowViewModel : Page
{
   public string Name { get; private set; }
   public string Description { get; private set; }
   public TestWindowViewModel(string name, string description)
   {
       Name = name;
       Description = description;
    }
}

_

public partial class SomeViewModel : Page
{
    public TestWindowViewModel Panel0;

    public SomeViewModel()
    {
        Panel0 = new TestWindowViewModel("panelName", "panelDescription"); 
        InitializeComponent();
    }
}

Solution

  • You can use a Frame tag

    <ScrollViewer>
    <Frame content = "{Binding MyPage}"/>
    </ScrollViewer>
    

    If you don't want to have a prop in your ViewModel then you should be able to do

    <ScrollViewer>
    <Frame>
    <Frame.Content>
    <locals:MyPage>
    </Frame.Content>
    </ScrollViewer>
    

    Keep in mind you have something called TestWindowViewModel and it inherits Page. This is not a ViewModel. Instead it is a normal page.

    You want something that looks like this:

        public class NotifyPropertyClass : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            private Page myPage;
    
            public Page MyPage
            {
                get { return myPage; }
                set
                {
                    myPage = value;
                    NotifyPropertyChanged();
                }
            }
    
        }
    

    and you can go a level farther and make an abstract class:

        public abstract class ViewModel : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    and then you can just inherit ViewModel like so:

    public class TestWindow: Page
    {
       public TestWindow()
       {
           InitializeComponent();
        }
    }
    
    public class TestWindowViewModel : ViewModel
        {
            private string name;
    
            public string Name
            {
                get { return name; }
                set
                {
                    name = value;
                    NotifyPropertyChanged();
                }
            }
    
            private string description;
    
            public string Description
            {
                get { return description; }
                set
                {
                    Description = value;
                    NotifyPropertyChanged();
                }
            }
    
        }
    

    Once you get this all seperated out correctly you can use the frame and do the same for the SomePage and SomePageViewModel and then you can use actual binding on the Frame Content from the ViewModel. I know this is long winded, but if you start out right on setting up a good MVVM setup you will save yourself headache if you ever get into Async and what not.