I am trying to add a custom converter (Boolean to Visibility). The code for the converter is just fine. It seems to map ok. However, when I try and add it as a resource for a User Control I get an Invalid Markup which says "BooleanToVisibilityConverter was not found. Verify you are not missing an assembly and that all referenced assemblies have been built". Even with this Invalid Markup showing the project compiles and runs with no errors or crashes.
I am using Visual Studio 2013 on Windows 8.1
converter .h file:
#pragma once
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Interop;
namespace BooleanConverter{
public ref class BooleanToVisibilityConverter sealed : IValueConverter
{
public:
virtual Platform::Object^ Convert(
Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object^ parameter,
Platform::String^ language);
virtual Platform::Object^ ConvertBack(
Platform::Object^ value,
Windows::UI::Xaml::Interop::TypeName targetType,
Platform::Object^ parameter,
Platform::String^ language);
};
}
converter .cpp file:
#include "pch.h"
#include "BooleanToVisibilityConverter.h"
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Data;
Object^ BooleanConverter::BooleanToVisibilityConverter::Convert(Object^ value, TypeName targetType, Object^ parameter, String^ language)
{
auto boxedBool = dynamic_cast<Box<bool>^>(value);
auto boolValue = (boxedBool != nullptr && boxedBool->Value);
return (boolValue ? Visibility::Visible : Visibility::Collapsed);
}
Object^ BooleanConverter::BooleanToVisibilityConverter::ConvertBack(Object^ value, TypeName targetType, Object^ parameter, String^ language)
{
throw ref new Platform::NotImplementedException();
}
the xaml code:
<UserControl
x:Class="SimpleShop.JobItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:SimpleShop"
xmlns:converters="using:BooleanConverter"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Width="1030" Height="Auto" Background="Black">
<UserControl.Resources>
<ResourceDictionary>
<converters:BooleanToVisibilityConverter x:Key="BooleanToCollapesdConverter"/>
</ResourceDictionary>
</UserControl.Resources>
I've tried changing the xmlns statement to:
xmlns:converters="clr-namespace:BooleanConverter"
but that throws up errors saying the BooleanConverter namespace can not be found
The really odd part is that if I delete the xmlns statement and re-type it in, intellisense says that the namespace can not be found. However if I simply copy and paste that line back over its self the error on the xmlns statement goes away.
How do I get rid of this Invalid Markup which doesn't seem to be invalid at all since it compiles and runs. Or have I missed something in implementing this converter? I am using MSDN as a reference (http://msdn.microsoft.com/en-us/library/ms747086(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1) and, to me, it doesn't look like I've implemented this wrong.
Please let me know if I need to supply more code but I believe this is everything that is relevant.
WinRT namespace lookup rules require that all namespaces published by a winmd live in a winmd with the same name (or a root namespace name). That is, a class named "MyNamespace.MySubNamespace.MyClass" must live in either MyNamespace.winmd or MyNamespace.MySubNamespace.winmd, otherwise it cannot be reliably found by all type loaders.
I think your issue is that your namespace is ::Converters, but your boolean converter class is probably hiding inside SimpleShop.winmd. I would try changing the namespace (and references) to SimpleShop::Converters and see if this resolves your issue.
Related
I have a WinUI 3 app where we use Dependency-Injection from Microsoft.Extensions, and settings containing DateTime the current Date-Time formatting have been registered to the service collection as followed:
services.AddSingleton<IDateFormatService, DateFormatService>();
I'd like to just inject it into the constructor of the IValeConverter, but as it is constructed by the XAML the constructor must be empty.
Below is my current converter
public sealed class DateTimeFormatingConverter : DependencyObject, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is not DateTime dateTime)
return value;
// return formatted dateTime based on settings formatting string
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
I know other injection libraries can allow this, as I've seen in this post and there for wondered if a likewise solution exist with the Microsoft extensions version.
I know it's a possibility to make a DependencyProperty and in XAML bind it to the dependency injected property in the viewmodel. However im looking into this as it would clean up the code substantially and while also removed multiple requirements from the converter that another developer won't easily know would be required.
I'd like to just inject it into the constructor of the IValeConverter, but as it is constructed by the XAML the constructor must be empty.
Correct.
The XAML processor engine doesn't know how to use Microsoft.Extensions to resolve dependencies so if you want to inject your converter with a constructor dependency that you register yourself, you must construct the converter programmatically (and not define it in the XAML markup).
You could for example do this in App.xaml.cs after you have registered the dependencies, e.g.:
this.Resources.Add("myConverter",
services.GetRequiredService<DateTimeFormatingConverter>());
I have a IValueConverter that has a System.Type property which is set in XAML.
Converter:
internal class EnumTypeConverter : IValueConverter
{
public Type TypeToDisplay { get; set; }
public object Convert(object value, Type targetType, object parameter, string language)
{
return TypeToDisplay?.FullName;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
XAML:
<Page
x:Class="UWPSystemTypeConverterTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converter="using:UWPSystemTypeConverterTest.Converter"
xmlns:enums="using:UWPSystemTypeConverterTest.Enum"
mc:Ignorable="d">
<Page.Resources>
<converter:EnumTypeConverter x:Key="Converter" TypeToDisplay="enums:CustomEnum" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="{Binding Converter={StaticResource Converter}}" />
</Grid>
</Page>
When I run the application, I get following error:
Windows.UI.Xaml.Markup.XamlParseException: 'The text associated with
this error code could not be found.
Failed to create a
'UWPSystemTypeConverterTest.Converter.EnumTypeConverter' from the text
'enums:CustomEnum'. [Line: 14 Position: 56]'
If I add a property of type CustomEnum to the code- behind file, which is never used, the application works.
the changed code- behind- File:
public sealed partial class MainPage : Page
{
public CustomEnum WithThisPropertyTheAppWorks { get; set; }
public MainPage()
{
InitializeComponent();
this.DataContext = this;
}
}
The complete project for reproduction is here: https://github.com/SabotageAndi/UWPSystemTypeConverterTest
Line to uncomment is https://github.com/SabotageAndi/UWPSystemTypeConverterTest/blob/master/UWPSystemTypeConverterTest/MainPage.xaml.cs#L13
I suspect that an optimiser of UWP is causing this problem.
Is this really the case?
How can I fix the error without the unused property in the code-behind file?
Targeting UWP Build 10240, a viable work around is to add a dummy instance of the targeted enum in static resources of the page before instantiating the converter.
<Page.Resources>
<enums:CustomEnum x:Key="WorkAround">CustomEnumValue</enums:CustomEnum>
<converter:EnumTypeConverter x:Key="Converter" TypeToDisplay="enums:CustomEnum" />
</Page.Resources>
Info from a MSFT employee on a MVP mailing list:
This behaviour is a current limitation of UWP.
The XAML compiler and the runtime don't support System.Type- typed properties. So the needed metadata is not generated and the runtime can not convert the string to the type.
But because of the public properties on the code-behind, the compiler generates the needed metadata now. I am not that happy with the work around, but it is better than other solutions (e.g. a string property with the fullname to the type).
I'm creating an application that will be build in modules (DLL's). One of these DLL's provides the Strings for the application in different languages.
The DLL has following structure:
Languages (This is the project.)
Properties
References
Language.cs (Here I'm able to set the desired language from the application and has a GetText function that returns the String based on the set Culture.) Please let me know is this is a good approach.
Language.en-US.resx
Language.nl-BE.resx
So, from Languages.cs I'm able to get the desired String in C# from the resource files based on the set Culture.
Here is an example:
I set the culture to Dutch: Languages.Language.SetCulture("nl-BE");
I request the Dutch word for the resource Name: Language.GetText("Name");
It will return the String Naam.
That was C#. Xaml appears to be a bigger problem to get a Label.Text get the resource Name.
I added xmlns:l="clr-namespace:My.Languages.;assembly=My.Languages" to my xaml file, but this is as far as I got. I can't figure out a way how to have a similar Language.GetText("Name") in Binding.
My only solution at this point would be to bind every Label.Text to a property in my C# code and get the correct String from there. This will generate a lot of "not needed" binding/properties and would be hard to maintain.
Any suggestions?
My approach for Xaml would be to use a Converter that would call your Language.GetText(key);
e.g. XAML
<TextBlock Text={Binding FallbackValue='Naam', ConverterParameter='Name' Converter={StaticResource Translate}}" />
C#
public class TranslateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
return DependencyProperty.UnsetValue;
string localizedValue = string.Empty;
if (parameter is string)
{
localizedValue = Language.GetText(parameter as string);
return localizedValue;
}
else
{
return DependencyProperty.UnsetValue;
}
}
}
I got the following code:
namespace SomeApp
{
public partial class MyClass : PhoneApplicationPage, IValueConverter
{
SOME METHODS...
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return true;
}
}
}
I would like to bind this class to a ValueConverter of a RadioButton. Is there any way to reference to the current class I'm working with? For example:
<phone:PhoneApplicationPage
x:Class="SomeApp.MyClass"
xmlns:local="clr-namespace:SomeApp">
<phone:PhoneApplicationPage.Resources>
<local:MyClass x:Key="myClass"/>
</phone:PhoneApplicationPage.Resources>
<RadioButton IsChecked="{Binding Converter={StaticResource myClass}}"/>
Thanks in advance =)
First using your page as a converter don't seem like a good idea, it's better practice to separate the converter fonctionality in a separate class. Particularly it would be a very bad idea to create a StaticResources of a converter created that way as it will use a lot of unessessary memory to create the whole page.
The only thing a converter can be binded in xaml is a StaticResource so you will not be able to do it in xaml but if you really want to do it you could do it by creating the binding from code behind (for example in the constructor of the page):
Binding binding=new Binding();
binding.Converter = this;
myRadioButton.SetBinding(CheckBox.IsCheckedProperty, binding);
Sorry for the F#...
I have a VS project with the following class:
namespace ABCCommonSilverlight
module ConvertersAndFormatters =
type FixedDecimalConverter () =
interface IValueConverter with
member this.Convert(value, targetType, parameter, culture) =
if value = null then
"N/A" :> obj
else
(decimalFormatter (value :?> Double)) :> obj
member this.ConvertBack(value, targetType, parameter, culture) = raise <| NotImplementedException()
And I've referenced this project in another project which has a XAML resources file which looks like this...
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:y="clr-namespace:ABCCommonSilverlight;assembly=ABCCommonSilverlight">
<y:ConvertersAndFormatters.FixedDecimalConverter x:Key="abcFixedDecimalConverter" />
</ResourceDictionary>
Without the ConvertersAndFormatters. in front of FixedDecimalConverter I get:
Exception "The type 'FixedDecimalConverter' was not found."
And with the "ConvertersAndFormatters." I get:
Exception "Cannot set properties on property elements."
Any idea what the right way to do this is?
The first thing I would try is moving the FixedDecimalConverter type out of the module, so that it's sitting directly in a namespace. (Right now the CLI and XAML see it as a nested class inside the module class.)