Referencing a UIElement in a ViewModel from XAML

3.4k views Asked by At

I'm relatively new to using WPF and the MVVM architecture. I have a question about referencing UIelements from a XAML window's DataContext.

I have menu items that are bound to Views DataContext using this syntax:

<MenuItem Header="About" Command="{Binding AboutCommand}" />

I'd like to use a similar paradigm to add items to a grid. Right now I am using a class WorkflowDesigner. I can add it to my grid using the following code in my ViewModel:

grid.AddChildren(wd.View)

where view is of type UIElement.

What I'd rather do is add is reference to it from my XAML file without putting anything in my codebehind so that I can use the XAML mostly as a skin. Is it possible to use a tag just takes its UIElement from the datacontext of the XAML file?

2

There are 2 answers

0
mancaus On BEST ANSWER

This is possible, but it's not within the spirit of MVVM to have your ViewModel provide controls to your view. Ideally your ViewModel should have no dependencies on System.Windows.Controls at all.

If you must, then you can use a ContentControl:

<ContentControl Content={Binding wd.View} />

To handle this I'd create a ViewLocator class and put an instance of it into your resource dictionary. Then use this:

<ContentControl Content={Binding Source={StaticResource ViewLocator}, Path=WorkflowDesigner} />
0
bigfoot On

I'm not sure if I quite understand your problem, but if you have a class you wish to present in your view from your ViewModel, you could use an ItemsControl to display different classes using a DataTemplate.

Say you have class User

public class User
{
    public string Id { get; set;}
    public string Name { get; set;}
}


public class UserViewModel
{
    private ObservableCollectionaUser<User> _users = new......
    public ObservableCollection<User> Users
    {
        get
        {
            return _users;
        }
    }
}

In UserView, you could have

<ItemsControl ItemsSource="{Binding Users}">
    <ItemsControl.Resources>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
               <TextBlock Text="{Binding Id}" />
               <TextBlock Text="{Binding Name}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>

This way, a User would be presented in the view using the template declared above. Then you would not have to use UIElements in your ViewModel.

The ItemsControl could refer to grid items, and have items presented in a grid with SharedGridScope (if I remember correctly).