-1

I have a UserControl in ViewModel which is a Property in ViewModel. I will obtain this UserControl from some dll's.

    private GraphicControl _graphicCtrl;

            public GraphicControl GraphicCtrl
            {
                get { return _graphicCtrl; }
                set
                {
                    _graphicCtrl = value;
                    NotifyPropertyChanged();
                }
            }

In the above property, GraphicCtrl is nothing but a UserControl. I want to display this in my View (xaml). So how should I achieve this.?

Pravin
  • 55
  • 1
  • 9
  • 2
    You should not have any UI stuff like Controls in your ViewModel – Sir Rufo May 28 '20 at 06:21
  • I will get the UserControl from dll's, so where to incorporate that.? @SirRufo – Pravin May 28 '20 at 06:24
  • 1
    It does not matter where you get that control from. A ViewModel is an **abstraction** of the View without **any dependency** to the concrete View framework (WPF, Xamarin, etc.) – Sir Rufo May 28 '20 at 06:27
  • Okay. I agree, kindly tell me how to achieve this. I have got the the *UserControl* from dll. Now I want to display in View. @SirRufo – Pravin May 28 '20 at 06:32
  • If the intent is to have some sort of dynamic UI/plug-in/SmartClient approach then the view model should be defined in the dll where you get the UserControls. –  May 28 '20 at 06:32
  • 1
    How this dll is linked? With static linking (added to references) you just have to use appropriate `xmlns` (see [this](https://stackoverflow.com/a/1093451/1997232)), otherwise you need a little bit of code behind to do reflection (see [this](https://stackoverflow.com/a/7872994/1997232)), the latter can be put into custom xaml markup extension (see [this](https://stackoverflow.com/a/23376241/1997232)) or you can create custom control. As always use data templates to separate view from view models. – Sinatr May 28 '20 at 07:22

2 Answers2

1

Here is a very simple example how to separate this

public class MainViewModel : ReactiveObject
{
    public MainViewModel()
    {
        Stuff = new ObservableCollection<object>
        {
            new Person { FirstName = "Jon", LastName="Doe", },
            new Car { Brand = "Ford", Model = "Model T" },
        };
    }
    public IEnumerable Stuff { get; }
    [Reactive] public object SelectedStuff { get; set; }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Car
{
    public string Brand { get; set; }
    public string Model { get; set; }
}

As you can see, no dependency to any controls or other UI related stuff.

Now the view where I decide how to present the data from the ViewModel

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="200" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ListBox
          ItemsSource="{Binding Stuff}"
          SelectedItem="{Binding SelectedStuff}">
        <ListBox.Resources>
            <DataTemplate DataType="{x:Type local:Car}">
                <TextBlock>
                    <Run Text="{Binding Brand}" /><Run Text=" - " /><Run Text="{Binding Model}" />
                </TextBlock>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:Person}">
                <TextBlock>
                    <Run Text="{Binding FirstName}" /> <Run Text="{Binding LastName}" />
                </TextBlock>
            </DataTemplate>
        </ListBox.Resources>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <ContentPresenter Content="{Binding}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <ContentControl
          Grid.Column="1"
          Content="{Binding SelectedStuff}">
        <ContentControl.Resources>
            <DataTemplate DataType="{x:Type local:Car}">
                <local:CarControl/>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:Person}">
                <local:PersonControl/>
            </DataTemplate>
        </ContentControl.Resources>
    </ContentControl>
</Grid>

the CarControl

<StackPanel>
    <Label Content="Car" />
    <Label Content="Brand" />
    <TextBlock Text="{Binding Brand}" />
    <Label Content="Model" />
    <TextBlock Text="{Binding Model}" />
</StackPanel>

the PersonControl

<StackPanel>
    <Label Content="Person" />
    <Label Content="FirstName" />
    <TextBlock Text="{Binding FirstName}" />
    <Label Content="LastName" />
    <TextBlock Text="{Binding LastName}" />
</StackPanel>

and finally a screenshot

MainWindow Screenshot

Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
1

I want to display this in my View (xaml). So how should I achieve this.?

Short answer: Use a ContentControl and bind its Content property to the UserControl:

<ContentControl Content="{Binding GraphicCtrl}" />

As others have already mentioned, exposing a UserControl from a view model is not MVVM though.

You should rather expose a POCO data object called Graphic or something and then use a DataTemplate to map this type to a UserControl in the view:

<ContentControl Content="{Binding Graphic}">
    <ContentControl.ContentTemplate>
        <DataTemplate>
            <local:GraphicControl />
        </DataTemplate>
    </ContentControl.ContentTemplate>
</ContentControl>
mm8
  • 163,881
  • 10
  • 57
  • 88