I am localizing a WPF application. The datagrid columns headers needs to be changed at runtime according to the specific UI culture in the XAML.
Though I am able to do the localization in the code behind and also in XAML by using the LocBaml tool. I am not able to achieve it with one particular scenario in the XAML. The scenario is that I am parsing XAML, as I am loading it in an XML file and parsing..
So now when I parse it like:
<dg:DataGridColumnHeader Header="{x:Static findlocale:My.Resources.String.anylocalword}"></dg:DataGridColumnHeader>
Where findlocale is the XAML namespace keyword, I am getting an error:
XAML parse error. Cannot find type My.Resources.String.localword in
the xaml namespace.
Why is this not working in this scenario? How do I overcome it?
I'm willing to bet your findlocale XML namespace is incorrect. If you have something like:
namespace MyNameSpace.MySubNamespace {
public class MyClass {
public static string MyProperty { get; set; }
}
}
Then your XML namespace must be declared like xmlns:findlocale="clr-namespace:MyNameSpace.MySubNamespace" in order to use {x:Static findlocale:MyClass.MyProperty}.
You cannot declare your XML namespace like xmlns:findlocale="clr-namespace:MyNameSpace" and use it like {x:Static findlocale:MySubNamespace.MyClass.MyProperty}.
Also, if you have any nested classes/enums, then you must use a + sign in place of the .. So if you had:
namespace MyNameSpace.MySubNamespace {
public class MyClass {
public class MyNestedClass {
public static string MyProperty { get; set; }
}
}
}
To access MyProperty, you'd need to declare your XML namespace like xmlns:findlocale="clr-namespace:MyNameSpace.MySubNamespace" and access it like {x:Static findlocale:MyClass+MyNestedClass.MyProperty}.
Related
I'm trying to implement my own Translator using Converters. In the converter I call a static class containing translations. This translations are loaded when application starts.
The main advantage using this converters for me are three:
I translate texts in runtime, based on XML language files.
When executing application I register text without translation in other XML file, so I can later add the translation.
Translations are applied also to data when desired.
All works fine when the text to translate comes from a binded property, per example:
<TextBox Grid.Row="1" Text="{Binding NameToShow, Converter={StaticResource TranslationConverter}}"></TextBox>
The problem is translating static text like labels, button content... The idea is making something like this:
<Button Content={Binding "MyText",Converter={StaticResource TranslationConverter}} Command="{Binding InitializeAdapterCommand}"></Button>
Obviously, I want neither to declare static strings in resources or to use bindable properties.
Any suggestions?
you can use Binding.Source property to pass a const value to a converter:
Text="{Binding Source='My Text', Converter={StaticResource TranslationConverter}}"
You can create your own MarkupExtension instead of relying on Bindings:
public class StaticTranslation : MarkupExtension
{
public StaticTranslation()
{
}
public StaticTranslation(string textToTranslate)
{
TextToTranslate = textToTranslate;
}
public string TextToTranslate { get; set; }
public IValueConverter Converter { get; set; }
public object ConverterParameter { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (Converter != null)
{
return Converter.Convert(TextToTranslate, typeof(string), ConverterParameter, CultureInfo.CurrentUICulture);
}
return TextToTranslate;
}
}
And use it with lib being the xmlns:lib=[namespace containing StaticTranslation]
<TextBlock Text="{lib:StaticTranslation 'ABC',Converter={StaticResource TranslationConverter}}"/>
Ofcourse the converter usage in StaticTranslation is just an example. You may want to test / improve the code for production usage.
Side note:
If you get an error when nesting Converter={StaticResource TranslationConverter}, move your markup extension to a separate class library project. See the following: https://stackoverflow.com/a/11785549/5265292
I'm wondering if there is a way to use a custom markup extension on a custom property on a type derived from datatemplate?
I need some additional information inside my DataTemplates:
public class MyDataTemplate : DataTemplate
{
public string GroupName { get; set; }
public string TemplateKey { get; set; }
public object Geometry { get; set; }
}
<MyDataTemplate x:Key="Foo" DataType="{x:Type system:String}" GroupName="Group1"
Geometry="{telerik:CommonShape ShapeType=RectangleShape}">
...
</MyDataTemplate>
When I put the CommonShape markupextension on the DataType property, everything works.
When I put the x:Type markupextension on the Geometry property, everything works, too.
But if I put the custom markupextension on the custom property, I get the error
The property 'Geometry' cannot be set as a property element on template.
Only Triggers and Storyboards are allowed as property elements.
Is there any workaround for this?
Alex
Edit:
One possible workaround could be to put the values of the markupextension into the resource dictionary and use a StaticResource on the Geometry property - however, I'm not sure if this is possible using xaml?
Is it possible to introduce 'custom' attributes into different UI Elements in XAML ? Also to read them later like we add attributes for server controls in ASP.NET ?
I intend to read specific attributes and operate on them together.
It sounds like you're trying to find Attached Properties.
An attached property lets you add in a property, definable in Xaml, which can be "attached" to any UIelement. You then retrieve them in code like any other Dependency Property.
Here is the approach I tend to take with this.
Create a new class file called Meta:-
namespace SilverlightApplication1
{
public static class Meta
{
#region SomeValue
public static string GetSomeValue(DependencyObject obj)
{
return (string)obj.GetValue(SomeValueProperty);
}
public static void SetSomeValue(DependencyObject obj, string value)
{
obj.SetValue(SomeValueProperty, value);
}
public static readonly DependencyProperty SomeValueProperty =
DependencyProperty.RegisterAttached("SomeValue", typeof(string), typeof(Meta),
new PropertyMetadata(null));
#end region
#region SomeOtherValue
// Boilerplate code from above.
#end region
}
}
A value can now be attached in XAML like this:-
<TextBox x:Name="txt" local:Meta.SomeValue="Hello, World!" />
At some point in code this value can be retrieved with:-
string value = Meta.GetSomeValue(txt);
Note you don't have to stick with String as the type of the property you can pretty much use any type you like with the limitation that if you can to attach it in XAML the type must be compatible with the way XAML constructs objects (for example requires a default constructor).
The way I've accomplished that is by creating a new class that inherits the base control.
For example, I have a class called WebTextBox that inherits TextBox. And inside WebTextBox are some custom properties and events. By doing this you're inheriting all the behaviors of the TextBox control. But you can get creative here if you choose, even modifying the behavior by overriding events and such.
Anyway, after you create the class you'll then have to add the namespace for the project to the XAML. Something like this:
xmlns:me="clr-namespace:YourNamespace;assembly=YourAssembly"
And then you can add a WebTextBox (or whatever you call it) like this:
<me:WebTextBox CustomAttribute="cool stuff" />
Is it possible to have a DependencyProperty within a MarkupExtension derived class?
public class GeometryQueryExtension : MarkupExtension
{
public XmlDataProvider Source { get; set; }
public string XPath { get; set; }
public static readonly DependencyProperty ArgumentProperty = DependencyProperty.RegisterAttached(
"Argument",
typeof(string),
typeof(GeometryQueryExtension)); // this wont work because GeometryQueryExtension is not a DependencyProperty
public string Argument
{
get
{
return (string)GetValue(ArgumentProperty); // this wont even compile because GeometryQueryExtension doesnt derive from a class which has GetValue
}
set
{
SetValue(ArgumentProperty,value);// this wont even compile because GeometryQueryExtension doesnt derive from a class which has SetValue
}
}
}
The extension is used in the following snippet.
<Label.Content>
<local:GeometryQueryExtension Source="{StaticResource shapesDS}">
<local:GeometryQueryExtension.XPath>
/Shapes/Geometry/{0}
</local:GeometryQueryExtension.XPath>
<local:GeometryQueryExtension.Argument>
<Binding XPath="Geometry"/> <!-- will throw exception when processing this bind -->
</local:GeometryQueryExtension.Argument>
</local:GeometryQueryExtension>
</Label.Content>
Is it even possible to build such an extension or am i just barking up the wrong tree ?
(the code above wont compile and run, but i posted it here to best illustrate the problem).
No, you can only add dependency properties to classes that are derived from DependencyObject, MarkupExtention is derived directly from Object
Yea.. it’s an ugly problem.. However it has a simple non intuitive answer.
Create another markup extension to get the static resource.
So instead of using {StaticResource shapesDS}
You would create a new MarkupExtension called DataSetLocator
I'm not going to write the code but the Provide value would need to return your dataset based on a name or some other input.
Then you change your xaml to have your extension use the dataset locator extension example Source="{DataSetLocator name=shapesDS }"
It’s too bad that extensions don’t extend DependencyProperty but they don’t.
Just use IMarkupExtension instead of MarkupExtension and you can extend DependencyObject. At least in Silverlight 5 you can, but I would assume WPF also has it.
I have the following class,
internal class PageInformation
{
public string Name
{
get;
set;
}
public Uri PageUri
{
get;
set;
}
}
How can I use it in XAML (a page) and assign values to its properties?
Update-1:
I added xmlns attribute in page tag
<Page xmlns:local="clr-namespace:Demo.Pages">
and inherited PageInformation from DependencyObject (to have dependency properties).
Still XAML does not recognize the PageInformation class
I was trying to use PageInformation element in a Canvas. Since it is not a UIElement, I think, It can't be added there.
I can use it as a resource element instead (in Page.Resources) :)