Binding Exception but i don t know why? - wpf

I have a custom usercontrol with that code:
public partial class AudioControl : UserControl
{
public AudioControl()
{
InitializeComponent();
Value = 0.1;
DataContext = this;
}
public event RoutedPropertyChangedEventHandler<double> ValueChanged = delegate { };
public int TextWidth
{
get { return (int)GetValue(TextWidthProperty); }
set { SetValue(TextWidthProperty, value); }
}
public int SliderWidth
{
get { return (int)GetValue(SliderWidthProperty); }
set { SetValue(SliderWidthProperty, value); }
}
public string Header
{
get { return (string)GetValue(TextBlock.TextProperty); }
set { SetValue(TextBlock.TextProperty, value); }
}
//public double Value
//{
// get { return (double)GetValue(Slider.ValueProperty); }
// set { SetValue(Slider.ValueProperty, value); }
//}
public double Value
{
get {
return (double)GetValue(ValueProperty);
}
set {
SetValue(ValueProperty, value);
}
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(AudioControl), new UIPropertyMetadata(0));
public static readonly DependencyProperty TextWidthProperty =
DependencyProperty.Register("TextWidth", typeof(int), typeof(AudioControl), new UIPropertyMetadata(0));
public static readonly DependencyProperty SliderWidthProperty =
DependencyProperty.Register("SliderWidth", typeof(int), typeof(AudioControl), new UIPropertyMetadata(0));
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
ValueChanged(this, e);
}
}
And this XAML:
<UserControl x:Class="Controller.Audio.AudioControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Audio="clr-namespace:Controller.Audio"
mc:Ignorable="d"
d:DesignHeight="23" d:DesignWidth="500" x:Name="audioControl">
<UserControl.Resources>
<Audio:DoubleToIntConverter x:Key="doubleToInt"/>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding TextWidth}"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="{Binding SliderWidth}"/>
</Grid.ColumnDefinitions>
<Label x:Name="txtBlock" Margin="0,0,10,0">
<Binding Path="Header"/>
</Label>
<Label Grid.Column="1" Content="{Binding ElementName=slider, Path=Value, Converter={StaticResource doubleToInt}}"/>
<Slider x:Name="slider" Grid.Column="2" Style="{StaticResource Office2010SilverSliderStyle}"
Value="{Binding Path=Value, ElementName=audioControl}" Minimum="0.0" Maximum="1.0" LargeChange="0.25" TickFrequency="0.01" ValueChanged="Slider_ValueChanged"/>
</Grid>
So if i start it I get an exception that something with the value binding is wrong. I also tried the commented version (the value-Property). There is no exception but if i set the value of that property my slider does not change.
Does anyone has any idea why? I ve never done something like that :(

There's an error in the following dependency property declaration:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(AudioControl), new UIPropertyMetadata(0));
The problem here is that you're defining the dependency property to be of type double, but giving it a default value 0 that is an int. Try changing 0 to 0.0.
I ran your code and encountered an exception. The innermost exception contained the following message:
Default value type does not match type of property 'Value'.
I changed the 0 in the line above to 0.0 and the problem went away.

Related

Binding text to attached property

My question is similar to this: WPF Generate TextBlock Inlines but I don't have enough reputation to comment. Here is the attached property class:
public class Attached
{
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
"FormattedText",
typeof(string),
typeof(TextBlock),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetFormattedText(DependencyObject textBlock, string value)
{
textBlock.SetValue(FormattedTextProperty, value);
}
public static string GetFormattedText(DependencyObject textBlock)
{
return (string)textBlock.GetValue(FormattedTextProperty);
}
private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBlock = d as TextBlock;
if (textBlock == null)
{
return;
}
var formattedText = (string)e.NewValue ?? string.Empty;
formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", formattedText);
textBlock.Inlines.Clear();
using (var xmlReader = XmlReader.Create(new StringReader(formattedText)))
{
var result = (Span)XamlReader.Load(xmlReader);
textBlock.Inlines.Add(result);
}
}
}
I'm using this attached property class and trying to apply it to a textblock to make the text recognize inline values like bold, underline, etc from a string in my view model class. I have the following XAML in my textblock:
<TextBlock Grid.Row="1" Grid.Column="1" TextWrapping="Wrap" my:Attached.FormattedText="test" />
However I get nothing at all in the textblock when I start the program. I also would like to bind the text to a property on my view model eventually but wanted to get something to show up first...
Sorry this is probably a newbie question but I can't figure out why it's not working. It doesn't give me any error here, just doesn't show up. If I try to bind, it gives me the error:
{"A 'Binding' cannot be set on the 'SetFormattedText' property of type 'TextBlock'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject."}
First, the type of property needs to be a class name, not the type TextBlock:
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
"FormattedText",
typeof(string),
typeof(TextBlock), <----- Here
Second, the handler is not called, it must be registered here:
new FrameworkPropertyMetadata(string.Empty,
FrameworkPropertyMetadataOptions.AffectsMeasure,
YOUR_PropertyChanged_HANDLER)
Thirdly, an example to work, you need to specify the input string like this:
<Bold>My little text</Bold>
Working example is below:
XAML
<Window x:Class="InlineTextBlockHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:InlineTextBlockHelp"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock Name="TestText"
this:AttachedPropertyTest.FormattedText="TestString"
Width="200"
Height="100"
TextWrapping="Wrap" />
<Button Name="TestButton"
Width="100"
Height="30"
VerticalAlignment="Top"
Content="TestClick"
Click="Button_Click" />
</Grid>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
string inlineExpression = "<Bold>Once I saw a little bird, go hop, hop, hop.</Bold>";
AttachedPropertyTest.SetFormattedText(TestText, inlineExpression);
}
}
public class AttachedPropertyTest
{
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
"FormattedText",
typeof(string),
typeof(AttachedPropertyTest),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));
public static void SetFormattedText(DependencyObject textBlock, string value)
{
textBlock.SetValue(FormattedTextProperty, value);
}
public static string GetFormattedText(DependencyObject textBlock)
{
return (string)textBlock.GetValue(FormattedTextProperty);
}
private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBlock = d as TextBlock;
if (textBlock == null)
{
return;
}
var formattedText = (string)e.NewValue ?? string.Empty;
formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", formattedText);
textBlock.Inlines.Clear();
using (var xmlReader = XmlReader.Create(new StringReader(formattedText)))
{
var result = (Span)XamlReader.Load(xmlReader);
textBlock.Inlines.Add(result);
}
}
}
Initially be plain text, after clicking on the Button will be assigned to inline text.
Example for MVVM version
To use this example in MVVM style, you need to create the appropriate property in the Model/ViewModel and associate it with the attached dependency property like this:
<TextBlock Name="TestText"
PropertiesExtension:TextBlockExt.FormattedText="{Binding Path=InlineText,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Width="200"
Height="100"
TextWrapping="Wrap" />
Property in Model/ViewModel must support method NotifyPropertyChanged.
Here is a full sample:
AttachedProperty
public class TextBlockExt
{
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
"FormattedText",
typeof(string),
typeof(TextBlockExt),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));
public static void SetFormattedText(DependencyObject textBlock, string value)
{
textBlock.SetValue(FormattedTextProperty, value);
}
public static string GetFormattedText(DependencyObject textBlock)
{
return (string)textBlock.GetValue(FormattedTextProperty);
}
private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBlock = d as TextBlock;
if (textBlock == null)
{
return;
}
var formattedText = (string)e.NewValue ?? string.Empty;
formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", formattedText);
textBlock.Inlines.Clear();
using (var xmlReader = XmlReader.Create(new StringReader(formattedText)))
{
var result = (Span)XamlReader.Load(xmlReader);
textBlock.Inlines.Add(result);
}
}
}
MainViewModel
public class MainViewModel : NotificationObject
{
private string _inlineText = "";
public string InlineText
{
get
{
return _inlineText;
}
set
{
_inlineText = value;
NotifyPropertyChanged("InlineText");
}
}
}
MainWindow.xaml
<Window x:Class="InlineTextBlockHelp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:InlineTextBlockHelp.ViewModels"
xmlns:PropertiesExtension="clr-namespace:InlineTextBlockHelp.PropertiesExtension"
Title="MainWindow" Height="350" Width="525"
ContentRendered="Window_ContentRendered">
<Window.DataContext>
<ViewModels:MainViewModel />
</Window.DataContext>
<Grid>
<TextBlock Name="TestText"
PropertiesExtension:TextBlockExt.FormattedText="{Binding Path=InlineText,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Width="200"
Height="100"
TextWrapping="Wrap" />
</Grid>
</Window>
Code-behind (just for test)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
MainViewModel mainViewModel = this.DataContext as MainViewModel;
mainViewModel.InlineText = "<Bold>Once I saw a little bird, go hop, hop, hop.</Bold>";
}
}
This example is available at this link.

