最初,我有以下代码:
<TextBox Text="{Binding LengthUnit, Mode=OneWay}" IsReadOnly="True" Background="{x:Static SystemColors.ControlBrush}" />
我知道我可以定义这样的风格:
<Style TargetType="{x:Type TextBox}" x:Key="readOnlyTextBox">
<Setter Property="Background" Value="{x:Static SystemColors.ControlBrush}"></Setter>
<Setter Property="IsReadOnly" Value="True"></Setter>
</Style>
所以我可以写:
<TextBox Text="{Binding LengthUnit, Mode=OneWay}" Style="{StaticResource readOnlyTextBox}" />
因为这个文本框是只读的,所以绑定模式不能是双向的。那么,是否可以使用此样式将OneWay绑定作为我的TextBox的默认值?
编辑:我需要将绑定模式更改为OneWay,因为我的属性是get-only,而不是因为我标记了TextBox只读。但是,如果可能的话,我仍然希望将文本框的默认绑定模式更改为OneWay。这是我遵循你的建议的代码,但它不起作用。我错过了什么吗?
public class ReadOnlyTextBox : TextBox
{
static ReadOnlyTextBox()
{
TextBox.TextProperty.OverrideMetadata(typeof(ReadOnlyTextBox),
new FrameworkPropertyMetadata() { BindsTwoWayByDefault = false, Journal = true, DefaultUpdateSourceTrigger = UpdateSourceTrigger.Explicit });
}
public ReadOnlyTextBox()
{
base.Background = SystemColors.ControlBrush;
base.IsReadOnly = true;
}
}
答案 0 :(得分:4)
因为这个文本框是只读的,所以绑定模式不能是双向的。
为什么不呢? IsReadOnly将阻止用户修改Text,从而修改属性。请确保不要修改代码中的Text属性。
如果您继承TextBox,则可以阻止绑定属性更新。如果这样做,您可以覆盖TextBox.Text依赖项属性元数据。
public class TextBoxEx : TextBox
{
public TextBoxEx() : base() { }
static TextBoxEx()
{
TextBox.TextProperty.OverrideMetadata(typeof(TextBoxEx),
new FrameworkPropertyMetadata() { BindsTwoWayByDefault = false, Journal = true,
DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.Explicit });
}
}
对于某些原因,将BindsTwoWayByDefault更改为false对我不起作用,但您可以将DefaultUpdateSourceTrigger设置为Explicit,这意味着除非通过代码完成绑定属性,否则不会更新绑定属性,从而有效地进行绑定OneWay。
答案 1 :(得分:2)
样式是一种将同一组自定义应用于UI对象的一个或多个属性的方法,例如背景,IsReadOnly等通常是依赖属性。
模式是Binding对象的属性,它不是UI对象。
您可以在任何元素上设置样式 派生自FrameworkElement或 FrameworkContentElement上。 - Source (MSDN)
所以这通常不是通过XAML / Styling完成的......我的猜测是你必须为它编写代码。虽然XAML允许您设置嵌套属性Text.Mode =“value”,但它容易出错(因为它假定Text已经设置为绑定对象)。如果Text属性返回一个没有Mode属性的对象,它将导致绑定异常 - 例如如果Text =“一个普通的字符串”。
如果你绝对必须拥有它,那么你需要以编程方式创建绑定。例如,您可以使用命名约定来查看backing属性是否具有setter,如果不是,则添加OneWay绑定。
答案 2 :(得分:2)
我知道这个问题真的很老了,但我最近自己遇到了这个问题,所以也许我也可以帮助其他人。
我想在Text属性上创建一个具有OneWayBinding的TextBox。 我发现这没有问题所示,因为WPF将现有的元数据和覆盖的元数据结合在一起,基本上将标志OR化在一起。 由于BindsTwoWayByDefault是其中一个标志,只要其中一个元数据对象具有BindsTwoWayByDefault = true就保持为真。
唯一的方法是在OverrideMetadata中进行WPF合并过程后更改元数据。 但是,元数据对象在方法中标记为“密封”。
任何优秀的开发者都会在这里停下来重新考虑...... Naaa,我用反射来“解封”元数据对象,并将BindsTwoWayByDefault设置为true。
如果有人知道更好的方法,请告诉我。
这是我的代码:
public partial class SelectableTextBlock : TextBox
{
static SelectableTextBlock()
{
var defaultMetadata = (FrameworkPropertyMetadata)TextProperty.GetMetadata(typeof(TextBox));
var newMetadata = new FrameworkPropertyMetadata(
defaultMetadata.DefaultValue,
FrameworkPropertyMetadataOptions.Journal,
defaultMetadata.PropertyChangedCallback,
defaultMetadata.CoerceValueCallback,
defaultMetadata.IsAnimationProhibited,
defaultMetadata.DefaultUpdateSourceTrigger);
TextProperty.OverrideMetadata(typeof(SelectableTextBlock), newMetadata);
//Workaround for a bug in WPF were the Metadata is merged wrongly and BindsTwoWayByDefault is always true
var sealedProperty = typeof(PropertyMetadata).GetProperty("Sealed", BindingFlags.Instance | BindingFlags.NonPublic);
sealedProperty.SetValue(newMetadata, false);
newMetadata.BindsTwoWayByDefault = false;
sealedProperty.SetValue(newMetadata, true);
}
public SelectableTextBlock()
{
InitializeComponent();
}
}