c# - 我应该在 WPF 中使用自定义控件声明绑定选项的页面
问题描述
我是在 wpf 中进行自定义控件的新手。
我完全不了解自定义控件的绑定技术。
让我给你看看我的练习。
我在cs文件中声明了我的自定义控件
public class CustomControl1 : Control
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata
(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))
);
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextaaProperty =
DependencyProperty.Register(
"Textaa",
typeof(string), typeof(CustomControl1),
new PropertyMetadata(null));
public string Textaa
{
get { return (string)GetValue(TextaaProperty); }
set { SetValue(TextaaProperty, value); }
}
}
在 Generic.xaml 中,我在 Generic.xaml 中为我的自定义控件声明了模板样式。
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Background" Value="DimGray"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
为了给我的控件发文本,我为只有 name 属性并且只是从 INPC 继承的 Data 对象创建了 My Custom 类
public MainWindow()
{
InitializeComponent();
DataContext = new DataObject() { name = "Jeong Yo Han" };
}
public class DataObject : INotifyPropertyChanged
{
private string _name;
public string name
{
get { return _name; }
set {
_name = value;
onPropertyChanged("name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void onPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
在我的主窗口页面中,我声明了我的自定义控件标签
<Grid>
<cc:CustomControl1 Background="Red"
Textaa="{Binding name ,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
</cc:CustomControl1>
</Grid>
我试图测试模板样式中的 templatedParent 是否适用于双向绑定。(请参阅 RelativeSource= { Rela ... TemplatedParent } )。
然后我运行我的程序来查看何时在 DataObject 类中获得命中名称设置器属性。即使我添加了 UpdateSourceTrigger=PropertyChanged,但是当我更改 TextBox 中的文本时它也不能正常工作。当我失去注意力时它会起作用,即使我输入了 UpdateSourceTrigger=PropertyChanged。
所以我改变了我的来源,就像下面的来源一样。
<!-- in Generic.xaml (Template style) -->
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
<!--- in MainWindow.xaml--->
<cc:CustomControl1 Background="Red"
Textaa="{Binding name ,Mode=TwoWay}" >
</cc:CustomControl1>
正如我所料,这很好用。
并且以下不起作用,不是我预期的。
<!-- in Generic.xaml (Template style) -->
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}">
</TextBox>
<!--- in MainWindow.xaml--->
<cc:CustomControl1 Background="Red"
Textaa="{Binding name}" >
</cc:CustomControl1>
但是我很困惑,为什么我应该将 UpdateSourceTrigger 选项放在 StyleTemplate 和 Mode= TwoWayBinding 选项直接放在 customcontrol 标记的 Textaa 依赖属性中。
我需要一个解释。感谢您的阅读。
为了帮助您理解,我在下面添加了我的源代码。
解决方案
更新 TextBox 的 Text 属性的 Binding 的源属性的默认行为是LostFocus
。
请参阅TextBox.Text 属性页上的备注:
在数据绑定方案中使用时,此属性使用 UpdateSourceTrigger.LostFocus 的默认更新行为。
但是,您不需要设置Mode=TwoWay
,因为这已经是默认设置。所以 TextBox 声明应该是这样的:
<TextBox Background="{TemplateBinding Background}"
Text="{Binding Textaa,
UpdateSourceTrigger=PropertyChanged,
RelativeSource={RelativeSource TemplatedParent}}" />
不必在属性UpdateSourceTrigger=PropertyChanged
的 Binding 上进行设置Textaa
,因为(与 相比TextBlock.Text
),您的自定义依赖属性的默认行为已经是PropertyChanged
.
您还可以以默认情况下使其双向绑定的方式注册您的属性,这样您就不必Mode=TwoWay
在Textaa
Binding 上进行设置:
public static readonly DependencyProperty TextaaProperty =
DependencyProperty.Register(
nameof(Textaa), typeof(string), typeof(CustomControl1),
new FrameworkPropertyMetadata(
null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
现在您可以像这样绑定Textaa
属性:
<cc:CustomControl1 Textaa="{Binding name}" />
推荐阅读
- oracle - 我必须在不使用条件语句的情况下在 Pl/SQl 中找到一个数字的回文
- javascript - 测试动态项目列表条件的最佳方法?
- javascript - 如何在 Vue+typescript 中为 Angular 创建 Web 组件?
- c++ - 使用 cusolverDnDpotrfBatched 得到不正确的结果
- visual-studio-code - 为 .code-workspace 文件指定默认的“打开工作区...”位置
- django - 如何使用 Supervisor(包括 Gunicorn 和 Nginx)设置多个 Django 应用程序?bind() to [::]:8090 失败(98:地址已在使用中)
- laravel - 如何检测电子邮件是否未送达收件人?(Gmail SMTP,传送失败)
- javascript - 如何迭代对象数组
- fullcalendar - 我在我的 vue 应用程序中使用 2 fullcalendar,当我点击日历时,我必须点击弹出窗口两次才能关闭它
- typescript - 打字稿:无法将 parseInt() 应用于 HTTP 请求标头中的字符串