WPF UserControl Binding

I've been trying to find a solution to this problem, but I'm quite confused by the possible approaches I've found on the Internet.
I have created a UserControl containing a slider for DateTime.
<UserControl x:Name="root">
<Grid x:Name="gridPanel">
<Slider x:Name="slider" HorizontalAlignment="Left" VerticalAlignment="Top" Height="34" Width="479"
Minimum="{Binding ElementName=root, Path=Minimum, Converter={StaticResource ResourceKey=dateToDoubleConverter}}"
Maximum="{Binding ElementName=root, Path=Maximum, Converter={StaticResource ResourceKey=dateToDoubleConverter}}"
Value="{Binding ElementName=root, Path=Value, Converter={StaticResource ResourceKey=dateToDoubleConverter}}" />
<Label x:Name="lblStartTime" Content="{Binding ElementName=slider, Path=Minimum, Converter={StaticResource ResourceKey=doubleToStringConverter}}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,73,0,0" FontSize="10"/>
<Label x:Name="lblStopTime" Content="{Binding ElementName=slider, Path=Maximum, Converter={StaticResource ResourceKey=doubleToStringConverter}}" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,73,10,0" FontSize="10"/>
</Grid>
</UserControl>
Code behind:
public SliderPanel() {
InitializeComponent();
gridPanel.DataContext = this;
}
#region Dependency Property - Minimum
public DateTime Minimum {
get { return (DateTime)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register("Minimum", typeof(DateTime), typeof(SliderPanel), new UIPropertyMetadata(DateTime.Now));
#endregion
#region Dependency Property - Maximum
public DateTime Maximum {
get { return (DateTime)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register("Maximum", typeof(DateTime), typeof(SliderPanel), new UIPropertyMetadata(DateTime.Now.AddDays(1)));
#endregion
#region Dependency Property - Value
public DateTime Value {
get { return (DateTime)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(DateTime), typeof(SliderPanel), new UIPropertyMetadata(DateTime.Now, new PropertyChangedCallback(OnValueChanged)));
public static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
SliderPanel sP = (SliderPanel)d;
if (e.Property == SliderPanel.ValueProperty) {
sP.slider.Value = ((DateTime)e.NewValue).Ticks;
}
}
#endregion
In my main window, I use the UserControl and bind some properties via code, such as:
System.Windows.Data.Binding bndPlayTime = new System.Windows.Data.Binding("CurrentPlayTime");
bndPlayTime.Source = controller;
bndPlayTime.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
lblCurPlayTime.SetBinding(System.Windows.Controls.TextBox.TextProperty, bndPlayString);
sliderPanel.SetBinding(SliderPanel.ValueProperty, bndPlayTime);
The Controller class implements INotifyPropertyChanged:
public DateTime CurrentPlayTime {
get {
return currentPlayTime;
}
set {
if (DateTime.Compare(currentPlayTime, value) != 0) {
currentPlayTime = value;
NotifyPropertyChanged("CurrentPlayTime");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
The CurrentPlayTime property is constantly updated by a timer. Now I would like the slider to move accordingly. The binding to the label works. The label is updated on a regular basis. However, the binding to the dependency property of the UserControl does not cause the slider value to update (even though I have implemented a callback method). Am I missing something?
Please bear with me, I'm very new to WPF. I'd really appreciate your help.
Did you try to set the binding mode to TwoWay on your bindings ?

Silverlight how to bind my usercontrol in Data Grid column template

today I getting crazy while trying to do, what I think, is simple thing.
I want to be able to create my usercontrol, and use it in my column template in my datagrid
I have searched and tried several combinations, and nothing appear to work
Can anyone help me?
public class User
{
public string Name { get; set; }
public bool IsValid { get; set; }
}
partial class MyControl : UserControl
{
private string _value;
public string Value
{
get { return _value; }
set { _value = value;
txt.Text = value;
}
}
public MyControl()
{
InitializeComponent();
}
}
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="txt" Text="[undefined]"></TextBlock>
</Grid>
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
var items = new List<User>();
items.Add(new User{Name = "user 1", IsValid = true});
items.Add(new User { Name = "user 2", IsValid = false });
myGrid.ItemsSource = items;
}
}
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid x:Name="myGrid" AutoGenerateColumns="False" IsReadOnly="True">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Name">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<SilverlightApplication1:MyControl Value="{Binding Name}"></SilverlightApplication1:MyControl>
<!--<TextBlock Text="{Binding Name}"></TextBlock>-->
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
Edited:
I also tried the following, but I get no results on my grid:
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="txt" Text="{Binding Value}"></TextBlock>
</Grid>
public partial class MyControl : UserControl
{
public DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(string),
typeof(MyControl),
new PropertyMetadata(OnValueChanged));
public string Value
{
get
{
return (string)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
NotifyPropertyChanged("Value");
}
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyControl) d).Value = (String)e.NewValue; //ERROR: here I got always empty string
}
public MyControl()
{
InitializeComponent();
}
}
The reason why your first code didn't work is simple. To be able to bind the "Value" property on your "MyControl" (Value={Binding Name}), it has to be a Dependency Property. which you fixed in your second bit of code.
Here's what I did (and that worked well):
<UserControl x:Class="BusinessApplication8_SOF_Sandbox.Controls.MyControl"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" Name="myControl">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Name="textBlock" Text="{Binding Value, ElementName=myControl}"/>
</Grid>
</UserControl>
For the rest, I used your code.
Another possibility, which should be OK in case you only want the data to flow in one direction ("One Way" from source to target), as it is the case when using the TextBlock control is to update the Text property in the "OnValueChanged". here's the code for the Value property:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(string), typeof(MyControl),
new PropertyMetadata("", OnValueChanged));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = (MyControl)d;
var oldValue = (string)e.OldValue;
var newValue = target.Value;
target.OnValueChanged(oldValue, newValue);
}
protected virtual void OnValueChanged(string oldValue, string newValue)
{
textBlock.Text = newValue;
}
and you can remove the binding in xaml:
<TextBlock Name="textBlock" />
this worked for me as well.
Hope this helps ;)
you need to implement the INotifyPropertyChanged interface in your User class so that bound user controls are aware if any of the bound properties change. See the following page with the details how to implement it : http://www.silverlightshow.net/tips/How-to-implement-INotifyPropertyChanged-interface.aspx
As you can see you need to implement the interface and in the setters raise the event OnPropertyChanged
Then it should work with your bindings.
Best,
Tim

