当绑定失败时,如何防止设置本地值(以便继承的值将传播)

2024-03-28

考虑以下场景:

我想将 TextElement.FontWeight 属性绑定到 xml 属性。 xml 看起来有点像这样并且具有任意深度。

<text font-weight="bold">
    bold text here
    <inlinetext>more bold text</inlinetext>
    even more bold text
</text>

我使用分层模板来显示文本,没有问题,但是模板样式中有一个 Setter,如下所示:

<Setter Property="TextElement.FontWeight" Value="{Binding XPath=@font-weight}"/>

在第一级正确设置 fontweight,但用 null 覆盖第二级(因为绑定找不到 xpath),这将恢复到正常的 Fontweight。

我在这里尝试了各种各样的方法,但似乎没有什么效果。

例如我使用转换器返回 UnsetValue,但这不起作用。

我目前正在尝试:

<Setter Property="custom:AttributeInserter.Wrapper" Value="{custom:AttributeInserter Property=TextElement.FontWeight, Binding={Binding XPath=@font-weight}}"/>

隐藏代码:

public static class AttributeInserter
{
    public static AttributeInserterExtension GetWrapper(DependencyObject obj)
    {
        return (AttributeInserterExtension)obj.GetValue(WrapperProperty);
    }
    public static void SetWrapper(DependencyObject obj, AttributeInserterExtension value)
    {
        obj.SetValue(WrapperProperty, value);
    }
    // Using a DependencyProperty as the backing store for Wrapper.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty WrapperProperty =
        DependencyProperty.RegisterAttached("Wrapper", typeof(AttributeInserterExtension), typeof(AttributeInserter), new UIPropertyMetadata(pcc));

    static void pcc(DependencyObject o,DependencyPropertyChangedEventArgs e)
    {
        var n=e.NewValue as AttributeInserterExtension;
        var c = o as FrameworkElement;
        if (n == null || c==null || n.Property==null || n.Binding==null)
            return;

        var bex = c.SetBinding(n.Property, n.Binding);
        bex.UpdateTarget();
        if (bex.Status == BindingStatus.UpdateTargetError)
            c.ClearValue(n.Property);
    }

}

public class AttributeInserterExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public DependencyProperty Property { get; set; }
    public Binding Binding { get; set; }
}

这有点有效,但无法跟踪属性的变化

有任何想法吗?有链接吗?

谢谢你的帮助


你走在正确的轨道上。使用附加属性是正确的方法。

最简单的解决方案

如果您愿意为每个继承的属性(数量不是很多)编写代码,那么它会简单得多:

<Setter Property="my:OnlyIfSet.FontWeight" Value="{Binding XPath=@font-weight}"/>

带代码

public class OnlyIfSet : DependencyObject
{
  public static FontWeight GetFontWeight(DependencyObject obj) { return (FontWeight)obj.GetValue(FontWeightProperty); }
  public static void SetFontWeight(DependencyObject obj, FontWeight value) { obj.SetValue(FontWeightProperty, value); }
  public static readonly DependencyProperty FontWeightProperty = DependencyProperty.RegisterAttached("FontWeight", typeof(FontWeight), typeof(Object), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
      {
        if(e.NewValue!=null)
          obj.SetValue(TextElement.FontWeightProperty, e.NewValue);
        else
          obj.ClearValue(TextElement.FontWeightProperty);
      }
  });
}

泛化多个属性

概括这一点可以通过多种方式来完成。一种是创建一个通用的属性注册方法,但仍然使用多个附加属性:

public class OnlyIfSet
{
  static DependencyProperty CreateMap(DependencyProperty prop)
  {
    return DependencyProperty.RegisterAttached(
      prop.Name, prop.PropertyType, typeof(OnlyIfSet), new PropertyMetadata
      {
        PropertyChangedCallback = (obj, e) =>
        {
          if(e.NewValue!=null)
            obj.SetValue(prop, e.NewValue);
          else
          obj.ClearValue(prop);
        }
      });
  }

  public static FontWeight GetFontWeight(DependencyObject obj) { return (FontWeight)obj.GetValue(FontWeightProperty); }
  public static void SetFontWeight(DependencyObject obj, FontWeight value) { obj.SetValue(FontWeightProperty, value); }
  public static readonly DependencyProperty FontWeightProperty =
    CreateMap(TextElement.FontWeightProperty);

  public static double GetFontSize(DependencyObject obj) { return (double)obj.GetValue(FontSizeProperty); }
  public static void SetFontSize(DependencyObject obj, double value) { obj.SetValue(FontSizeProperty, value); }
  public static readonly DependencyProperty FontSizeProperty =
    CreateMap(TextElement.FontSizeProperty);

  ...    
}

允许任意属性

另一种方法是使用两个附加属性:

<Setter Property="my:ConditionalSetter.Property" Value="FontWeight" />
<Setter Property="my:ConditionalSetter.Value" Value="{Binding XPath=@font-weight}"/>

带代码

