I am new to WPF and the programming world in general and I need help. I am building a WPF MVVM application.
I want to create a method, which takes a View
(or the name of a View
) and returns its ViewModel
. I need it to use an instance of the ViewModel
in the MainViewModel
(or ShellViewModel
) without creating one with = new()
everytime. I just want to put the name of the View
as an argument and for it to return the ViewModel
.
I was thinking of using ViewModelLocator
from https://www.c-sharpcorner.com/article/datacontext-autowire-in-wpf/ and making it work for my case, but perhaps maybe there is a better way to do this.
Another idea is to add all the ViewModel
s in a class, e.g ViewModelCollector
, and implement a GetViewModel
method and call it in MainViewModel
each time I need another ViewModel
, but it's just an idea I'm not sure how to implement yet.
What is the best approach here?
What I have:
MainView.xaml:
<Grid>
<ItemsControl ItemsSource="{Binding NavigationItems, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton GroupName="Menu" IsChecked="{Binding IsActive, UpdateSourceTrigger=PropertyChanged}"
Command="{Binding DataContext.ShowPageCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}} }"
CommandParameter="{Binding NavigationIndex}">
<RadioButton.Style>
//some style
</RadioButton.Style>
<RadioButton.Content>
<Grid Margin="25,10">
<TextBlock Grid.Row="1" Text="{Binding Name}" />
</Grid>
</RadioButton.Content>
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
MainView.xaml.cs:
public MainView()
{
InitializeComponent();
DataContext = new MainViewModel();
}
(MainViewModel
should be injected here as far as I know but it currently doesn't work that way)
I have 2 other ViewModels, let's say FirstViewModel and SecondViewModel. Services are injected in the constructors of both ViewModels.
Every ViewModel (except MainViewModel
) implements INavigation
:
string Name { get; set; }
string Source { get; set; }
int NavigationIndex { get; set; }
bool IsActive { get; set; }
And there is a ConfigureView
method in every constructor:
public FirstViewModel(SomeService service)
{
this.service = service ?? throw new ArgumentNullException(nameof(service));
//not important things
ConfigureView();
}
private void ConfigureView()
{
Name = "First";
Source = "FirstView.xaml";
}
MainViewModel.cs:
public ObservableCollection<INavigation> NavigationItems { get; set; } //it is set in a different way, using INotifyPropertyChanged
public INavigation SelectedNavigation { get; set; } //it is set in a different way, using INotifyPropertyChanged
public ICommand ShowPageCommand { get; set; }
public MainViewModel()
{
ShowPageCommand = new RelayCommand<int>(ShowPage);
int index = 0;
NavigationItems = new ObservableCollection<INavigation>();
NavigationItems.Add(new FirstViewModel { NavigationIndex = index++, IsActive = true }); //error
NavigationItems.Add(new SecondViewModel { NavigationIndex = index++ }); //error
SelectedNavigation = NavigationItems[0];
}
private void ShowPage(int index)
{
SelectedNavigation = NavigationItems[index];
}
The error is that there is no default constructor.
How can I add the ViewModels to NavigationItems
without creating an instance of them in MainViewModel
?