Silverlight databind int to lookless control not working

I am working a very simple lookless control, and I can't seem to get one of the template bindings to work. In the control I have two Dependency Properties, the one that is a string works, and the one that is an int does not.
The csharp code looks like this:
using System;
using System.Windows;
using System.Windows.Controls;
namespace ControlDemo
{
public class TextControlLookless : Control
{
#region Title
public static readonly DependencyProperty ChartTitleProperty =
DependencyProperty.Register("ChartTitle", typeof(string), typeof(TextControlLookless),
null);
public String ChartTitle
{
get { return (string)GetValue(ChartTitleProperty); }
set
{
SetValue(ChartTitleProperty, value);
}
}
#endregion
#region Value
public static readonly DependencyProperty ChartValueProperty =
DependencyProperty.Register("ChartValue", typeof(int), typeof(TextControlLookless),
null);
public int ChartValue
{
get { return (int)GetValue(ChartValueProperty); }
set
{
SetValue(ChartValueProperty, value);
}
}
#endregion
#region ctor
public TextControlLookless()
{
this.DefaultStyleKey = typeof(TextControlLookless);
}
#endregion
}
}
And the xaml for the control looks like this:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ControlDemo">
<Style TargetType="local:TextControlLookless">
<Setter Property="ChartTitle" Value="Set Title" />
<Setter Property="ChartValue" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TextControlLookless">
<Grid x:Name="Root">
<Border BorderBrush="Black" BorderThickness="2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Text="{TemplateBinding ChartTitle}" />
<TextBlock Text="{TemplateBinding ChartValue}" Grid.Row="1" />
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When I put this on a page, I can see the ChartTitle (either Set Title, or whatever I set it to), but the ChartValue never shows up. If I change its type to a string, it does show up, so I must be missing something.
The problem is that TemplateBinding is a far more primitive operation than Binding. Binding is an actual class and includes some helpful features including the implicit conversion of strings back and forth between other data types.
TemplateBinding is purely a markup instruction and crucially in your case does not do type conversion for you. Hence the dependency property being bound to a Text property of a TextBlock must be a string.
You have two choices:-
One choice is instead using TemplateBinding give the TextBlock a name and assign its Text in the ChartValue property changed call back:-
#region Value
public static readonly DependencyProperty ChartValueProperty =
DependencyProperty.Register("ChartValue", typeof(int), typeof(TextControlLookless),
new PropertyMetadata(0, OnChartValuePropertyChanged));
private static void OnChartValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextControlLookless source = d as TextControlLookless;
source.Refresh();
}
public int ChartValue
{
get { return (int)GetValue(ChartValueProperty); }
set
{
SetValue(ChartValueProperty, value);
}
}
#endregion
private TextBlock txtChartValue { get; set; }
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
txtChartValue = GetTemplateChild("txtChartValue") as TextBlock;
Refresh();
}
private void Refresh()
{
if (txtChartValue != null)
{
txtChartValue.Text = ChartValue.ToString();
}
}
where the xaml looks like:-
<TextBlock x:Name="txtChartValue" Grid.Row="1" />
The other choice is to create a private dependency property for the value with type of string:-
#region Value
public static readonly DependencyProperty ChartValueProperty =
DependencyProperty.Register("ChartValue", typeof(int), typeof(TextControlLookless),
new PropertyMetadata(0, OnChartValuePropertyChanged));
private static void OnChartValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.SetValue(ChartValueStrProperty, e.NewValue.ToString());
}
private static readonly DependencyProperty ChartValueStrProperty =
DependencyProperty.Register("ChartValueStr", typeof(string), typeof(TextControlLookless),
new PropertyMetadata("0"));
public int ChartValue
{
get { return (int)GetValue(ChartValueProperty); }
set
{
SetValue(ChartValueProperty, value);
}
}
#endregion
where the xaml looks like:-
<TextBlock Text="{TemplateBinding ChartValueStr}" Grid.Row="1" />
Note that the ChartValueStrProperty is private and I haven't bothered creating a standard .NET property to cover it. TemplateBinding actually takes the property name you assign suffixes is with "Property" then looks for a static field on the target type.
Both approaches have their strengths and weaknesses. The first approach is the more common pattern but takes a little more code and is less flexiable (the control displaying the value must be a TextBlock). The second is more flexiable and uses less code but is somewhat unorthodox.

