Search code examples
c#wpfuser-controlsmvvm-light

WPF MVVM Lights - Same user control with different parameter


I have a WPF application using MVVM Light.
One MainView (+ MainViewModel) and One User Control (+ UCViewModel).

The application will have a Tab control with 2 Tab Items.
Each tab will have a user control (same user control).

User Control job: Load the contents of the file, display the contents (and allow user to export it out to other format).

When application launch, I will read a config file and will pass the file location (from config file) to each user control (Eg: File1Path, File2Path).
I can use MVVM Light Messenger.Default.Send to do this job (From MainViewModel to UCViewModel).

My issue is: How can I differentiate which User Control will get which file path?

I use SimpleIoc.Default.Register in ViewModelLocator to register my MainViewModel and UCViewModel.
At the time of registration, I do not have the data from Config file yet so I cannot pass it to UCViewModel.

Any comment/solution for my issue?


Solution

  • Method 1 (by using mm8's way)

    As per @mm8 suggested, I ends up declaring DataContext for each UserControl usage in my MainViewModel class as Properties.

    Example (in MainView xaml):

    <v:UC Grid.Row="0" HorizontalAlignment="Stretch" Margin="10" DataContext="{Binding UC2DC}" />
    

    However, in order for me to support my design time XAML intelliense supports, I still use default MVVM Light way of DataContext binding.

    Example: In ViewModelLocator,

    static ViewModelLocator()
    {
        ....
        SimpleIoc.Default.Register<MainViewModel>();
        SimpleIoc.Default.Register<UCViewModel>();
        ....
    }
    
    public UCViewModel CM
    {
        get
        {
            return ServiceLocator.Current.GetInstance<UCViewModel>();
        }
    }
    

    And in MainViewModel,

    private UCViewModel _uC2DC;
    
    public UCViewModel UC2DC
    {
        get { return _uC2DC; }
        set { Set(ref _uC2DC, value); }
    }
    
    private UCViewModel _uC1DC;
    
    public UCViewModel UC1DC
    {
        get { return _uC1DC; }
        set { Set(ref _uC1DC, value); }
    }
    

    And somewhere in my MainViewModel, I need to create new instances and put into these properties.

    When I finish everything, I will delete/comment out User Control default MVVM Light DataContext binding, ViewModelLocator's SimpleIoc Register and GetInstance property,etc and it will change to my MainView databinding.

    I am not so sure does it Ok with MVVM way but as of now, it solves my issue.

    Method 2 (by using Marco's way)

    After Marco sample code, I came to know that we can register multiple instances of ViewModel with a key to differentiate them and when calling in property, use that key to pull the correct one.
    Below is the code...

    For ViewModelLocator

    static ViewModelLocator()
    {
        ...
        SimpleIoc.Default.Register<MainViewModel>();
        SimpleIoc.Default.Register(() => new UCViewModel(), "1");
        SimpleIoc.Default.Register(() => new UCViewModel(), "2");
        ...
    }
    
    public UCViewModel UCVM1
    {
        get
        {
            return ServiceLocator.Current.GetInstance<UCViewModel>("1");
        }
    }
    
    public UCViewModel UCVM2
    {
        get
        {
            return ServiceLocator.Current.GetInstance<UCViewModel>("2");
        }
    }
    

    And in my MainView XAML

    <TabControl>
        <TabItem Header="Test 1">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="70"/>
                    <RowDefinition Height="70"/>
                </Grid.RowDefinitions>
                <v:UC Grid.Row="0" HorizontalAlignment="Stretch" Margin="10" 
                    DataContext="{Binding UCVM1,Source={StaticResource Locator}}" />
                ...
                ...
            </Grid>
        </TabItem>
        <TabItem Header="Test 2">
            <Grid Background="AliceBlue">
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="70"/>
                    <RowDefinition Height="70"/>
                </Grid.RowDefinitions>
                <v:UC Grid.Row="0" HorizontalAlignment="Stretch" Margin="10" 
                    DataContext="{Binding UCVM2,Source={StaticResource Locator}}" />
                ...
                ...
            </Grid>
        </TabItem>
    </TabControl>
    

    For this approach, it still the same, for design time, we cannot bind to one default DataContext. May be this is give and take for such cases.