7

我有一个涉及大量代码的问题,但我已将其隔离。如果你想要一个 TL;DR; 再往下跳。如果您想要一些上下文,这是我的情况:

我为绑定创建了三个数据转换器。其中之一是“字符串前缀”:它为您输入的任何内容添加一个固定字符串的前缀。在当前示例中,该固定字符串是"ms-appx:///cache/". 第二个将stringtype 转换为ImageSource,第三个将多个转换器链接在一起。

然后我创建了一个名为LocalCacheFile. 一切都如您所想。用于此的 Xaml 代码如下所示:

<Image Source="{x:Bind imageSource,Converter={StaticResource LocalCacheFile}}" />

但是,我遇到了以下问题。如果我尝试使用 FallbackValue 为imageSource空时放置一个占位符图像,我只会得到奇怪的行为x:Bind

以下代码按预期工作:

<Image Source="{Binding imageSource,FallbackValue='ms-appx:///Assets/default.png',Converter={StaticResource LocalCacheFile}}" />

<Image Source="{x:Bind imageSource,FallbackValue='ms-appx:///Assets/default.png',Converter={StaticResource LocalCacheFile}}" />

才不是!

我已将其隔离为仅一个转换器,并且DependencyProperty.UnsetValuex:Bind 似乎没有处理。

TL;博士; 这是我的字符串前缀的代码,如果我单独使用它作为测试会触发相同的错误行为:

public class StringPrefix : IValueConverter
{
    public string prefix { get; set; }

    public object Convert(object value, Type typeName, object parameter, string language)
    {
        if (value == DependencyProperty.UnsetValue || value == null || (string)value == "")
            return DependencyProperty.UnsetValue ;

        return (prefix + value.ToString());
    }

    public object ConvertBack(object value, Type typeName, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

当使用Binding. 与 .一起使用时会引发类型异常x:Bind

这是怎么回事?


编辑:有关异常的详细信息。

这是生成的代码:

        private void Update_project_imageSource(global::System.String obj, int phase)
        {
            if((phase & ((1 << 0) | NOT_PHASED | DATA_CHANGED)) != 0)
            {
                XamlBindingSetters.Set_Windows_UI_Xaml_Controls_Image_Source(this.obj16, (global::Windows.UI.Xaml.Media.ImageSource)this.LookupConverter("LocalCacheFile").Convert(obj, typeof(global::Windows.UI.Xaml.Media.ImageSource), null, null), null);
            }
        }

异常详情:

System.InvalidCastException was unhandled by user code
  HResult=-2147467262
  Message=Unable to cast object of type 'System.__ComObject' to type 'Windows.UI.Xaml.Media.ImageSource'.
  Source=Test
  StackTrace:
       at Test.Pages.ProjectView.ProjectView_obj1_Bindings.Update_project_imageSource(String obj, Int32 phase)
       at Test.Pages.ProjectView.ProjectView_obj1_Bindings.Update_project(Project obj, Int32 phase)
       at Test.Pages.ProjectView.ProjectView_obj1_Bindings.Update_(ProjectView obj, Int32 phase)
       at Test.Pages.ProjectView.ProjectView_obj1_Bindings.Update()
       at Test.Pages.ProjectView.<.ctor>b__6_0(FrameworkElement s, DataContextChangedEventArgs e)
  InnerException: 

(对我来说,看起来生成的代码只是不处理默认值的可能性。顺便说一句,那__ComObjectDependencyProperty.UnsetValue.

编辑 2:我应该补充一点,如果我将 Convert 函数更改为返回 null 而不是 DependencyProperty.UnsetValue,x:Bind则函数,但是既不x:Bind也不Binding做他们预期的使用FallbackValue

4

2 回答 2

7

FallbackValueinBindingx:Bind是不同的。

Binding,FallbackValue是绑定无法返回值时使用的值。

对于Path根本不在数据源上评估的情况,或者如果尝试使用双向绑定在源上设置它会引发数据绑定引擎捕获的异常,则绑定使用FallbackValue 。如果源值是依赖属性标记值DependencyProperty.UnsetValue ,也会使用FallbackValue

但在 中x:BindFallbackValue指定了在无法解析源或路径时显示的值。它不能与DependencyProperty.UnsetValue.

如您所知,x:Bind在编译时生成代码并且它是强类型的。当您使用Converterin 时x:Bind,它会将Converter' 的返回值视为与目标属性相同类型的值,并像在您的代码中一样对其进行强制转换:

(global::Windows.UI.Xaml.Media.ImageSource)this.LookupConverter("LocalCacheFile").Convert(obj, typeof(global::Windows.UI.Xaml.Media.ImageSource), null, null)

如果你返回DependencyProperty.UnsetValue你的Converter,它会抛出异常,因为DependencyProperty.UnsetValue不能转换为ImageSource.

对于您的方案,您可以使用TargetNullValue.

TargetNullValue是具有类似场景的类似属性。不同之处在于,如果 Path 和 Source 确实计算,则绑定使用TargetNullValue,但找到的值为 null。

例如使用以下代码是 XAML。

<Image Source="{x:Bind imageSource, TargetNullValue='ms-appx:///Assets/default.png', Converter={StaticResource LocalCacheFile}}" />

而在Convert, 中返回null而不是DependencyProperty.UnsetValue.

这在运行应用程序并且imageSource为空时有效。但是为了获得设计时间的好处,我们仍然需要使用FallbackValue. 所以我们可以x:Bind像下面这样使用:

<Image Source="{x:Bind imageSource, TargetNullValue='ms-appx:///Assets/default.png', FallbackValue='ms-appx:///Assets/default.png', Converter={StaticResource LocalCacheFile}}" />
于 2016-02-05T07:42:15.503 回答
4

实际上只用于设计时数据x:BindFallBackValue现在,让我们谈谈更重要的事情。为什么使用x:Bind. 以旋转的成本IValueConverter,您确信x:Bind值得吗?我不是。当我看到开发人员x:Bind为列表之外的绑定而努力工作时,我的建议是切换到binding. 每次。在列表中,已编译绑定具有“重复”值,但在其他任何地方,您必须向我证明这是值得的努力——如果这很困难的话。通常x:bind很棒。但是在这样的情况下,以及像UpdateSourceTrigger回退到或默认到这样的情况binding是完全没问题的。

于 2016-02-07T06:17:20.593 回答