考虑以下情况:
我想将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 normal。
我在这里尝试了各种各样的东西,但似乎没有什么工作。
e.g。我使用转换器返回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; }
}
哪种方式有效,但无法跟踪属性的变化
有什么想法吗?有链接吗?
请求帮助
答案 0 :(得分:3)
你走在正确的轨道上。使用附属物是可行的方法。
最简单的解决方案
如果你愿意为每个继承的属性编写代码(它们不是很多),它可以更简单:
<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);
}
}
答案 1 :(得分:0)
如果有人遇到这个,我的最终解决方案就是:
<DataTrigger Binding="{Binding XPath=@font-weight,Converter={converters:IsNullConverter}}" Value="false">
<Setter Property="TextElement.FontWeight" Value="{Binding XPath=@font-weight}" />
</DataTrigger>
IsNullConverter是一个带有此主体的简单Valueconverter:
return value == null;