0

sorry about this question. I know MVVM exist for many years but each time I try to code something with it I face the same issue again and again ans I'm still looking for a real good tutorial about this.

Let's consider we have a main window (MainWindow.xaml) with its view model (MainViewModel.cs).

This window has a grid, in my grid I define 2 user controls. Whatever it is. One is on the left, one on the right. On my main window I have create, in MainViewModel.cs an engine:

    internal class MainWindowViewModel
    {
        public MainWindowViewModel()
        {
            QCEngine qcEngine = new();
        }
    }

This engine is my unique model and contains a complex code that read data. Whatever. This engine has a public list of value. I want to display these values on my left and right panels in different ways. Again whatever. The display is not my issue.

My issue is how I pass this list or the entire engine reference to my panels? I'm really lost. I can do this in few seconds with any classic WinForms but I never figure out how to do in MVVM. I'm at this moment where I give up MVVM to do classic WinForms. This time I want to understand.

Can you help me?

My QC engine is a RFID reader. It already works fine as console application. All parameters are in a config file. the idea of the interface is to give more flexibility to the reader. Having a nice result screen, a setting screen, some interactions.

<Window x:Class="Beper.QCTable.Control.View.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:view="clr-namespace:Beper.QCTable.Control.View"
        xmlns:viewmodel="clr-namespace:Beper.QCTable.Control.ViewModel"
        mc:Ignorable="d"
        Title="MainWindow" 
        Height="450" 
        Width="800">
    <Window.DataContext>
        <viewmodel:MainWindowViewModel />
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- Menu -->
        <Menu Grid.Row="0" FontSize="20">
            <MenuItem Header="_Menu">
                <MenuItem Header="_Advanced"/>
            </MenuItem>
        </Menu>

        <!--Header-->
        <StackPanel Grid.Row="1" Background="Orange">
            <TextBlock FontSize="20">
                Header
            </TextBlock>
        </StackPanel>

        <!--Body-->
        <Grid Grid.Row="2">
            <view:TabPanel/>
        </Grid>

        <!--Status Bar-->
        <StatusBar Grid.Row="3" FontSize="20">
            <StatusBarItem>
                Status
            </StatusBarItem>
        </StatusBar>
    </Grid>
</Window>

Focus on tab panel:

    public class TabPanelViewModel
    {
        public ObservableCollection<TabItem> Tabs { get; set; } = new ObservableCollection<TabItem>();

        public TabPanelViewModel()
        {
            Tabs.Add(new TabItem { Header = "One", Content = "One's content" });
            Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" });

        }
    }

I cannot chare the engine code but, really, it is just a list of keys (RFID keys / EPC). This is the only public data. I want to display this list of key by group under my tabs.

Bastien Vandamme
  • 17,659
  • 30
  • 118
  • 200
  • What does your View code look like? – Julian Oct 10 '22 at 10:58
  • Of course, I'm watching and reading a lot of tutorials on MVVM right now (I also have access to Pluralsight) but I cannot find a good example of how to pass object from a main view ti child view. Well, I find some examples that are using third party lib. I want to avoid this. I don't want to bring any dependencies if any open-source stuff in this project. – Bastien Vandamme Oct 10 '22 at 10:58
  • Don't 'pass' the engine, use databinding by exposing the engine as a (dependency)property of the MainViewModel and then bind the datacontext of the usercontrol to the Engine property. In the usercontrol all databinding are then relative to the Enigine – Emond Oct 10 '22 at 10:58
  • Yeah something like that..."by exposing the engine as a (dependency)property of the MainViewModel" but I don't understand. I will try to share my code. – Bastien Vandamme Oct 10 '22 at 11:01
  • The engine sets properties that the views bind to. You don't "pass this list or the entire engine reference to my panels". This defeats the purpose of the MVVM design pattern. – mm8 Oct 10 '22 at 11:02
  • Ok fine. So, from my panel I can bind the list of my engin defined on the window? – Bastien Vandamme Oct 10 '22 at 11:08
  • You bind to properties defined in the view model. – mm8 Oct 10 '22 at 11:16
  • If `MainViewModel.TabView` returns the `TabViewModel`, use `` in XAML to set it as data context of the user control. – Klaus Gütter Oct 10 '22 at 11:17
  • Sounds like `QCEngine` is a _service_ and if so you could take a leaf out of any other _how do I use service xxx with MVVM._ Simply pass it as an argument to the VM constructor. If you want to pass it to a control you could have it expose a `DependencyProperty` that you could bind to in the XAML. i.e. expose `QCEngine` in your VM. –  Oct 10 '22 at 11:17
  • The core concept of "passing data to a UserControl" is [property value inheritance](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/property-value-inheritance?view=netdesktop-6.0) of the DataContext property. You do not bind the DataContext, but just have it automatically set (via value inheritance) to the value of the "data item" assigned to a parent element of your control, e.g. the Content property of a ContentControl, or the ItemsSource collection element that is associated to an item container in an ItemsControl. – Clemens Oct 10 '22 at 13:52
  • See also [Data Templating Overview](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/data-templating-overview?view=netframeworkdesktop-4.8). – Clemens Oct 10 '22 at 13:54

1 Answers1

1

Passing "this list or the entire engine reference" to the view defats the purpose of implementing the MVVM design pattern in the first place.

What you should do is to use the engine to prepare and set the state of your app/view in your view model.

The controls in the views should then bind to properties of the view model that contains, and effetively defines, the current state.

mm8
  • 163,881
  • 10
  • 57
  • 88