WPF - Dependency Properties Error - wpf

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 .

Related

WPF/XAML: Shortcut to a user control

I have created a UserControl named ContactPerson. It contains a persons name, phone number etc.
This usercontrol does not have a headline (ie. a label such as "_Contact Person") because I use this usercontrol in different situations.
However in one situation, I do have such a label, which means my code look somewhat like this:
<Label Content="_Contact Person"
Target="{Binding ElementName=_contactView}" />
<View1:contactView x:Name="_contactView"
DataContext="{Binding SupplierContact}"/>
I want - to set keyboard focus to the name-textbox inside the ContactPersonUserControl but it seems to be a difficult task (it is private after alle).
I do not want to move the label inside the usercontrol, which I guess would in fact be the most simple solution. It seems to me that XAML should provide a solution to this scenario.
How to do this in a simple and elegant way?
Thx
(I have a few of these controls, so I'll need to use the same solution several times).
I am not sure whether i understand your scenario correctly, But if you want to set focus to ui control from view model, then you may need to create an attached property.
Attached Property:
public static class ControlFocusExtension
{
public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached("IsFocused", typeof(bool), typeof(ControlFocusExtension), new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
public static bool GetIsFocused(DependencyObject obj)
{
return (bool)obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
private static void OnIsFocusedPropertyChanged(DependencyObject pDependencyObject, DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement)pDependencyObject;
if ((bool)e.NewValue)
{
uie.Focus();
}
}
}
User control XAML:
Now in your View (in XAML) you can bind this property to your ViewModel:
<TextBox local:FocusExtension.IsFocused="{Binding IsNameFocused}" />
You can change the value of IsNameFocused from your view model if needed.
Alternatively if you don't want to bind this then you can use it as -
<TextBox local:FocusExtension.IsFocused="True" />
Set focusvisualstyle property null for those you dont want to set focus like this
example <Label FocusVisualStyle="{x:Null}">
and for textbox focus <TextBox Focusable="True"/>

What are the scenarios in which we need to use dependency property in WPF?

We can achieve the binding by simply CLR property, so why do we need to use DP?
When do you need DPs over CLRPs?
When you need binding
when you need property value change callback (Default Implementation)
When you need property value validation
When you need animation
When you need property value inheritance
When you need to attach a property value to another element (Attached Property, but still)
When you need styling
Some of these can be implemented in CLR properties. But, with DPs, its piece of cake.
Typically these are declared in UserControls and derived controls.
You can bind to a CLR property, but you can't bind with a CLR property; you'll need a dependency property to do any binding.
Edit (in response to comment)
Let's say you need a TextBox, but you want to customize it to have different behaviour in "EditMode" and "ReadMode". You'll need to either create a derived class or a UserControl; in either case you'll add a DependencyPropery.
public class TextBoxWithModes : TextBox
{
public bool EditMode
{
get { return (bool) GetValue(EditModeProperty); }
set { SetValue(EditModeProperty, value); }
}
public static readonly DependencyProperty EditModeProperty = DependencyProperty.Register(
"EditMode", typeof (bool), typeof (TextBoxWithModes));
}
With this in place, you can declare it in XAML:
<Namespace:TextBoxWithModes Text="enter text here"
Width="200"
HorizontalAlignment="Center"
EditMode="{Binding IsChecked, ElementName=editModeCheckBox}" />

How to combine binding from custom data context with custom markup

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

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

Setting XAML property value to user control

I have a user control in WPF which i want the text of one of it's labels to be read from the XAML where it is used. Hence..
My User Control:
<UserControl x:Class="muc">
<Label Foreground="#FF7800" FontSize="20" FontWeight="Bold">
<Label.Content>
<Binding ElementName="TestName" Path="." />
</Label.Content>
</Label>
</UserControl>
Then using it:
<mycontorls:muc TestName="This is a test" />
But it doesn't works ...
How can i read the properties ?
I tried the first two answers and what I got worked in code but not on XAML (also doesn't let you see changes in the design view when using the control).
To get a property working like any other native one, here is the full process:
(The sample adds a dependency property of type Nullable to show in the control as text or a default if null)
In the code file:
1.a Define a dependency property:
public static readonly DependencyProperty MyNumberProperty = DependencyProperty.Register("MyNumber", typeof(Nullable<int>), typeof(MyUserControl), new PropertyMetadata(null, new PropertyChangedCallback(OnMyNumberChanged)));
1.b Implement the OnMyNumberChanged Callback:
private static void OnMyNumberChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args){
// When the color changes, set the icon color PlayButton
MyUserControl muc = (MyUserControl)obj;
Nullable<int> value = (Nullable<int>)args.NewValue;
if (value != null)
{
muc.MyNumberTextBlock.Text = value.ToString();
}
else
{
muc.MyNumberTextBlock.Text = "N/A";
}
}
1.c implement the MyNumber property (not dependency) to use the dependency property for easy in code use:
public Nullable<int> MyNumber{
get
{
return (Nullable<int>)GetValue(MyNumberProperty);
}
set
{
SetValue(MyNumberProperty, value);
OnTargetPowerChanged(this, new DependencyPropertyChangedEventArgs(TargetPowerProperty, value, value)); // Old value irrelevant.
}
}
In the XAML file bind the TextBlock control's text to the property (not dependency) to get the default value of the dependency property in case it is not set by the user of the control (assuming you called your root element of the user control "RootElement"):
This code:
< TextBlock Name="MyNumberTextBlock" Text="{Binding MyNumber, ElementName=RootElement}"/>
If you give the root UserControl element a name, then you can refer to it using ElementName:
<UserControl x:Class="muc"
Name="rootElement">
<Label Foreground="#FF7800" FontSize="20" FontWeight="Bold">
<Label.Content>
<Binding ElementName="rootElement" Path="TestName" />
</Label.Content>
</Label>
</UserControl>
You can also use the markup extension syntax to make it a little shorter:
<UserControl x:Class="muc"
Name="rootElement">
<Label Foreground="#FF7800" FontSize="20" FontWeight="Bold"
Content="{Binding TestName, ElementName=rootElement}"/>
</UserControl>
Also remember that your control will be created before its properties are set. You will either need to implement INotifyPropertyChanged or have TestName be a dependency property so that the binding is re-evaluated after the property is set.
I've only done this with Silverlight, but i wouldnt be surprised if it works in the exact same way!
// <summary>
// Xaml exposed TextExposedInXaml property.
// </summary>
public static readonly DependencyProperty TestNameProperty = DependencyProperty.Register("TestName", typeof(string), typeof(NameOfMyUserControl), new PropertyMetadata(string.empty));
// <summary>
// Gets or sets the control's text
// </summary>
public string TextExposedInXaml
{
get
{
return (string)GetValue(TestNameProperty );
}
set
{
SetValue(TestNameProperty , value);
// set the value of the control's text here...!
}
}
{Binding ElementName=x} binds to an element with name x in the element tree, there is nothing here that deals with property TestName. If you want a property on your user control, then you have to define the property in the class corresponding to that user control (in your case it would be muc), and use {Binding RelativeSource={RelativeSource FindAncestor, ...}} to reference it on your user control (see here for details), or give it a name so you can use ElementName.

Resources