用户控件的数据上下文是什么?
What is the datacontext of the user control?
我有这样的用户控件:
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding NameC}" Width="100" />
<TextBlock Text="{Binding Filename}" />
</StackPanel>
</Grid>
在代码后面有 DP:
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); }
}
现在,在 window、
中使用它时
这很好用:
<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>
但这不是:
<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();
}
}
谁能解释一下为什么?为什么用户控件的数据上下文没有自动设置为父级 - 主 window?
当你在做的时候<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />
它不是在看 MainWindow 的数据上下文而是在你的 UserControl 的数据上下文。
所以您可能想要搜索正确的元素并绑定它。下面是使用 ElementName
的一种方法,方法是给 Window 一个名字,比如 MainWindowName
。或者你也可以使用相对源来搜索它的祖先。
<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>
这是因为 UserControl
构造函数中的这一行 DataContext = this
。您将 DataContext
设置为您的用户控件,这会影响 TestUc
和所有子项(包括 <uc:TestUc ... />
)的默认绑定上下文。所以现在
<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />
将在 UserControl
中查找 Name
和 FileName
属性。您需要删除该行,但这会破坏用户控件内的绑定。
<TextBlock Text="{Binding NameC}" Width="100" />
<TextBlock Text="{Binding Filename}" />
将在 MainWindow
中查找 NameC
和 Filename
。解决方案是通过 RelativeSource
或 ElementName
绑定在 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>
在使用 DependencyProperties 创建 UserControl 时,您必须使用 ElementName- 或 RelativeSource Binding 将 DP 绑定到 UserControl 中的控件
<TextBlock Text="{Binding ElementName=myUserControl, Path=NameC}" Width="100" />
而且您从未设置 DataContext。
DataContext = this; <-- do not do that within your UserControl
当你想使用你的 UserControl 时,你将它放在你的视图中并将你实际 DataContext/Viewmodel 的属性绑定到 UserControl 的 DependencyProperties。
<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />
我有这样的用户控件:
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding NameC}" Width="100" />
<TextBlock Text="{Binding Filename}" />
</StackPanel>
</Grid>
在代码后面有 DP:
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); }
}
现在,在 window、
中使用它时这很好用:
<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>
但这不是:
<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();
}
}
谁能解释一下为什么?为什么用户控件的数据上下文没有自动设置为父级 - 主 window?
当你在做的时候<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />
它不是在看 MainWindow 的数据上下文而是在你的 UserControl 的数据上下文。
所以您可能想要搜索正确的元素并绑定它。下面是使用 ElementName
的一种方法,方法是给 Window 一个名字,比如 MainWindowName
。或者你也可以使用相对源来搜索它的祖先。
<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>
这是因为 UserControl
构造函数中的这一行 DataContext = this
。您将 DataContext
设置为您的用户控件,这会影响 TestUc
和所有子项(包括 <uc:TestUc ... />
)的默认绑定上下文。所以现在
<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />
将在 UserControl
中查找 Name
和 FileName
属性。您需要删除该行,但这会破坏用户控件内的绑定。
<TextBlock Text="{Binding NameC}" Width="100" />
<TextBlock Text="{Binding Filename}" />
将在 MainWindow
中查找 NameC
和 Filename
。解决方案是通过 RelativeSource
或 ElementName
绑定在 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>
在使用 DependencyProperties 创建 UserControl 时,您必须使用 ElementName- 或 RelativeSource Binding 将 DP 绑定到 UserControl 中的控件
<TextBlock Text="{Binding ElementName=myUserControl, Path=NameC}" Width="100" />
而且您从未设置 DataContext。
DataContext = this; <-- do not do that within your UserControl
当你想使用你的 UserControl 时,你将它放在你的视图中并将你实际 DataContext/Viewmodel 的属性绑定到 UserControl 的 DependencyProperties。
<uc:TestUc NameC="{Binding Name}" Filename="{Binding FileName}" />