I get this error when starting the UWP app. It's failing to find the FirstNameToVisibilityConverter resource. I would really appreciate it if someone could identify why I get this error, or post a small working sample of a UWP app using a converter. Thanks!
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>
Code Behind:
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();
}
}
}
This is because you're using the compile-time binding extension {x:Bind}
instead of the run-time binding extension {Binding}
, combined with the fact that the XAML compiler handles the Converter
property as a special case, generating an explicit LookupConverter()
method for finding the converter:
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]);
}
While the normal resource lookup rules would traverse the object tree, checking each parent recursively until it found a resource of the given name, as you can see above the explicitly-generated method bypasses the ResourceDictionary
behavior, and only looks in the root-level Resources
(i.e. the UserControl
object's Resources
), or the application Resources
.
So, you need to declare your converter resource in one of those locations. For example:
<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>
Another alternative would be to put the resource in the App.xaml file, in the <Application.Resources/>
element, or of course to use the {Binding}
extension instead, which does go through the normal resource lookup process.
Addendum:
Personally, I feel this is a bug in the platform. The generated code-behind is accessing the framework elements anyway, so it should not be difficult to provide an implementation that would traverse the tree just as the run-time based {Binding}
would. Some degree of limitation is understandable, but an arbitrary inconsistency like this just makes it harder to transfer WPF skills to Winrt/UWP.
As such, I went ahead and opened a bug on the Connect site: x:Bind doesn't find converter resource. I'm guessing Microsoft will disagree, but at the very least if we're lucky they will a) provide some rationale for the implementation decision, and b) change the documentation so that this limitation is called out clearly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With