-1

I have a Grid and want to show user control as child of the grid or content of the grid. When a button is clicked, a few user controls will be shown dependent on the cases. Please check the xaml part and code behind.

 <Grid x:Name="ContentPanel" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
  Margin="5,5,5,5">
 </Grid>

I want to bind Grid content to the below activeUserControl object.

 public class MainVM
  {
    public UserControl activeUserControl;
    Stability stability;
    Tank tank;

    public MainVM()
    {

        stability = new Stability();
        tank = new Tank();
        activeUserControl = stability;

        stability.Visibility = Visibility.Visible;

    }
}
nihasmata
  • 652
  • 1
  • 8
  • 28
  • Having a UserControl is a view model is not MVVM. You probably want to use an ItemsControl like this: https://stackoverflow.com/q/6995844/1136211 – Clemens Jul 06 '20 at 06:26
  • Do you want to display a `UserControl` in `ContentPanel`? Or what are you trying to do? What's the purpose of `MainVM`? – mm8 Jul 06 '20 at 14:22

1 Answers1

1

The problem is that you cannot directly bind to the Children collection of a Grid, because it is not a DependencyProperty. You would have to implement attached properties or a behavior to do so. However, you can put a ContentControl into your Grid or replace it as a workaround. Then bind its Content to the activeUserControl property in your view model. Usually properties start with a capital letter, so I adapted it.

<Grid x:Name="ContentPanel" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5">
  <ContentControl Content="{Binding ActiveUserControl}"/>
</Grid>

Make sure that your MainVM is set as DataContext in any of the parent controls, otherwise this binding will not work. activeUserControl must be a property to make it bindable. Implement INotifyPropertyChanged in your MainVM, so that the ContentControl gets notified when the property changes and adapts its Content.

// Implement "INotifyPropertyChanged" so controls get notified about property changes
public class MainVM : INotifyPropertyChanged
{
    // Backing field of the "ActiveUserControl" property
    private UserControl _activeUserControl;
    
    public UserControl ActiveUserControl
    {
        get => _activeUserControl;
        set
        {
            // Only set the value if it has changed
            if (_activeUserControl != value)
            {
                _activeUserControl = value;

                // Signal to the control that it needs to update the value
                OnPropertyChanged(nameof(ActiveUserControl));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public MainVM()
    {
        // ...your code.

        ActiveUserControl = stability;

        // ...your code.
    }

    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

This should solve your problem, but your code is still a mix of MVVM and code-behind. Ideally, you should not have any UI control references in a view model.

Consider creating Tank and Stability view models using INotifyPropertyChanged and data templates to display them, instead of UserControls in your view model. You can still use the ContentControl in this case.

<ContentControl Content="{Binding activeUserControl}">
    <ContentControl.Resources>
        <DataTemplate DataType={x:Type TankViewModel}>
            <!-- ...data template equivalent of your "Tank" user control. -->
        </DataTemplate>
        <DataTemplate DataType={x:Type StabilityViewModel}>
            <!-- ...data template equivalent of your "Stability" user control. -->
        </DataTemplate>
    </ContentControl.Resources>
</ContentControl>
thatguy
  • 21,059
  • 6
  • 30
  • 40
  • Thank you so much for the answer, I tested first solution it worked but when i change the ActiveUserControl it has no effect on GUI. – nihasmata Jul 07 '20 at 11:12
  • I corrected spelling errors in code, it is `ActiveUserControl`, be sure to update it. Assigning a different instance to `ActiveUserControl` is enough. Are you sure that your class implements `INotifyPropertyChanged` (`public class MainVM : INotifyPropertyChanged`)? – thatguy Jul 07 '20 at 11:33
  • Ohh yes i forget to implement INotifyPropertyChanged. When i added this part, it worked. Thank you so much. I will try your second solution for MVVM. – nihasmata Jul 07 '20 at 11:34