我看起来很长很难,而且被困住了。我试图通过Window的绑定将参数从Window传递给UserControl1。
在MainWindow中,UserControl1包含两次,一次通过MyValue上的绑定传递参数MyCustom,再次使用文字。使用绑定传递对UserControl1没有影响。 MyCustom依赖项属性未更改。使用文字,它按预期工作。
我很困惑。我在https://stackoverflow.com/a/21718694/468523复制了这个例子但没有快乐。必须有一些我想念的简单。
对于我复制的所有代码感到很抱歉,但是恶魔通常都在详细信息中。
MainWindow.xaml
<Window x:Class="MyParamaterizedTest3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyParamaterizedTest3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel>
<Rectangle Height="20"/>
<local:UserControl1 MyCustom="{Binding MyValue, UpdateSourceTrigger=PropertyChanged}"/>
<Rectangle Height="20"/>
<local:UserControl1 MyCustom="Literal Stuff"/>
<Rectangle Height="20"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="MainWindow: "/>
<TextBlock Text="{Binding MyValue, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
namespace MyParamaterizedTest3
{
public partial class MainWindow : INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
public string MyValue { get => _myValue; set => SetField(ref _myValue, value); }
private string _myValue= "First things first";
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) { return false; }
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
}
}
UserControl1.xaml(已在下方更正)
<UserControl x:Class="MyParamaterizedTest3.UserControl1"
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"
xmlns:local="clr-namespace:MyParamaterizedTest3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Border BorderThickness="3" BorderBrush="Black">
<StackPanel>
<TextBlock Text="{Binding MyCustom, UpdateSourceTrigger=PropertyChanged, FallbackValue=mycustom}"></TextBlock>
</StackPanel>
</Border>
</Grid>
</UserControl>
UserControl1.xaml.cs(已在下方更正)
namespace MyParamaterizedTest3
{
public partial class UserControl1 : INotifyPropertyChanged
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty MyCustomProperty =
DependencyProperty.Register("MyCustom", typeof(string), typeof(UserControl1));
public string MyCustom
{
get
{
return this.GetValue(MyCustomProperty) as string;
}
set
{
this.SetValue(MyCustomProperty, value);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) { return false; }
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
}
}
更正了UserControl1.xaml(每个Ed Plunkett)
<UserControl x:Class="MyParamaterizedTest3.UserControl1"
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 HorizontalAlignment="Center" VerticalAlignment="Center">
<Border BorderThickness="3" BorderBrush="Black">
<StackPanel>
<TextBlock Text="{Binding MyCustom, RelativeSource={RelativeSource AncestorType=UserControl}, FallbackValue=mycustom}"></TextBlock>
</StackPanel>
</Border>
</Grid>
</UserControl>
更正了UserControl1.xaml.cs(每个Ed Plunkett)
<UserControl x:Class="MyParamaterizedTest3.UserControl1"
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 HorizontalAlignment="Center" VerticalAlignment="Center">
<Border BorderThickness="3" BorderBrush="Black">
<StackPanel>
<TextBlock Text="{Binding MyCustom, RelativeSource={RelativeSource AncestorType=UserControl}, FallbackValue=mycustom}"></TextBlock>
</StackPanel>
</Border>
</Grid>
</UserControl>
答案 0 :(得分:3)
在XAML窗口中,默认情况下,usercontrol实例上的绑定使用usercontrol的DataContext作为其源。你假设它从窗口继承了它的datacontext。
但是在UserControl中有这个:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
这会破坏父级给出的所有绑定。所以不要这样做。使用relativesource:
<UserControl x:Class="MyParamaterizedTest3.UserControl1"
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"
xmlns:local="clr-namespace:MyParamaterizedTest3"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Border BorderThickness="3" BorderBrush="Black">
<StackPanel>
<TextBlock Text="{Binding MyCustom, RelativeSource={RelativeSource AncestorType=UserControl}, FallbackValue=mycustom}"></TextBlock>
</StackPanel>
</Border>
</Grid>
</UserControl>
另外:
UpdateSourceTrigger=PropertyChanged
对于从不更新其来源的属性的绑定没有任何作用,因此可以省略。
正如我们在评论中所讨论的,依赖属性不需要INotifyPropertyChanged
。
当绑定无法正常工作时,这是非常令人沮丧的,因为你如何调试它们?你看不到任何东西。关键是在哪里寻找这个属性?你可以得到这样的诊断信息:
<TextBlock
Text="{Binding MyCustom, PresentationTraceSources.TraceLevel=High, FallbackValue=mycustom}"></TextBlock>
这将在运行时向Visual Studio的“输出”窗格发出大量调试信息。它会告诉你Binding正在尝试做什么,一步一步,它找到了什么,以及它失败的地方。
窗口可以通过将自己的DataContext设置为Self来逃脱,因为它没有父级,因此它不会踩到继承的DataContext。但是,窗口可以并且应该使用RelativeSource本身 - 或者更好的是,编写一个主viewmodel类(你知道如何实现INPC),将窗口的属性移动到主视图模型,并分配一个实例viewmodel到窗口的DataContext。