0

I'm not able to display a property value on the usercontrol. I set up the datacontext in this way:

public MainController cm;
public static MainWindow AppWindow;

public partial class MainWindow
{
     public MainWindow()
     {
        InitializeComponent();
        cm = new MainController();
        DataContext = cm;

        AppWindow = this;
     }
}

inside MainController I've all the controller with all the properties like this:

public class MainController: MainControllerVM
{
    private ClubController _clubController = new ClubController();

    public ClubController ClubController 
    {
        get { return _clubController ; }
    }
}

Now I've splitted my user interface in different controls to have more xaml organization. I need to access to the main datacontext that's cm from all user controls, I tried in this way:

public partial class Club : UserControl
{
    public Club ()
    {
        InitializeComponent();
        DataContext = MainWindow.AppWindow.cm;
    }

but I get:

NullReferenceException

on AppWindow. My main problem's that I can't get to display the value of the property on a label available on the user control:

<Label Content="{Binding ClubController.Club.Name}" />

this binding working in the main window but not working on usercontrol, why??

  • 2
    Don't set the UserControl's DataContext that way. It will inherit the DataContext of its parent. If that's not what you want, use a binding in the XAML. What is the parent? What is `MainWindow.AppWindow.sfVm`? Is there a stack trace for that NullReferenceException? Does it get thrown at any particular line in your code? – 15ee8f99-57ff-4f92-890c-b56153 Sep 26 '17 at 14:21
  • What class is `public static MainWindow AppWindow;` declared in? It looks like you are accessing it as a property of `MainWindow`, but it isn't declared there (the deceleration is outside the class). Are you sure you are accessing the right property? – Bradley Uffner Sep 26 '17 at 14:23
  • @EdPlunkett I need to use the same datacontext, for sfVM I corrected the question.. the null value is on AppWindow (when I start the app it return the exception) for Bradley, the MainWindow is the main class – Vandehusend Sep 26 '17 at 14:25
  • @Vandehusend not according to the code you posted. You have the `AppWindow` field declared **outside** `MainWindow`. – Bradley Uffner Sep 26 '17 at 14:26
  • @Vandehusend Nothing here returns an exception. Something throws one. Are you saying `AppWindow` is null in that constructor? Of course it is: You're assigning `this` to `AppWindow` in MainWindow's constructor *after* it calls `InitializeComponent` to create its own children, which executes the usercontrol constructor. If this isn't obvious from first principles, why didn't you put breakpoints or traces in your constructors to determine order of execution? – 15ee8f99-57ff-4f92-890c-b56153 Sep 26 '17 at 14:28
  • @EdPlunkett ok I added AppWindow = this on the top, now the exception is gone away, but the value of the binding isn't displayed – Vandehusend Sep 26 '17 at 14:34
  • Add to binding: `PresentationTraceSources.TraceLevel=High` and see what you see in the Debug pane in visual stuido at rumtime – 15ee8f99-57ff-4f92-890c-b56153 Sep 26 '17 at 16:13
  • @EdPlunkett is displayed "Datacontext is null" – Vandehusend Sep 26 '17 at 18:05
  • Well, I know you have a usercontrol instance somewhere, and a window somewhere. The relationship between the two, and the code in the two, will have a lot to do with what's really happening here, but I don't have any of that other information. If you could create a minimal testable sample showing the issue, I could help. Better yet, in the course of creating a minimal testable example, you'll probably figure it out yourself. – 15ee8f99-57ff-4f92-890c-b56153 Sep 26 '17 at 18:07

1 Answers1

1

Suppose you have a window like this:

<Window x:Class="Example.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Example"
        Title="MainWindow" Height="350" Width="525">
    <UniformGrid Rows="2" Columns="2">
        <local:MyUserControlA/>
        <local:MyUserControlB/>
        <local:MyUserControlC/>
        <local:MyUserControlD/>
    </UniformGrid>
</Window>

And you set the DataContext in the constructor:

public MainWindow()
{
    InitializeComponent();
    DataContext = this;
}

Now remember that the DataContext is an inheritable dependency property, i.e. it flows down. (In general, dependency properties are not inheritable by default, unless you explicitly state it)

So, you set the DataContext once on the root of the logical tree (the window) and all of its children will "see" it. (the UniformGrid and the custom controls in our case)

Yes, that means you can directly bind to the view model in your user control's XAML:

<UserControl x:Class="Example.MyUserControlA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBlock Text="{Binding PropertyFromMainViewModel}"/>      
    </Grid>
</UserControl>

Now, this approach works well, until your control gets so complicated that it needs to have its own ViewModel and DataContext reespectively. Usually this happens when the control is not a passive, but maintains a state (validates input, button state, etc.)

1.Declare all properties that you want to bind to the main view model as dependency properties and pay attention to the default value you specify.

2.Locate the main panel of your UserControl and name it, for example "LayoutRoot":

 <UserControl x:Class="Example.MyUserControlA"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid x:Name="LayoutRoot">
        <TextBlock Text="{Binding MyDependencyProperty}"/>      
    </Grid>
</UserControl>

3.Now, you set the DataContext on the LayoutRoot

public MyUserControlA()
{
    InitializeComponent();
    LayoutRoot.DataContext = new MyUserControlViewModel();
}

4.You bind to the main view model in this way

 <Window x:Class="Example.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Example"
        Title="MainWindow" Height="350" Width="525">
    <UniformGrid Rows="2" Columns="2">
        <local:MyUserControlA MyDependencyProperty="{Binding MainViewModelProperty}"/>
        <local:MyUserControlB/>
        <local:MyUserControlC/>
        <local:MyUserControlD/>
    </UniformGrid>
</Window>

The other way around is to bind using RelativeSource, but this would break the encapsulation and reusability of your UserControl.

WPF has a steep learning curve, I hope my tips were helpful...

shadow32
  • 464
  • 3
  • 9
  • thanks for your answer, I just tried to check if another usercontrol display this: `Content="{Binding ClubController.Club.Name}" ` and yes, so the problem is only of a specific control, no idea why – Vandehusend Sep 27 '17 at 20:37
  • Oh, I suspect another flaw here. Can you move cm = new MainController(); and AppWindow = this; before InitializeComponent() and tell the difference? – shadow32 Sep 27 '17 at 20:53
  • the datacontext is correct, I found the problem, I opened another question, if you have time check here: https://stackoverflow.com/questions/46456987/image-source-binding-not-display-anything – Vandehusend Sep 27 '17 at 20:54