x:绑定转换器和回退值不协作 (UWP 10)

本文关键字:协作 UWP 绑定 转换器 回退 | 更新日期: 2023-09-27 18:33:09

我有一个涉及一堆代码的问题,但我已经将其隔离开来。如果你想要一个TL;DR;再往下跳。如果你想要一些背景信息,这是我的情况:

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

然后,我创建了一个名为 LocalCacheFile 的 Xaml 资源。一切都像你想象的那样工作。用于此的 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.UnsetValue x:Bind 似乎无法处理。

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

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:我应该补充一点,如果我将转换函数更改为返回 null 而不是 DependencyProperty.UnsetValue,x:Bind函数,但x:BindBinding都没有完成他们预期的使用FallbackValue

x:绑定转换器和回退值不协作 (UWP 10)

Bindingx:Bind 中的FallbackValue是不同的。

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

绑定在以下情况下使用 FallbackValue :Path 根本不对数据源进行计算,或者尝试使用双向绑定在源上设置路径会引发数据绑定引擎捕获的异常。如果源值是依赖项属性哨兵值 DependencyProperty.UnsetValue,则也使用 FallbackValue

但在 x:Bind 中,FallbackValue指定在无法解析源或路径时要显示的值。它不能与DependencyProperty.UnsetValue一起使用。

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

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

如果您在Converter中返回DependencyProperty.UnsetValue,它将抛出异常,因为DependencyProperty.UnsetValue无法投射到ImageSource

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

TargetNullValue 是具有类似方案的类似属性。区别在于,如果路径和源确实计算,但在那里找到的值为 null,则绑定使用 TargetNullValue

例如,使用以下代码是 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}}" />

x:Bind中,FallBackValue实际上仅用于设计时数据。现在,让我们谈谈更重要的事情。为什么要使用 x:Bind .以旋转IValueConverter的成本,您确信x:Bind值得吗?我不是。当我看到开发人员努力让x:Bind在列表之外正确处理绑定时,我的建议是切换到 binding 。每次。在列表中,编译绑定具有"重复"值,但在其他任何地方,您必须向我证明值得付出努力 - 如果它在其他方面很困难。通常x:bind很棒。但是在这种情况下,像UpdateSourceTrigger回退或默认binding的情况是完全可以的。