x:绑定转换器和FallbackValue不协作(UWP 10)

MB.*_*MB. 4 c# winrt-xaml winrt-xaml-toolkit uwp

我有一个涉及大量代码的问题,但我把它隔离了.如果你想要TL; DR; 进一步向下跳.如果你想要一点上下文,这是我的情况:

我为我的绑定创建了三个数据转换器.其中一个是"字符串前缀":它为使用固定字符串放入的任何内容添加前缀.在当前示例中,该固定字符串是"ms-appx:///cache/".第二个将string类型转换为a ImageSource,第三个将多个转换器链接在一起.

然后我创建了一个名为Xaml的资源LocalCacheFile.一切都按照您的想法运作.Xaml代码看起来像这样:

<Image Source="{x:Bind imageSource,Converter={StaticResource LocalCacheFile}}" />
Run Code Online (Sandbox Code Playgroud)

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

以下代码可以正常工作:

<Image Source="{Binding imageSource,FallbackValue='ms-appx:///Assets/default.png',Converter={StaticResource LocalCacheFile}}" />
Run Code Online (Sandbox Code Playgroud)

<Image Source="{x:Bind imageSource,FallbackValue='ms-appx:///Assets/default.png',Converter={StaticResource LocalCacheFile}}" />
Run Code Online (Sandbox Code Playgroud)

才不是!

我把它分离到只有一个转换器,它是DependencyProperty.UnsetValuex:Bind似乎没有处理.

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用时,上述转换器的工作方式与您预期的一样(即,如果输入字符串为空,则回退值已正确使用)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);
            }
        }
Run Code Online (Sandbox Code Playgroud)

例外细节:

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: 
Run Code Online (Sandbox Code Playgroud)

(对我来说,看起来生成的代码只是不处理默认值的可能性.顺便说一下,__ComObject就是这样DependencyProperty.UnsetValue.

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

Jay*_*Zuo 5

FallbackValueBindingx:Bind是不同的.

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

对于Path根本不对数据源进行求值的情况,或者如果尝试使用双向绑定在源上设置它,则绑定使用FallbackValue会抛出数据绑定引擎捕获的异常.如果源值是依赖属性Sentinel值DependencyProperty.UnsetValue,则还使用FallbackValue.

但是x:Bind,FallbackValue指定在无法解析源或路径时显示的值.它无法使用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)
Run Code Online (Sandbox Code Playgroud)

如果你返回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}}" />
Run Code Online (Sandbox Code Playgroud)

而在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}}" />
Run Code Online (Sandbox Code Playgroud)