简体   繁体   中英

What is the datacontext of the user control?

I have a user control like so:

 <Grid>

    <StackPanel Orientation="Vertical">
        <TextBlock Text="{Binding NameC}" Width="100" />
        <TextBlock Text="{Binding Filename}"  />
    </StackPanel>

</Grid>

with DP in code behind:

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


    public static readonly DependencyProperty NameCProperty = DependencyProperty.Register(
        "NameC", typeof(string), typeof(TestUc), new PropertyMetadata(default(string)));

    public string NameC
    {
        get { return (string) GetValue(NameCProperty); }
        set { SetValue(NameCProperty, value); }
    }


    public static readonly DependencyProperty FilenameProperty = DependencyProperty.Register(
        "Filename", typeof (string), typeof (TestUc), new PropertyMetadata(default(string)));

    public string Filename
    {
        get { return (string) GetValue(FilenameProperty); }
        set { SetValue(FilenameProperty, value); }
    }

Now, when using it in a window,

this works fine:

<Window x:Class="TestDpOnUc.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:uc="clr-namespace:TestDpOnUc"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <uc:TestUc NameC="name is xxx" Filename="This is filename" />
</Grid>

But This does not:

<Window x:Class="TestDpOnUc.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:uc="clr-namespace:TestDpOnUc"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />
</Grid>

public MainWindow()
    {
        InitializeComponent();

        DataContext = this;

        Name = "name is nafsafd";
        FileName = "lkjsfdalkf";


    }

    private string _Name;

    public string Name
    {
        get { return _Name; }
        set
        {
            _Name = value; 
            OnPropertyChanged();
        }
    }


    private string _FileName;

    public string FileName
    {
        get { return _FileName; }
        set
        {
            _FileName = value;
            OnPropertyChanged();
        }
    }

Can someone please explain why? Why is the datacontext of the user control not automatically set to the parent - the main window?

It's because of this line DataContext = this in UserControl constructor. You set DataContext to your user control which affects default binding context for TestUc and all children, including <uc:TestUc ... /> . So at the moment

<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />

will look for Name and FileName properties inside UserControl . You need to remove that line but that will break bindings within the user control.

<TextBlock Text="{Binding NameC}" Width="100" />
<TextBlock Text="{Binding Filename}"  />

Will look for NameC and Filename in MainWindow . Solution to that is to change binding context, per binding, via either RelativeSource or ElementName binding inside UserControl

<UserControl ... x:Name="myUserControl">
    <Grid>
        <StackPanel Orientation="Vertical">
            <TextBlock Text="{Binding ElementName=myUserControl, Path=NameC}" Width="100" />
            <TextBlock Text="{Binding ElementName=myUserControl, Path=Filename}"  />
        </StackPanel>
    </Grid>
</UserControl>

When creating a UserControl with DependencyProperties you have to bind your DP's within your UserControl with ElementName- or RelativeSource Binding to your Controls in your UserControl

<TextBlock Text="{Binding ElementName=myUserControl, Path=NameC}" Width="100" />

and you never set the DataContext.

DataContext = this; <-- do not do that within your UserControl

When you wanna use your UserControl you put it in your View and bind the Properties of your actual DataContext/Viewmodel to the DependencyProperties of the UserControl.

<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />

Whe you are doing <uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" /> its not looking at MainWindow's data context instead at your UserControl's data context.

So you might want to search for the right element and bind it. Below is one way to do it using ElementName by giving a name to Window like MainWindowName . Or you can also use relative source to search for its ancestor.

<Window x:Class="TestDpOnUc.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:uc="clr-namespace:TestDpOnUc"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    x:Name="MainWindowName">
<Grid>
    <uc:TestUc NameC="{Binding Element=MainWindowName, Path=DataContext.Name}" Filename="{Binding Element=MainWindowName, Path=DataContext.FileName}" />
</Grid>

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