public class ConditionalSetter : DependencyObject
{
  public string GetProperty( ... // Attached property
  public void SetProperty( ...
  public static readonly DependencyProperty PropertyProperty = ...
  {
    PropertyChangedCallback = Update,
  });

  public object GetValue( ... // Attached property
  public void SetValue( ...
  public static readonly DependencyProperty ValueProperty = ...
  {
    PropertyChangedCallback = Update,
  });

  void Update(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  {
    var property = GetProperty(obj);
    var value = GetValue(obj);
    if(property==null) return;

    var prop = DependencyPropertyDescriptor.FromName(property, obj.GetType(), typeof(object)).DependencyProperty;
    if(prop==null) return;

    if(value!=null)
      obj.SetValue(prop, value);
    else
      obj.ClearValue(prop);
  }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当绑定失败时,如何防止设置本地值(以便继承的值将传播) 的相关文章

  • 跳转到文件行c#

    我如何跳到文件中的某些行 例如 c text txt 中的第 300 行 using var reader new StreamReader c test txt for int i 0 i lt 300 i reader ReadLine
  • pthread_create 编译返回错误

    我使用以下代码创建两个线程 header files include
  • 解决方案将无法构建,因为它无法从服务生成的类型转换为我的类型

    我有一个 WCF 服务项目 它构建得很好 可以生成可访问的 WSDL 并且 svcutil exe 不会生成任何错误 我有一个访问该 Web 服务的 服务管理器 项目 并且我已成功向其中添加了服务引用 ABCService 第三个项目包含我
  • 调试Windows服务

    Scenario 我有一个用 C 编写的 Windows 服务 我已经阅读了所有关于如何调试它的谷歌线程 但我仍然无法让它工作 我已经运行 PathTo NetFramework InstallUtil exe C MyService ex
  • 访问二维数组的一行末尾之后的元素是否是 UB?

    以下程序的行为是否未定义 include
  • 如何在 javascript 中使用 .net 资源文件

    无论如何 我可以在 javascript 中访问我的资源文件 resx 吗 如果没有 那么是否有任何解决方法可以用不同语言的 javascript 显示消息 如果您的 javascript 在页面中 您可以使用 var globalReso
  • 从 C 调用带有字符串参数的 Go 函数?

    我可以从 C 调用一个没有参数的 Go 函数 按照下面的 https github com joeprivacy crefgo hello world 这通过编译go build和打印 Hello from Golang main func
  • MDI应用程序中父窗体的问题

    我使用按钮作为容器中的控件 父窗体 当子窗体出现时 父窗体中的控件 按钮 图片 标签 出现在子窗体上并将其覆盖 我看不到子窗体 有谁知道如何防止这种情况 我不想将这些控件设置为 Control Visible false 因为当我最小化子表
  • C# - 获取 GPU 的总使用百分比

    我正在向我的程序添加一些新功能 这些功能当前通过串行连接将 CPU 使用情况和 RAM 使用情况发送到 Arduino 请参阅this https create arduino cc projecthub thesahilsaluja cp
  • 接收UDP数据包

    假设我的程序通过网络 UDP 发送 1000 字节 它是否保证接收方将 一批 接收 1000 个字节 或者他可能需要执行多次 读取 直到收到完整的消息 如果后者为真 我如何确保同一消息的数据包顺序不会 混淆 按顺序 或者协议可能保证这一点
  • Task.WaitAll 保持循环

    我正在尝试这个异步代码只是为了测试 async 关键字 public async Task
  • 为 C# 和 C++ 应用程序编写 DLL

    我需要编写几个 DLL 它们都可以从 C 应用程序和 C 应用程序访问 最初 我认为通过用 C 编写 DLL 并从 C 和 C 应用程序链接到它们可以节省时间 精力 这种方法明智吗 还是应该使用 C 编写 DLL 我的建议是在您最舒服的地方
  • IBM Rhapsody 中状态图终止连接器的理解

    在IBM Rhapsody中 如果我使用new创建了一个类的实例 那么我们是否必须通过调用delete来处理内存的释放 或者Termination Connector将在其状态图中通过内存释放来处理其销毁 如果您使用 C 和 OXF 对象执
  • dev_t 和 ino_t 是否必须是整数类型?

    glibc 的文档保留它们是整数类型 不比 unsigned int 窄 但我没有找到说明它们必须是整数类型的标准参考 另请参阅 time t 所以最后 问题就变成了 include
  • 正确重载 stringbuf 以替换 MATLAB mex 文件中的 cout

    MathWorks 目前不允许您使用cout当 MATLAB 桌面打开时 从 mex 文件中读取 因为它们已重定向 stdout 他们当前的解决方法是提供一个函数 mexPrintf 他们要求你改用 http www mathworks c
  • 将对象转换为泛型类型

    我已经有一段时间没有睡觉了 所以这可能比我想象的要容易 我有一个通用类或多或少是这样的 public class Reference
  • 位运算符,而不是在分支中使用异或

    问完后这个问题 https stackoverflow com questions 22336015 why use xor with a literal instead of inversion bitwise not 我收到了 Ando
  • LINQ 表达式树 Any() 位于Where() 内

    我正在尝试生成以下 LINQ 查询 Query the database for all AdAccountAlerts that haven t had notifications sent out Then get the entity
  • OledbConnection.Dispose() 是否关闭连接? [复制]

    这个问题在这里已经有答案了 可能的重复 如果使用 using 子句 是否需要关闭 DbConnection https stackoverflow com questions 12033998 is there any need to cl
  • Phong 着色问题

    我正在根据以下内容编写着色器冯模型 http en wikipedia org wiki Phong reflection model 我正在尝试实现这个方程 其中 n 是法线 l 是光线方向 v 是相机方向 r 是光反射 维基百科文章中更

随机推荐