WPF DependencyProperty Exposing in UserControl?

I have a UserControl where I'd like to have some parameters of customization "radius"(double) and "contentSource" (string[]).
My UserControl is composed of a few nested controls:
<UserControl ...>
<Grid>
<my:Menu ...>
<my:Button>
</my:Button>
<my:Button>
</my:Button>
<my:Button>
</my:Button>
</my:Menu ...>
</Grid>
I'm trying to expose the parameters with:
public double Rad
{
get { return (double)GetValue(RadProperty); }
set { SetValue(RadProperty, value); }
}
public static readonly DependencyProperty RadProperty =
DependencyProperty.Register(
"Radius",
typeof(double),
typeof(Menu));
public String[] DataSource
{
get { return (String[])GetValue(DataSourceProperty); }
set { SetValue(DataSourceProperty, value); }
}
public static readonly DependencyProperty DataSourceProperty =
DependencyProperty.Register(
"DataSource",
typeof(String[]),
typeof(Menu));
However, there seems to be two problems, the "string[]" parameter seems to be causing crashes, but mostly, I cannot set the "Radius" property at all. Is there something else I need to do to expose the parameter?
How are you trying to access the values? I have copied your code into a UserControl and it seems to work fine. Have you set the DataContext for the object you are accessing these values from?
Here is my test code, which might help:
public partial class uc : UserControl
{
public uc()
{
InitializeComponent();
this.DataContext = this;
this.DataSource = new string[] { "hello","There" };
this.Rad = 7;
}
public String[] DataSource
{
get { return (String[])GetValue(DataSourceProperty); }
set { SetValue(DataSourceProperty, value); }
}
public static readonly DependencyProperty DataSourceProperty =
DependencyProperty.Register(
"DataSource",
typeof(String[]),
typeof(uc));
public double Rad
{
get { return (double)GetValue(RadProperty); }
set { SetValue(RadProperty, value); }
}
public static readonly DependencyProperty RadProperty =
DependencyProperty.Register(
"Radius",
typeof(double),
typeof(uc));
}
and the XAML:
<UserControl x:Class="WpfApplication18.uc"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel>
<TextBox Text="{Binding Path=DataSource[0]}"></TextBox>
<TextBox Text="{Binding Path=DataSource[1]}"></TextBox>
<TextBox Text="{Binding Path=Radius}"></TextBox>
<TextBox Text="{Binding Path=Radius}"></TextBox>
</StackPanel>
</Grid>
</UserControl>

Resources