c# - 如何防止 UserControl 破坏 ElementName 绑定
问题描述
编辑:
创建控件的正确方法是如何避免ElementName 绑定出现以下问题:
<TextBox x:Name="MyTextBox" Text="some Text"></TextBox>
<Label>
<!--Binding works-->
<TextBlock Text="{Binding Path=Text, ElementName=MyTextBox, FallbackValue='Binding Failed'}"></TextBlock>
</Label>
<Button>
<!--Binding works-->
<TextBlock Text="{Binding Path=Text, ElementName=MyTextBox, FallbackValue='Binding Failed'}"></TextBlock>
</Button>
<local:MyUserControl>
<!-- THIS BINDING FAILS !!!-->
<TextBlock Text="{Binding Path=Text, ElementName=MyTextBox, FallbackValue='Binding Failed'}"></TextBlock>
</local:MyUserControl>
MyUserControl.xaml:
<UserControl x:Class="Problem.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
MyUserControl.xaml.cs
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
}
原文: 我还是 WPF 的新手,无法找到正确的方法。我基本上希望 UserControl 的子项保留能够绑定到 XAML 中根元素的 x:Name 的行为。
这是一个示例,显示了与 WPF 控件相比,由我的 UserControl 描述符引起的问题:
<Parent x:Name="_thisParent">
...
<Label>
<!-- Binding to _thisParent works -->
<TextBlock Text="{Binding Path=MyText, ElementName=_thisParent}" />
</Label>
<uc:Descriptor Text="description: ">
<!-- Binding to _thisParent FAILS !! -->
<TextBlock Text="{Binding Path=MyText, ElementName=_thisParent}" />
</uc:Descriptor>
<Button>
<!-- Binding to _thisParent works -->
<TextBlock Text="{Binding Path=MyText, ElementName=_thisParent}" />
</Button>
这是我的用户控件的代码:
描述符.xaml
<UserControl
x:Class="EmbedContent.UserControls.Descriptor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="_thisDescriptor">
<UserControl.Template>
<ControlTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="{Binding Path=Text, ElementName=_thisDescriptor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, FallbackValue='Binding Failed'}" />
<ContentPresenter Content="{Binding Path=Content, ElementName=_thisDescriptor, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, FallbackValue='Binding Failed'}" />
</DockPanel>
</ControlTemplate>
</UserControl.Template>
描述符.xaml.cs
public partial class Descriptor : UserControl
{
#region Ctor
public Descriptor()
{
InitializeComponent();
}
#endregion
#region Dependency-Properties
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(Descriptor), new PropertyMetadata("Descriptor's default Text"));
#endregion
我将如何需要实现自定义 UserControl / ContentControl(如果需要没有 xaml)来保留 WPF 控件的行为?
无论如何,这是如何根据最佳实践完成的?我假设我只是遇到这个问题,因为我做错了什么。
解决方案
我终于找到了一个解决方案,但它看起来仍然有些难看,所以我希望有人能发布一个更好的解决方案。我在这里发布代码,包括一个再次突出显示问题的示例。
解决方案:
将 UserControl / ContentControl 拆分为继承自例如 ContentControl 的 .cs 类,并设置描述 App.xaml 资源中额外元素的模板。基本上将 .xaml 部分作为样式移动到资源中。
描述符.cs
namespace EmbedContent.UserControls
{
class Descriptor : ContentControl{
#region Ctor
public Descriptor() : base() {}
#endregion
#region Dependency-Properties
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(Descriptor), new PropertyMetadata("Descriptor's default Text"));
#endregion
}
}
应用程序.xaml
<Application
x:Class="EmbedContent.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EmbedContent"
xmlns:uc="clr-namespace:EmbedContent.UserControls"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="uc:Descriptor">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="uc:Descriptor">
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="{Binding Path=Text, RelativeSource={RelativeSource AncestorType=uc:Descriptor}}" />
<ContentPresenter />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
上面可以调用和使用描述符,因为我期望它来自 WPF 控件。这里是 UserControl 的代码,它在使用时会破坏绑定:
描述符二.xaml
<UserControl
x:Class="EmbedContent.UserControls.DescriptorTwo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="_thisDescriptorTwo">
<UserControl.Template>
<ControlTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="{Binding Path=Text, ElementName=_thisDescriptorTwo}" />
<ContentPresenter Content="{Binding Path=Content, ElementName=_thisDescriptorTwo}" />
</DockPanel>
</ControlTemplate>
</UserControl.Template>
描述符Two.xaml.cs
namespace EmbedContent.UserControls
{
public partial class DescriptorTwo : UserControl
{
#region Ctor
public DescriptorTwo()
{
InitializeComponent();
}
#endregion
#region Dependency-Properties
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(DescriptorTwo), new PropertyMetadata("Descriptor's default Text"));
#endregion
}
}
这里是如何从另一个 UserControl 调用两者的示例
Example.xaml
<UserControl
x:Class="EmbedContent.UserControls.EmbedContentExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:EmbedContent.UserControls"
x:Name="parent">
<StackPanel>
<Label>
<!-- Binding to parent works -->
<TextBlock Text="{Binding Path=MyText, ElementName=parent}" />
</Label>
<uc:Descriptor Text="description: ">
<!-- Binding to parent works -->
<TextBlock Text="{Binding Path=MyText, ElementName=parent}" />
</uc:Descriptor>
<uc:DescriptorTwo Text="description: ">
<!-- Binding to parent fails -->
<TextBlock Text="{Binding Path=MyText, ElementName=parent}" />
</uc:DescriptorTwo>
</StackPanel>
和代码隐藏
示例.xaml.cs
namespace EmbedContent.UserControls
{
public partial class EmbedContentExample : UserControl
{
public EmbedContentExample()
{
InitializeComponent();
}
public string MyText
{
get { return (string)GetValue(MyTextProperty); }
set { SetValue(MyTextProperty, value); }
}
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register("MyText", typeof(string), typeof(EmbedContentExample), new PropertyMetadata("EmbedContentExample's MyText"));
}
}
推荐阅读
- flutter - Dart 中的居中问题与 Wrap Display
- python - 每 3 分钟重复一次单元测试
- r - 如何使用文本计数创建数据透视表
- excel - 如何从过滤列表中检索行号
- bootstrap-vue - Bootstrap Vue b-dropdown 在移动设备上导致页面滚动问题
- python - 使用python的电子邮件自动化
- r - 在单个命令中运行选定的 Rmd 块 (R)
- scala - Parquet 的 Hdinsight Spark 会话问题
- android-studio - Android studio 弹出登录授权问题
- dynamic-programming - 这里的子问题是什么以及它是如何计算的