0

I am on practice using WPF MVVM with a YouTube video. I made menu buttons in a main window and UserControls, and when I click a menu the UserControl is shown in the main window. The MainViewModel has each ViewModel of the UserControl, and the shown UserControl is changed by changing CurrentView in the MainViewModel.

I want to set the DataContext in the UserControl before it is initialized, but I do not know how. I tried to change ViewModel member values in the MainViewModel, but the actual DataContext member variables in the UserControl are just null.

What I want to ask is how I can set the DataContext in the UserControl when it initialize. Or is there any way to access DataContext from MainWindow?

My Code is below:

Application.xaml

<Application x:Class="Practice.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Practice"
             xmlns:viewModel="clr-namespace:Practice.MVVM.ViewModel"
             xmlns:view="clr-namespace:Practice.MVVM.View"
             Startup="Application_Startup">
    <Application.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type viewModel:HomeViewModel}">
                <view:HomeView/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewModel:UserViewModel}">
                <view:UserView/>
            </DataTemplate>
        </ResourceDictionary>
    </Application.Resources>
</Application>

MainWindow.xaml

<Window x:Class="Practice.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:Practice"
        xmlns:viewModel="clr-namespace:Practice.MVVM.ViewModel"
        xmlns:view="clr-namespace:Practice.MVVM.View"
        mc:Ignorable="d"
        Title="Practice" MinHeight="800" MinWidth="1200"
        WindowStyle="None"
        ResizeMode="NoResize"
        Background="Transparent"
        AllowsTransparency="True"
        Loaded="Window_Loaded">
    <Window.DataContext>
        <viewModel:MainViewModel/>
    </Window.DataContext>
    <Border Background="#002241"
            CornerRadius="10">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200"/>
                <ColumnDefinition Width="1*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="100"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Grid.Column="0"
                       Text="Logo"
                       HorizontalAlignment="Center"
                       VerticalAlignment="Center"
                       FontSize="20"
                       Foreground="White"/>
            <Grid Grid.Row="1" Grid.Column="0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="75"/>
                </Grid.RowDefinitions>
                <StackPanel Grid.Row="0">
                    <RadioButton Content="Home"
                                 Height="50"
                                 Foreground="White"
                                 FontSize="16"
                                 IsChecked="True"
                                 Command="{Binding HomeViewCommand}"/>
                    <RadioButton Content="Users"
                                 Height="50"
                                 Foreground="White"
                                 FontSize="16"
                                 Command="{Binding UserViewCommand}"/>
                </StackPanel>
            </Grid>
            <ContentControl Grid.Row="1" Grid.Column="1"
                            x:Name="CC_View"
                            Margin="10"
                            Content="{Binding CurrentView}"/>
        </Grid>
    </Border>
</Window>

HomeView.xaml

<UserControl x:Class="Practice.MVVM.View.HomeView"
             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:Practice.MVVM.View"
             xmlns:viewModel="clr-namespace:Practice.MVVM.ViewModel"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.DataContext>
        <viewModel:HomeViewModel/>
    </UserControl.DataContext>
    <Grid>
        
    </Grid>
</UserControl>

ObservableObject.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Practice.Core
{
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

RelayCommand.cs

using System;
using System.Windows.Input;

namespace Practice.Core
{
    public class RelayCommand:ICommand
    {
        private Action<object> _execute;
        private Func<object, bool> _canExecute;

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

MainViewModel.cs

namespace Practice.MVVM.ViewModel
{
    public class MainViewModel : ObservableObject
    {
        public RelayCommand HomeViewCommand { get; set; }
        public RelayCommand UserViewCommand { get; set; }

        public HomeViewModel HomeVM { get; set; }
        public UserViewModel UserVM { get; set; }

        private object _currentView;

        private object parameter1;
        private object parameter2;
        private object parameter3;

        public object CurrentView 
        { 
            get { return _currentView; } 
            set 
            { 
                _currentView = value; 
                OnPropertyChanged(); 
            } 
        }

        public MainViewModel()
        {
            parameter1 = new object();
            parameter2 = new object();
            parameter3 = new object();
            HomeVM = new HomeViewModel();
            HomeVM.Initialize(parameter1, parameter2, parameter3);
            UserVM = new UserViewModel();

            CurrentView = HomeVM;

            HomeViewCommand = new RelayCommand(o =>
            {
                CurrentView = HomeVM;
            });
            UserViewCommand = new RelayCommand(o =>
            {
                CurrentView = UserVM;
            });
        }
    }
}

HomeViewModel.cs

namespace Practice.MVVM.ViewModel
{
    public class HomeViewModel : ObservableObject
    {
        private object _parameter1;
        private object _parameter2;
        private object _parameter3;

        public HomeViewModel()
        {
            
        }

        public void Initialize(object parameter1, object parameter2, object parameter3)
        {
            _parameter1= parameter1;
            _parameter2= parameter2;
            _parameter3= parameter3;
        }
    }
}

Thank you in advance.

  • 2
    You should remove the `...`. The DataContext will already be set to HomeVM. – Klaus Gütter Sep 10 '21 at 04:55
  • A UserControl should never explicitly set its own DataContext. DataContext is a property that "inherits" its value from that of the parent element of the control. Explicitly setting it breaks the inheritance and any DataContext-based Bindings of the control's properties will no longer work as expected. – Clemens Sep 10 '21 at 06:33

0 Answers0