MikaelKP
MikaelKP

Reputation: 133

Is it possible to have two different DataContext in one UserControl?

Is it possible to have two different DataContext in one UserControl? I would like to access one of my Model objects, but also properties in the MainViewModel. Examples:

ClassDatas DataContext (an object defined in a Model):

<DataGrid x:Name="PropertiesControl1" Height="auto" ItemsSource="{Binding ClassDatas}" HeadersVisibility="None" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="True">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Fields}" Header="" Width="*" IsReadOnly="True"/>
            </DataGrid.Columns>
</DataGrid>

MainViewModel DataContext:

<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty, UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" >.....</TextBox>

And further how is it possible to combine them?

<TextBox x:Name="txtFields" Text="{Binding FieldsTextProperty, UpdateSourceTrigger=PropertyChanged}" Height="23" TextWrapping="NoWrap" Background="#FFCBEECD" AcceptsReturn="False" >
                <i:Interaction.Triggers>
                    <iex:KeyTrigger Key="Enter">              
                        <cmd:EventToCommand Command="{Binding DataContext.AddFieldCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PassEventArgsToCommand="True"/>
                    </iex:KeyTrigger>
                </i:Interaction.Triggers>
</TextBox>

The FieldsTextProperty is a DataContext from the MainViewModel and the EventToCommand contains DataContext from my object.

Upvotes: 1

Views: 1577

Answers (2)

Rachel
Rachel

Reputation: 132548

No, a control can only have a single object set to its DataContext property

However a binding doesn't have to bind to it's DataContext. You can use other binding properties to specify a different source for the binding. Commonly used properties to change the source for a binding are Source, RelativeSource, and ElementName.

  • You can either change the binding's source for a specific binding only, such as you're doing in your Command binding

  • Or you can change it for an entire control by setting or binding the control's DataContext property to something else

I actually see so much confusion over the DataContext in WPF beginners that I wrote a blog post about it. You may be interested in reading it over : What is this "DataContext" you speak of?

Here's a code block I use to help demonstrate the DataContext:

Suppose we bind a window to an object called ClassA. ClassA has a property called ClassB, and both ClassA and ClassB have a property called Name.

Here is a block of XAML which illustrates how the DataContext works. It also includes an example of how a control would refer to a property not in its own DataContext.

public partial class MyWindow: Window
{
    public MyWindow()
    {
       InitializeComponent();
       this.DataContext = new ClassA();
    }
}

public class ClassA
{
    public string Name { get; set; }
    public ClassB ClassB { get; set; }
}

public class ClassB
{
    public string Name { get; set; }
}
<!-- DataContext set to ClassA in initialization code -->
<Window x:Name="MyWindow"> 
 
    <!-- DataContext here is not specified, so it's inherited 
         from its parent's DataContext, which is ClassA -->
    <StackPanel> 
 
        <!-- DataContext inherited from parent, which is 
             ClassA, so this will display ClassA.Name -->
        <Label Content="{Binding Name}" />
 
         <!-- DataContext is still ClassA, however we are 
              setting it to ClassA.ClassB with a binding -->
        <StackPanel DataContext="{Binding ClassB}">
 
            <!-- DataContext inherited from parent, which is 
                 ClassB, so this will display ClassB.Name -->
            <Label Content="{Binding Name}" />
 
            <!-- DataContext is still ClassB, but we are 
                 binding to the Window's DataContext.Name, 
                 which is ClassA.Name -->
            <Label Content="{Binding 
                       ElementName=MyWindow, 
                       Path=DataContext.Name}" /> 
        </StackPanel>
 
        <!-- We've left the StackPanel with its DataContext 
             bound to ClassB, so this Label's DataContext 
             is ClassA (inherited from parent StackPanel), 
             and we are binding to ClassA.ClassB.Name -->
        <Label Content="{Binding ClassB.Name}" />
    </StackPanel>
</Window>

Upvotes: 2

Dean Kuga
Dean Kuga

Reputation: 12119

Yes, your User Control can have a DataContext and any control within that user control can have a different DataContext as well but in your scenario that's not what you should be doing.

Your TextBox should use a simple command bound to the underlying ViewModel of the UserControl and when the command is executed you should use the message bus to get whatever you need from your MainViewModel or any other ViewModel. The message bus is how ViewModels are supposed to communicate and exchange information in MVVM...

Upvotes: 0

Related Questions