WPF文本框:如何将绑定模式默认更改为单向?
最初,我有以下代码:WPF文本框:如何将绑定模式默认更改为单向?,wpf,binding,textbox,binding-mode,Wpf,Binding,Textbox,Binding Mode,最初,我有以下代码: <TextBox Text="{Binding LengthUnit, Mode=OneWay}" IsReadOnly="True" Background="{x:Static SystemColors.ControlBrush}" /> 因为这个文本框是只读的,所以绑定模式不能是双向的 为什么不呢?IsReadOnly将阻止用户修改文本,从而修改属性。只需确保不要修改代码中的Text属性 如果将TextBox子类化,则可以防止绑定属性更新。如果这样做,则可
<TextBox Text="{Binding LengthUnit, Mode=OneWay}" IsReadOnly="True" Background="{x:Static SystemColors.ControlBrush}" />
因为这个文本框是只读的,所以绑定模式不能是双向的
为什么不呢?IsReadOnly将阻止用户修改文本,从而修改属性。只需确保不要修改代码中的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,这意味着绑定属性不会更新,除非通过代码进行更新,有效地使绑定单向。样式是一种将同一组自定义应用于UI对象的一个或多个属性的方法,例如后台、IsReadOnly等,它们通常是依赖性属性 模式是绑定对象的属性,它不是UI对象 可以在任何元素上设置样式 从FrameworkElement或 框架内容元素。- 因此,这通常不是通过XAML/样式实现的。。我猜你必须为它编写代码。尽管XAML允许您设置嵌套属性Text.Mode=“value”,但它很容易出错(因为它假定文本已经设置为绑定对象)。如果Text属性返回的对象上没有Mode属性,则会导致绑定异常,例如,如果Text=“纯字符串”
如果您必须拥有这个,那么您需要以编程方式创建绑定。例如,您可以使用命名约定来查看backing属性是否有setter,如果没有,则添加单向绑定。我知道这个问题很老,但我最近自己也遇到了这个问题,所以也许我可以帮助其他人 我想创建一个文本框,它的文本属性上有一个单向绑定。 我发现这并没有像问题中所示那样起作用,因为WPF基本上通过对标志进行ORing将现有元数据和覆盖元数据结合在一起。 由于BindsTwoWayByDefault是这些标志之一,只要其中一个元数据对象具有BindsTwoWayByDefault=true,则保持为true 唯一的解决方法是在OverrideMetadata中发生WPF合并过程后更改元数据。 但是,元数据对象在方法中标记为密封 作为一个优秀的开发人员,我停在这里重新考虑。。。 Naaa,我使用反射来“解封”元数据对象,并将bindstwaybydefault设置回false 如果有人知道更好的方法,请告诉我 这是我的代码:
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();
}
}
@福森:非常感谢你的回答。这种方法应该可以,因为我实际上正在考虑创建一个派生的ReadOnlyTextBox类。至于绑定模式,你是对的。当我从xaml中删除Mode=OneWay时,我得到了一个异常:“TwoWay或OneWayToSource绑定不能在类型为'xxx'的只读属性'LengthUnit'上工作。”我没有更仔细地看这条消息。问题是我的绑定资源属性只有一个getter。因此,它与文本框的IsReadOnly无关。再次感谢@我刚刚测试了你建议的代码,但它不起作用。我仍然得到一个例外:“双向或单向源绑定不能在类型为“xxx”的只读属性“LengthUnit”上工作。”。我会把我的代码贴在“答案”部分,让它更具可读性。@Prince:对你有用吗?这对我不合适。我还尝试使用TextProperty.AddOwner(…),但出现了相同的错误。@miliu:是否要将此标记为正确并开始一个新问题,或者编辑问题以包含属性为get only?@foson:正如我所说,您建议的解决方案不起作用(即,它不会将TextBox的默认绑定模式更改为单向)。这与我的属性是只读的这一事实无关。非常感谢您的解释,这非常有帮助。@milliu,如果它将是只读的,为什么您希望它是单向的?imho为单个属性创建单独的控件不是一个健康的想法。@Prince,正如我的更新所指出的,单向是由于我的get-only属性。
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;
}
}
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 });
}
}
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();
}
}