How to combine binding from custom data context with custom markup - wpf

I want to combine binding from my custom data context which contains ViewModel class and ResourceProvider class. Custom data context is set as window DataContext.
I use it that way:
<Button x:Name="btnShow" Content="Show" Command="{Binding View.HandleShow}"/>
Which View is property from dataContext. I want to use localization by custom data context using minimum markup and set ResourceProvider from other source in code that I created my own data context
Is there any possibility to do it in something which is similar to that line of code:
<TextBlock Text="{Binding Res.Key=test}" />
My resource provider inherits from markup extension with one Property: Key.
Thanks for any advice

You can create a custom markup extension using the following code :
public class LocalizedBinding : MarkupExtension
{
public String Key { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
//use target.TargetObject and target.TargetProperty to provide value based on Key
}
}
and use it like :
<TextBlock Text="{local:LocalizedBinding Key=SomeKey}" />

I try that solution but i prefer avoid prefix local because localizedBinding came from different source and use IoC pattern because of that I create CustomDataContext

Related

WPF Converter Static Text

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

Why WPF user control properties must be public to use them from XAML?

I'm working on a WPF custom control. The control has a property that is set in code behind and used in XAML. This property must be public for it work on XAML via a Binding. Why is this, if there is just one class?
<TextBlock Text="{Binding ElementName=PolicyBoxName, Path=FileNames[0]}" />
private string[] _fileNames;
public string[] FileNames
{
get
{
return _fileNames;
}
set
{
if (value != _fileNames)
{
_fileNames = value;
OnPropertyChanged("FileNames");
}
}
}
The XAML parsers constructs objects based on the supplied XML and sets their properties. It is no different from any other class, from a different namespace, that might wish to create your user control and set its properties. Without reflection, the constraints of the C# language demand that these properties are public for them to be set.

Why does data binding to DynamicResource not work?

The following code does not work. How do I make it work?
<Image Source="{DynamicResource {Binding VM.ImageKey}}" />
This is an incorrect usage of the DynamicResource MarkupExtension. Correct it would be:
<Image Source="{DynamicResource VM.ImageKey}" />
Assuming you have a resource with a key "VM.ImageKey" defined somewhere like this:
<Bla.Resources>
<BitmapImage x:Key="VM.ImageKey" UriSource="C:\Uri\To\Image.jpg" />
</Bla.Resources>
However if you want to bind against some property form the current DataContext you must not use DynamicResource but Binding:
<Image Source="{Binding VM.ImageKey}" />
Assuming your current DataContext is an instance that has a property called VM wich again has a property called ImageKey wich is a derived type of ImageSource.
This behaviour is by design. Binding works only on dependency properties of dependency objects and MarkupExtension is not dependency object.
It cannot work since the DyamicResource is a MarkupExtension and not a dependency property. Databinding only works with dependendcy properties.
However, there is a semi smooth workaround. Create a DynamicTextBlock class that extends a TextBlock.
The xaml:
<TextBlock x:Class="Rebtel.Win.App.Controls.DynamicTextBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"/>
The codebehind:
public partial class DynamicTextBlock : TextBlock
{
public static readonly DependencyProperty TextKeyProperty = DependencyProperty.Register(
"TextKey", typeof(string), typeof(DynamicTextBlock), new PropertyMetadata(string.Empty, OnTextKeyChanged));
private static void OnTextKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var me = ((DynamicTextBlock)d);
if (e.NewValue != null)
{
me.TextKey = (string) e.NewValue;
}
}
public string TextKey
{
set { SetResourceReference(TextProperty, value); }
}
public DynamicTextBlock()
{
InitializeComponent();
}
}
Usage:
<local:DynamicTextBlock TextKey="{Binding TextKeyProperty}" />
The TextKeyProperty then returns a key that can be found in the ResourceDictionary. The same approach can be taken for an Image and its Source property.
If you want to specify the resource key dynamically you should specify it using the ResourceKey markup extension - not sure if it supports bindings in the way you want it to however. See here for more details.
I'm assuming that in this case, VM.ImageKey refers to a property on a data source whose value you wish to use as a resource dictionary key. The idea being that your data source can determine which image is used by supplying a resource key. (Most of the other answers on this page are unhelpful, because they have unfortunately missed what you're trying to do, assume that you want to use the literal text "VM.ImageKey" as a resource key, which I'm pretty sure isn't what you're asking for.)
This doesn't seem to be supported, but there's another approach that can enable you to select an image resource through a key determined by databinding: https://stackoverflow.com/a/20566945/497397

WPF - Dependency Properties Error

I'm working on a WPF project, and my intention is to make two specific RadioButtons alter properties of another specified Component. But for now, i'm just trying to store a String inside the RadioButton.
For that, I've created a behavior class:
public class AdjustBehavior : Behavior<RadioButton>
{
With this property:
public static DependencyProperty AdjustLabelContentProperty =
DependencyProperty.RegisterAttached("LabelContent", typeof(String), typeof(AdjustBehavior),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.Inherits));
And these getters and setters:
public static String GetLabelContent(RadioButton tb)
{
return (String)tb.GetValue(AdjustLabelContentProperty);
}
public static void SetLabelContent(RadioButton tb, String value)
{
tb.SetValue(AdjustLabelContentProperty, value);
}
On the XAML side, I did this:
<RadioButton Content="Banana" Height="16" HorizontalAlignment="Left" Margin="30,216,0,0" Name="radioButton1" VerticalAlignment="Top" GroupName="a" IsThreeState="False" IsChecked="True" Checked="radioButton1_Checked" >
<int:Interaction.Behaviors>
<i:AdjustBehavior LabelContent="Apple" />
</int:Interaction.Behaviors>
</RadioButton>
Where int: is the namespace to Interaction.Behaviors and i: is the namespace to the AdjustBehavior class. But whenever I start my application, LabelContent is set to null. Why?
I didn't post the rest of my Behavior class because I think it won't matter, but I'll do if necessary.
Thanks in Advance.
Clark
You should use DependencyProperty.Register, not RegisterAttached. This isn't being used as an attached property, but rather a standard dependency property.
Attached property requires target to be attached to. In your case that target is radio button,
so you should use
<RadioButton i:AdjustBehavior.LabelContent="Apple" ... />
If you need to just create property of AdjustBehavior, use normal dependency property, not attached.
LabelContent should be either an attached property on RadioButton or dependency property on AdjustBehavior .

How to Add Custom Silverlight XAML Attributes?

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" />

Resources