编辑:我已经根据您的评论更新了代码。总之,由于这是一个自定义控件,一旦组件本身满足了这一需求,就不那么依赖MVVM模式来构建组件逻辑(从而在组件中使用代码)(为了排序,尽可能使其属性可绑定)。例如,在更新后的代码中,您现在可以绑定默认属性,但也可以想象在没有值时公开属性以设置用于显示控件名称的前景色,等等。
我的代码中出现了以下绑定错误,我不知道如何解决这些错误。绑定是由VS生成的。我尝试添加presentation.tracesources(在下面的代码中),但我得到了与以前相同的输出。
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='ClimateSolutions.SuperTB', AncestorLevel='1''. BindingExpression:Path=myName; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='ClimateSolutions.SuperTB', AncestorLevel='1''. BindingExpression:Path=isRequired; DataItem=null; target element is 'SuperTB' (Name='email'); target property is 'NoTarget' (type 'Object')
这是我的XAML:
<TextBox x:Class="ClimateSolutions.SuperTB"
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" Height="53" Width="296" FontSize="32"
xmlns:local="clr-namespace:ClimateSolutions"
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
HorizontalAlignment="Left" Name="Blarg">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="">
<Setter Property="Background">
<Setter.Value>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<TextBlock Foreground="Gray" FontSize="24" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:SuperTB, AncestorLevel=1}, Path=myName, diagnostics:PresentationTraceSources.TraceLevel=High}">
</TextBlock>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</Trigger>
<DataTrigger Binding="{Binding Path=isRequired, RelativeSource={RelativeSource FindAncestor, AncestorType=local:SuperTB, AncestorLevel=1}}" Value="False">
<Setter Property="Text" Value="100" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
这是SuperTB的CS:
namespace ClimateSolutions
{
/// <summary>
/// Interaction logic for SuperTB.xaml
/// </summary>
public partial class SuperTB : TextBox, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String Property)
{
var anEvent = this.PropertyChanged;
if (anEvent != null)
{
anEvent(this, new PropertyChangedEventArgs(Property));
}
}
private String MyName = "Unicorns!";
private static DependencyProperty myNameProperty = DependencyProperty.Register("myName", typeof(String), typeof(SuperTB));
public String myName
{
get { return MyName; }
set { MyName = value; NotifyPropertyChanged("myName"); }
}
DependencyProperty isRequiredProperty = DependencyProperty.Register("isRequired", typeof(Boolean), typeof(SuperTB));
public Boolean isRequired
{
get { return (Boolean)GetValue(isRequiredProperty); }
set { SetValue(isRequiredProperty, value); }
}
public SuperTB()
{
InitializeComponent();
myName = "Unicorns!";
}
}
}
我用你的原始代码(包括J cooper提供的解决方案)尝试了几件事,但似乎都不起作用。您的代码似乎有很多问题。
我设法通过使您的文本框成为自定义控件来找到解决方案。
以下是Generic.xaml(控件的视觉定义):
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Question_6514447">
<Style TargetType="{x:Type local:SuperTB2}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SuperTB2}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBox x:Name="PART_Input">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsRequired}" Value="False">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DefaultTextValue}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
这是控制背后的代码:
[TemplatePart(Name = "PART_Input")]
public class SuperTB2 : Control
{
private TextBox PART_Input;
static SuperTB2()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SuperTB2), new FrameworkPropertyMetadata(typeof(SuperTB2)));
}
public SuperTB2()
{
Loaded += SuperTb2Loaded;
}
public override void OnApplyTemplate()
{
PART_Input = GetTemplateChild("PART_Input") as TextBox;
if (PART_Input != null)
{
PART_Input.GotFocus += PartInputGotFocus;
PART_Input.LostFocus += PartInputLostFocus;
}
}
void PartInputLostFocus(object sender, RoutedEventArgs e)
{
if (PART_Input.Text == string.Empty)
{
PART_Input.Text = Name;
PART_Input.Foreground = new SolidColorBrush(Colors.Gray);
}
}
void PartInputGotFocus(object sender, RoutedEventArgs e)
{
if (PART_Input.Text.Equals(Name))
{
PART_Input.Text = string.Empty;
PART_Input.Foreground = new SolidColorBrush(Colors.Black);
}
}
void SuperTb2Loaded(object sender, RoutedEventArgs e)
{
if (PART_Input.Text == string.Empty)
{
PART_Input.Text = Name;
PART_Input.Foreground = new SolidColorBrush(Colors.Gray);
}
}
private static DependencyProperty myNameProperty =
DependencyProperty.Register("MyName", typeof(string), typeof(SuperTB2), new PropertyMetadata("Unicorns !", NameChanged));
private static void NameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public string MyName
{
get { return (string)GetValue(myNameProperty); }
set { SetValue(myNameProperty, value); }
}
DependencyProperty isRequiredProperty =
DependencyProperty.Register("IsRequired", typeof(bool), typeof(SuperTB2), new PropertyMetadata(false, IsReqChanged));
private static void IsReqChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public bool IsRequired
{
get { return (bool)GetValue(isRequiredProperty); }
set { SetValue(isRequiredProperty, value); }
}
public string DefaultTextValue
{
get { return (string)GetValue(DefaultTextValueProperty); }
set { SetValue(DefaultTextValueProperty, value); }
}
// Using a DependencyProperty as the backing store for DefaultTextValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DefaultTextValueProperty =
DependencyProperty.Register("DefaultTextValue", typeof(string), typeof(SuperTB2), new UIPropertyMetadata("100"));
}
组件的使用示例:
<Grid>
<StackPanel>
<Question_6514447:SuperTB2 x:Name="FirstName" IsRequired="true" DefaultTextValue="200"/>
</StackPanel>
</Grid>
有了这个更新的代码,我认为你几乎可以实现你需要的所有行为!
希望这会有所帮助!
不要在绑定表达式中使用相对源。相对源用于访问元素树中较高的元素。似乎您在对象继承方面使用了它。
<Trigger Property="Text" Value="">
<Setter Property="Background">
<Setter.Value>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<TextBlock Foreground="Gray" FontSize="24" Text="{Binding Path=myName, diagnostics:PresentationTraceSources.TraceLevel=High}">
</TextBlock>
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</Trigger>
<DataTrigger Binding="{Binding Path=isRequired}" Value="False">
<Setter Property="Text" Value="100" />
</DataTrigger>