WinRT信息:无法找到具有给定键的资源.转换器参考的问题

本文关键字:资源 转换器 问题 参考 信息 WinRT | 更新日期: 2023-09-27 18:09:11

当启动UWP应用程序时,我得到这个错误。它无法找到FirstNameToVisibilityConverter资源。如果有人能找出为什么我得到这个错误,或者发布一个使用转换器的UWP应用程序的小工作样本,我会非常感激。谢谢!

XAML:

<UserControl
    x:Class="MyHelloWorld.HelloWorld"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyHelloWorld"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">
<Grid>
    <Grid.Resources>
        <local:FirstNameToVisibilityConverter x:Key="FirstNameToVisibilityConverter"/>
        <p:Style TargetType="TextBox">
            <Setter Property="HorizontalAlignment" Value="Center"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
        </p:Style>
    </Grid.Resources>
    <StackPanel>
        <TextBlock Foreground="Red">HI</TextBlock>
        <TextBlock Foreground="Red">THERE</TextBlock>
        <TextBox Foreground="Red" Text="{x:Bind FirstWord}"/>
        <TextBlock Foreground="Red" Text="{x:Bind SecondWord}" Visibility="{x:Bind FirstWord, Converter={StaticResource FirstNameToVisibilityConverter}}"/>
        <CheckBox Foreground="Red" Content="Click me to hide the first word" IsChecked="{x:Bind FirstWordChecked}"/>
    </StackPanel>
</Grid>

背后的代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace MyHelloWorld
{
    public sealed partial class HelloWorld : UserControl
    {
        public string FirstWord { get; set; }
        public string SecondWord { get; set; }
        public bool? FirstWordChecked { get; set; }
        public HelloWorld()
        {
            this.InitializeComponent();
        }
    }
    public class FirstNameToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if ((string)value == "Today") return Visibility.Collapsed;
            return Visibility.Visible;
        }
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }  
}

WinRT信息:无法找到具有给定键的资源.转换器参考的问题

这是因为您正在使用编译时绑定扩展{x:Bind}而不是运行时绑定扩展{Binding},结合XAML编译器将Converter属性作为特殊情况处理的事实,生成用于查找转换器的显式LookupConverter()方法:

public global::Windows.UI.Xaml.Data.IValueConverter LookupConverter(string key)
{
    if (this.localResources == null)
    {
        global::Windows.UI.Xaml.FrameworkElement rootElement;
        this.converterLookupRoot.TryGetTarget(out rootElement);
        this.localResources = rootElement.Resources;
        this.converterLookupRoot = null;
    }
    return (global::Windows.UI.Xaml.Data.IValueConverter) (this.localResources.ContainsKey(key) ? this.localResources[key] : global::Windows.UI.Xaml.Application.Current.Resources[key]);
}

正常的资源查找规则将遍历对象树,递归地检查每个父类,直到找到给定名称的资源,正如您在上面看到的那样,显式生成的方法绕过ResourceDictionary行为,只查看根级Resources(即UserControl对象的Resources)或应用程序Resources

因此,您需要在其中一个位置声明您的转换器资源。例如:

<UserControl
    x:Class="TestSO39734815UwpResource.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestSO39734815UwpResource"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">
  <UserControl.Resources>
    <local:FirstNameToVisibilityConverter x:Key="FirstNameToVisibilityConverter"/>
  </UserControl.Resources>
  <Grid>
    <Grid.Resources>
      <p:Style TargetType="TextBox">
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
      </p:Style>
    </Grid.Resources>
    <StackPanel>
      <TextBlock Foreground="Red">HI</TextBlock>
      <TextBlock Foreground="Red" Text="THERE"/>
      <TextBox Foreground="Red" Text="{x:Bind FirstWord}"/>
      <TextBlock Foreground="Red" Text="{x:Bind SecondWord}"
                 Visibility="{x:Bind FirstWord, Converter={StaticResource FirstNameToVisibilityConverter}}"/>
      <CheckBox Foreground="Red" Content="Click me to hide the first word" IsChecked="{x:Bind FirstWordChecked}"/>
    </StackPanel>
  </Grid>
</UserControl>

另一种选择是将资源放在App.xaml文件中,在<Application.Resources/>元素中,当然也可以使用{Binding}扩展名,这将经历正常的资源查找过程。


附录:

我个人认为这是平台上的一个bug。生成的后台代码无论如何都要访问框架元素,因此提供一个像基于运行时的{Binding}那样遍历树的实现应该不难。某种程度的限制是可以理解的,但是像这样任意的不一致只会使将WPF技能转移到Winrt/UWP变得更加困难。

因此,我继续在Connect站点上打开一个错误:x:Bind找不到转换器资源。我猜微软会不同意,但至少如果我们幸运的话,他们会a)为实现决策提供一些基本原理,b)更改文档,以便清楚地指出这一限制。