简体   繁体   中英

Cannot display binding on usercontrol?

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??

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, ie 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...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM