简体   繁体   English

XAML“有条件”绑定

[英]XAML “Conditional” Binding

I have a DataTrigger attached to a style for TextBlock, defined as such: 我有一个DataTrigger附加到TextBlock的样式,定义如下:

<DataTrigger Binding="{Binding Path=Link, Converter={StaticResource HasContentConverter}}" Value="True">
    <Setter Property="TextDecorations" Value="Underline" />
    <Setter Property="Cursor" Value="Hand" />
</DataTrigger>

The issue that I'm having is that I have multiple objects that end up using this style, some of which contain a "Link" property, and some of which don't. 我遇到的问题是我有多个对象最终使用这种风格,其中一些包含“链接”属性,而其中一些则没有。 Whenever the system encounters an object that doesn't, it prints this error in the output window: 只要系统遇到没有的对象,它就会在输出窗口中输出以下错误:

BindingExpression path error: 'Link' property not found on 'object' ''DataRowView' (HashCode=53681904)'. BindingExpression路径错误:'对象'''DataRowView'(HashCode = 53681904)'上找不到'链接'属性。 BindingExpression:Path=Link; BindingExpression:路径=链接; DataItem='DataRowView' (HashCode=53681904); DataItem ='DataRowView'(HashCode = 53681904); target element is 'TextBlock' (Name=''); target元素是'TextBlock'(Name =''); target property is 'NoTarget' (type 'Object') target属性是'NoTarget'(类型'对象')

This is expected behaviour, however I'm wondering if there's a way to tell the processor in XAML to only apply if the "Link" property exists (ie. check for the property before attempting to bind, or some other method that doesn't print an error). 这是预期的行为,但是我想知道是否有办法告诉XAML中的处理器仅在“链接”属性存在时才应用(即在尝试绑定之前检查属性,或者某些其他方法没有打印错误)。 Is this possible? 这可能吗?

Both out of the box and directly it is not possible. 开箱即用,直接无法实现。

Not out of the box: you can write your own BindingExtension that would behave like that: bind if the prop exists, else ignore. 不是开箱即用:您可以编写自己的BindingExtension,其行为类似于:如果prop存在则绑定,否则忽略。 You can also, khem, turn off reporting binding error, but of course that is usually not wanted. 你也可以,khem,关闭报告绑定错误,但当然通常不需要。

Not directly: you can create an attached attribute of some type, and then set such attribute instead of setting the binding. 不直接:您可以创建某种类型的附加属性,然后设置此类属性而不是设置绑定。 Your attribute-setter would attach to datacontext-changes and inspect the objects and visual components as they fly around and set the binding or not. 您的属性设置器将附加到datacontext-changes并检查对象和可视组件在它们四处飞行时是否设置绑定。

Not directly#2: You can try to "hierarchize" the styles and triggers. 不直接#2:您可以尝试“层次化”样式和触发器。 As you know, Trigger has a Condition. 如您所知,Trigger有一个条件。 Split your style in two parts: first is the common style that does not need to be "guarded", and the second one contains features dependent on having "Blargh" property. 将你的风格分为两部分:第一部分是不需要“保护”的普通风格,第二部分包含依赖于“Blargh”属性的特征。 Set the first style as default/normal. 将第一个样式设置为默认/正常。 Now create a readonly attached property called "DefinesBlargh" or "HasBlarghDefines" that checks if the target object's datacontext actually has such property. 现在创建一个名为“DefinesBlargh”或“HasBlarghDefines”的只读附加属性,用于检查目标对象的datacontext是否实际具有此属性。 Now add to the first style a trigger that detects whether the styled control has "HasBlarghDefined" equal "true", and in the trigger's action... 现在添加第一个样式的触发器,检测样式控件是否具有“HasBlarghDefined”等于“true”,并在触发器的动作中...

...and here's the problem. ......这就是问题所在。 What to do there? 该怎么办? You cannot replace the style again to the second part of the style, as it probably would remove the trigger and in turn deactivate the logic (it would be one-shot). 你不能再将样式替换为样式的第二部分,因为它可能会删除触发器并反过来停用逻辑(它将是一次性)。 Or, it may simply crash due to the fact of trying to change the style two times in one update sweep. 或者,由于尝试在一次更新扫描中尝试两次更改样式,它可能会崩溃。 I actually not know what would happend, but I sense "a smell". 我其实不知道会发生什么,但我感觉到“有异味”。 More over, changing to the second-part would simply erase the common things that the first part set up. 更重要的是,改为第二部分将简单地抹去第一部分设置的常见事物。

So, if it actually would run and replace the style, you'd have to ENSURE that the original trigger logic and rest of the first style is preserved, I'd suggest using "style inheritace", that is, the based-on style property: http://wpftutorial.net/StyleInheritance.html That is, do not create two separate parts, but rather, make a "base part" with all common things, and a "specialized part" that is based on the first and adds the unsafe extra things. 所以,如果它实际上会运行并替换样式,你必须确保保留原始触发逻辑和第一个样式的其余部分,我建议使用“样式继承”,即基于样式property: http//wpftutorial.net/StyleInheritance.html也就是说,不要创建两个独立的部分,而是创建一个包含所有常见内容的“基础部分”,以及基于第一个和第一个部分的“专用部分”。添加不安全的额外的东西。 Now dynamically re-replacing to the specialized counterpart is a bit more reasonable. 现在动态地重新替换到专门的对应物是更合理的。

Or, if you have some control over the layout, you can get smart: Why apply the two styles to the same component? 或者,如果你对布局有一些控制,你可以变得聪明:为什么要将两种样式应用于同一个组件? Set the general style on some outer bound of the control and place the extra trigger there, and let the trigger apply the small unsafe second style to the control. 在控件的某个外边界上设置常规样式并在其中放置额外的触发器,然后让触发器将小的不安全的第二种样式应用于控件。

If you really have to target exactly one control with both parts of the style and cannot use "based on" or maybe if it simply does not work etc, you can do another smart trick: use a MultiStyle that allows you to define a style that mergers two/three/+ other styles into one, and then build a trigger hierarchy as follows: 如果你真的必须使用样式的两个部分准确地定位一个控件并且不能使用“基于”或者如果它根本不起作用等,你可以做另一个聪明的技巧:使用允许你定义样式的MultiStyle将两个/三个/ +其他样式合并为一个,然后构建一个触发器层次结构,如下所示:

multitrigger
   condition: HasBlarghDefined = TRUE
   condition: your own data condition
   setter: set style = multistyle of "generalpart" and "usnafepart"
multitrigger
   condition: HasBlarghDefined = FALSE
   condition: your own data condition
   setter: set style = just a generalpart

IMHO, that just have to work. 恕我直言,只需要工作。

edit: forgot to past the critical link: The MultiStyle 编辑:忘记过关键链接: MultiStyle

So my final solution for this was to have a base DataGrid class that implements the style in question, minus the "Link" specific data trigger. 所以我的最终解决方案是有一个基本的DataGrid类来实现相关的样式,减去“Link”特定的数据触发器。 Then I had a new DataGrid class that derived from my base class, with code to specifically create the data trigger: 然后我有了一个从我的基类派生的新DataGrid类,其代码专门用于创建数据触发器:

Binding binding = new Binding("Link");
binding.Converter = new MDTCommon.Converters.HasContentConverter();
DataTrigger trigger = new DataTrigger();
trigger.Binding = binding;
trigger.Value = true;
Setter setter1 = new Setter(TextBlock.TextDecorationsProperty, TextDecorations.Underline);
Setter setter2 = new Setter(TextBlock.CursorProperty, Cursors.Hand);
trigger.Setters.Add(setter1);
trigger.Setters.Add(setter2);
Style style = FindResource("DefaultStyleInQuestion") as Style;
style.Triggers.Add(trigger);

I was able to use this method because the binding object that had the "Link" property was only used in my derived DataGrid class. 我能够使用此方法,因为具有“链接”属性的绑定对象仅用于我的派生DataGrid类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM