WP7 Custom User Control Property - silverlight

I want a user control called Segmented Panel that contains 3 buttons of which I want to modify their names (Title1/2/3) from a XAML screen.
MainPage XAML:
<local:SegmentedControl HorizontalAlignment="Left" Margin="43,62,0,0" x:Name="segmentedControl1" VerticalAlignment="Top" Title1="ENTER BUTTON NAME HERE" Title2="blah.." Title3="Last Button" Loaded="segmentedControl1_Loaded" />
SegmentedControl XAML.CS:
public static readonly DependencyProperty Title1Property
= DependencyProperty.RegisterAttached("Title1", typeof(String), typeof(StackPanel),
new PropertyMetadata(""));
public static void SetTitle1(UIElement element, String value) {
element.SetValue(Title1Property, value);
}
public static string GetTitle1(UIElement element) {
return (string)element.GetValue(Title1Property);
}
public string Title1 {
get { return GetValue(Title1Property).ToString(); }
set { SetValue(Title1Property, value); }
}
In expression blend I open up the Segmented Panel, choose button1, in Content I tried chosing both Data Context and Element Value, then scrolling down to choose "Title1", but when I compile it, the button's contents never changes.
Can anybody help me out?

as John Gardner suggests, you have to write ...typeof(SegmentedControl) in your dependency property implementation and then one have to bind the property to the appropiate UI element!
For example:
<local:SegmentedControl HorizontalAlignment="Left" Margin="43,62,0,0" x:Name="segmentedControl1" VerticalAlignment="Top" Title1="{Binding Title1}" ... Loaded="segmentedControl1_Loaded" />

Related

Pass textbox from a page to Custom usercontrol using dependencyProperty

I have a Custom user control in a silver light Project.
I use it in other page and want to Pass textbox to Custom User control.
For this I create dependcy as below :
public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("TextBoxControl", typeof(TextBox), typeof(SpellCheck), new PropertyMetadata(false));
public TextBox TextBoxControl
{
get { return (TextBox)GetValue(MyPropertyProperty); }
set
{
SetValue(MyPropertyProperty, value);
TextSpell = value;
}
}
Here TextSpell is a textbox.
And I use this property in a silver light page as below:
<TextBox x:Name="txtNote" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="400"/>
<myButton:SpellCheck x:Name="btnSpell" Grid.Row="3" TextBoxControl="txtNote" Grid.Column="1" Width="20" Height="20" Margin="403,0,0,0" HorizontalAlignment="Left"/>
But I give s me a error : "The Typeconvertor for Texbox dose not support converting from a string"
So How can I pass a text box in custom usercontrol.
Thanks,
Hitesh
You can not simply use the field name (x:Name) string of the TextBox as a value for your TextBoxControl property. Instead you may use an ElementName binding like this:
<myButton:SpellCheck TextBoxControl="{Binding ElementName=txtNote}" ... />
And there are more things wrong:
In the CLR wrappers of a dependency property, you should never call anything else than GetValue and SetValue. The explanation is given in the XAML Loading and Dependency Properties article on MSDN. Instead, you have to have a PropertyChangedCallback registered with the property metadata.
There is a naming convention for the static dependency property fields. They should be named like the property, with a trailing Property.
The default value has to match the property type. Your false value is not valid, and might be null instead. But as that is the default anyway, you should leave it out completely.
The declaration would now look like this:
public static readonly DependencyProperty TextBoxControlProperty =
DependencyProperty.Register(
"TextBoxControl", typeof(TextBox), typeof(SpellCheck),
new PropertyMetadata(TextBoxControlPropertyChanged));
public TextBox TextBoxControl
{
get { return (TextBox)GetValue(TextBoxControlProperty); }
set { SetValue(TextBoxControlProperty, value); }
}
private static void TextBoxControlPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var spellCheck = (SpellCheck)obj;
spellCheck.TextSpell = (TextBox)e.NewValue;
}

Property bound to DependencyProperty won't update despite TwoWay Binding set

I have a little problem here. I've created custom TreeView using RadTreeView. It all works nice, but I've encountered an obstacle. I've set DependencyProperty for SelectedItem in TreeView. I nest my control in View, bind property to SelectedItem in TwoWay mode, but bound property won't update, it's null all the time, despite DependencyProperty value being set.
Here's tree xaml:
<Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:sdk='http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk'
xmlns:telerik='http://schemas.telerik.com/2008/xaml/presentation' x:Name='this' >
<Grid.Resources>
<DataTemplate x:Key='ChildTemplate'>
<TextBlock Text='{Binding Path=ChildPath}' Margin='5,0' />
</DataTemplate>
<telerik:HierarchicalDataTemplate x:Key='NameTemplate' ItemsSource='{Binding ChildrenCollectionPath}' ItemTemplate='{StaticResource ChildTemplate}'>
<TextBlock Text='{Binding Path=ParentPath }' Padding='7'/>
</telerik:HierarchicalDataTemplate>
</Grid.Resources>
<telerik:RadTreeView x:Name='rtvTreeView' Padding='5' BorderThickness='0' IsEditable='False' IsLineEnabled='True' IsExpandOnDblClickEnabled='False' ItemTemplate='{StaticResource NameTemplate}' />
</Grid>
Below is way I nest the control in View:
<windows:TreeViewReuse CollectionSource="{Binding SitesCollectionWithAddress}" ParentPath="Napis" Grid.Column="0" BorderThickness="2" SelectedItemD="{Binding SelectedSide, ElementName=this, UpdateSourceTrigger=Explicit, Mode=TwoWay}" ChildPath="FullAddress" ChildrenCollectionPath="AdresyStrony" BorderBrush="Red" DoubleClickCommand="{Binding TreeViewDoubleClick}">
</windows:TreeViewReuse>
And here's Tree's code behind in parts:
public partial class TreeViewReuse : UserControl
{
static Telerik.Windows.FrameworkPropertyMetadata propertyMetaData = new Telerik.Windows.FrameworkPropertyMetadata(null,
Telerik.Windows.FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(SelectedItemChangedCallback));
public object SelectedItemD
{
get { return GetValue(SelectedItemDProperty); }
set { SetValue(SelectedItemDProperty, value); }
}
public static readonly DependencyProperty SelectedItemDProperty =
DependencyProperty.Register("SelectedItemD", typeof(object), typeof(TreeViewReuse), propertyMetaData);
public TreeViewReuse()
{
InitializeComponent();
Loaded += new RoutedEventHandler(TreeViewReuse_Loaded);
}
void treeView_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
{
SelectedItemD = _treeView.SelectedItem;
}
static private void SelectedItemChangedCallback(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
}
Does anyone have an idea why property bound to SelectedItemD does not update? I don't care about setting tree's selected item from it, I only want to set it to selected item.
Here's property:
public StronaSprawy SelectedSide
{
get
{
return _selectedSide;
}
set
{
_selectedSide = value;
}
}
Your Dependency Property looks fine.. all except for that Telerik.Windows.FrameworkPropertyMetadata instance.
Silverlight does not support setting meta data options, so I cant think how the Telerik implementation will achieve that. It is possible that Telerik have their own DP implementation, or even that this type of property meta data only works with their controls.
Try using the standard System.Windows.PropertyMetaData type instead and see if that works for you.

Silverlight - Strategy passing Data to a User Control

Silverlight5
From a button click on Tab1Data I want to pass a parameter to Tab2_1Data
Am currently doing it with a global public property(!) on the MainPage which each UserControl can reference using this helper
Is there a better way using a non MVVM approach to pass parameters?
<controls:TabControl Name="TabOverallMain">
<!-- Tab 1 -->
<controls:TabItem Header="Home Screen" IsSelected="True">
<UserControls:Tab1Data />
</controls:TabItem>
<!-- Tab 2 -->
<controls:TabItem Header="Admin">
<Grid>
<controls:TabControl>
<!-- Tab 2_1 -->
<controls:TabItem Header="Users">
<UserControls:Tab2_1Data />
</controls:TabItem>
EDIT:
Using this I implemented a DependencyProperty in my Tab2_1Data control:
public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(WidgetControl),null);
public string Caption
{
get { return (string)GetValue(CaptionProperty); }
set { SetValue(CaptionProperty, value); }
}
which I then referenced from my Tab1Data user control by:
wid.Caption = "hello world";
This is fine for me now.. although databinding between the 2 looks v.good too!
Since you dont want to use MVVM, try use data binding.. You will need to expose the parameter as a dependency propety int the first control
Here's some pseudo code. Create a dependency property on Tab1Data called MyParam
public static readonly DependencyProperty MyParamProperty = DependencyProperty.Register("MyParam",
int, typeof(Tab2_1Data), null);
public int MyParam
{
get { return (int)GetValue(MyParamProperty); }
set
{
SetValue(MyParamProperty, value);
}
}
<controls:TabItem Header="Home Screen" IsSelected="True">
<UserControls:Tab1Data x:Name="OneCtrl" />
</controls:TabItem>
Then create a dependency property (similar to above) on the second control called something like ParamFromControlOne... then bind them
<UserControls:Tab2_1Data ParamFromControlOne="{Binding MyParam, ElementName=OneCtrl}" />
That's not tested and thrown together using Notepad, but that is the path I would go down

User control's Dependency Property doesn't get bound in Silverlight

I have created a user control like numeric updown as follows
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" >
<TextBox x:Name="InputTextBox" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1"
Style="{StaticResource NumericUpDownTextBoxStyle}"
KeyDown="InputTextBox_KeyDown"
KeyUp="InputTextBox_KeyUp"
GotFocus="InputTextBox_GotFocus"
LostFocus="InputTextBox_LostFocus"
MouseWheel="InputTextBox_MouseWheel"
MouseEnter="InputTextBox_MouseEnter"
LayoutUpdated="InputTextBox_LayoutUpdated"
Text="{Binding Path=ControlValue, Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}"/>
</StackPanel>
I have bind a ViewModel to this control where I Set ControlValue property to TextBox property of the user control template textbox.
Everthing works fine at a control level. I have exposed from usercontrol.
public static readonly DependencyProperty MaximumValueProperty;
public static readonly DependencyProperty MinimumValueProperty;
public static readonly DependencyProperty StepValueProperty;
public static readonly DependencyProperty TextValueProperty;
My Properties are
public double Maximum
{
get
{
return (double)GetValue(MaximumValueProperty);
}
set
{
SetValue(MaximumValueProperty, value);
this.ViewModel.Maximum = this.Maximum;
}
}
public double Minimum
{
get
{
return (double)GetValue(MinimumValueProperty);
}
set
{
SetValue(MinimumValueProperty, value);
this.ViewModel.Minimum = this.Minimum;
}
}
public double Step
{
get
{
return (double)GetValue(StepValueProperty);
}
set
{
SetValue(StepValueProperty, value);
this.ViewModel.Step = this.Step;
}
}
public double TextValue
{
get
{
return (double)GetValue(TextValueProperty);
}
set
{
SetValue(TextValueProperty, value);
this.ViewModel.ControlValue = Convert.ToString(value);
}
}
Initialization of the property.
static NumericUpDown()
{
MaximumValueProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
MinimumValueProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
StepValueProperty = DependencyProperty.Register("Step", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
TextValueProperty = DependencyProperty.Register("TextValue", typeof(double), typeof(NumericUpDown), new PropertyMetadata(null));
}
My Usercontrol implementation in the MainPage.xaml page as follows
<local:NumericUpDown Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding ElementName=FranePrice, Path=DataContext.FranePrice}"></local:NumericUpDown>
Where I have another ViewModel which i bind to the XAML page and there is a Property in the ViewModel which i bind to the TextValue property of the Usercontrol.
FramePrice is property in the View model that i bind to the TextValue property of the user control
and Main page XAML is
<UserControl x:Class="DatePicker.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:local="clr-namespace:DatePicker"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<local:NumericUpDown Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding ElementName=FranePrice, Path=DataContext.FranePrice}"></local:NumericUpDown>
<Button Content="Show Date" Height="23" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
</StackPanel>
</Grid>
This View model of the page where i used user control. On click event i showing TextValue to user.
public class MainPageViewModel : EntityViewModel
{
public MainPageViewModel()
{
}
private double framePrice;
public Double FramePrice
{
get
{
return framePrice;
}
set
{
framePrice = value;
PropertyChangedHandler("FramePrice");
}
}
}
When I change the TextValue in the User control it doesnot change in the FramePrice property of the page viewmodel.
Is anything wrong in the code.???
As per Luke Woodward's post I have updated code as follows
public static readonly DependencyProperty MaximumValueProperty;
public static readonly DependencyProperty MinimumValueProperty;
public static readonly DependencyProperty StepValueProperty;
public static readonly DependencyProperty TextValueProperty;
public static double Max;
public static double Min;
public static double Stp;
public static double Val;
public double Maximum
{
get
{
return (double)GetValue(MaximumValueProperty);
}
set
{
SetValue(MaximumValueProperty, value);
}
}
public double Minimum
{
get
{
return (double)GetValue(MinimumValueProperty);
}
set
{
SetValue(MinimumValueProperty, value);
}
}
public double Step
{
get
{
return (double)GetValue(StepValueProperty);
}
set
{
SetValue(StepValueProperty, value);
}
}
public double TextValue
{
get
{
return (double)GetValue(TextValueProperty);
}
set
{
SetValue(TextValueProperty, value);
}
}
static NumericUpDown()
{
MaximumValueProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onMaximumValueChanged)));
MinimumValueProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onMinimumValueChanged)));
StepValueProperty = DependencyProperty.Register("Step", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onStepValueChanged)));
TextValueProperty = DependencyProperty.Register("TextValue", typeof(double), typeof(NumericUpDown), new PropertyMetadata(new PropertyChangedCallback(onTextValueChanged)));
}
private static void onStepValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Stp = (double)e.NewValue;
}
private static void onMinimumValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Min = (double)e.NewValue;
}
private static void onMaximumValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Max = (double)e.NewValue;
}
private static void onTextValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Val = (double)e.NewValue;
}
Then i accessed Max, Min , Stp and Val property in user control's view model to perform my logic.
and XAML code is follows
<local:NumericUpDown x:Name="ctlUpDown" Maximum="28" Minimum="-28" Step="0.25" TextValue="{Binding Path=FramePrice}"></local:NumericUpDown>
and XAML of user control
<StackPanel Margin="5" Orientation="Horizontal" VerticalAlignment="Center">
<TextBox x:Name="InputTextBox" Grid.Row="0" Grid.Column="0" Grid.RowSpan="1"
Height="23" VerticalAlignment="Top"
Width="50" TextAlignment="Center"
KeyDown="InputTextBox_KeyDown"
KeyUp="InputTextBox_KeyUp"
GotFocus="InputTextBox_GotFocus"
LostFocus="InputTextBox_LostFocus"
MouseWheel="InputTextBox_MouseWheel"
MouseEnter="InputTextBox_MouseEnter"
Text="{Binding Path=TextValue, ElementName=ctlUpDown, Mode=TwoWay,ValidatesOnDataErrors=True,ValidatesOnExceptions=True,NotifyOnValidationError=True}"
/>
</StackPanel>
The first thing I noticed wrong about your code was the properties Maximum, Minimum, Step and TextValue. Here's the TextValue property:
public double TextValue
{
get
{
return (double)GetValue(TextValueProperty);
}
set
{
SetValue(TextValueProperty, value);
this.ViewModel.ControlValue = Convert.ToString(value);
}
}
Properties that are backed by a dependency property, such as the four I mentioned above, should ALWAYS look like the following:
public double TextValue
{
get { return (double)GetValue(TextValueProperty); }
set { SetValue(TextValueProperty, value); }
}
In other words, the getter should contain nothing more than a call to GetValue, and the setter should contain nothing more than a call to SetValue.
The reason for this is that when Silverlight changes the value of the TextValue dependency property, it won't do it by using the property above. The values of dependency properties are stored within the Silverlight dependency system, and when Silverlight wants to change the value of one of them, it goes directly to this dependency system. It doesn't call your code at all. Properties like that above are provided only for your convenience, giving you an easy way to access and change the value stored in the dependency property. They will never be called by anything other than your own code.
Generally, if you want a method to be called whenever a dependency property value changes, you need to pass a PropertyChangedCallback in the PropertyMetadata when registering the dependency property. However, I suspect that in your case you won't need to do that.
It seems to me that you have three properties:
the FramePrice property in your view-model class,
the TextValue dependency property of your NumericUpDown user control,
the Text dependency property of the TextBox within your NumericUpDown user control's XAML.
My impression is that you want the FramePrice property in your view-model to always have the same value as the Text property of the TextBox. To do that, you need to bind the FramePrice property to the NumericUpDown's TextValue property, and then bind that to the Text property of the TextBox.
To bind the first two of these properties together, there are a couple of things to change. Firstly, the TextValue property in your <local:NumericUpDown> element should look like
TextValue="{Binding Path=FramePrice}"
The binding {Binding ElementName=FramePrice, Path=DataContext.FramePrice} won't work, because there's no element in your XAML with the attribute x:Name="FramePrice". The value of an ElementName property in a {Binding ...} must match the x:Name of an object in the XAML.
You also need to set up the DataContext for your main page. If your main page view-model object has a zero-argument constructor, one way of doing this is to follow this answer.
To bind the second two properties together, I would:
add an x:Name attribute to the <UserControl> element of your NumericUpDown control (x:Name="ctlUpDown", say),
replace the Text property of the TextBox within your NumericUpDown control with the following:
Text="{Binding Path=TextValue, ElementName=ctlUpDown, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/>
Once you've done that, you can then remove all of the lines this.ViewModel.SomeProperty = ... from your code-behind class. They're not necessary, and as I've already explained they won't be run when you wanted them to.
Finally, is there a reason you're not using the Silverlight Toolkit's NumericUpDown control?
EDIT 2: Against my better judgement I took a look at one of the two Silverlight projects you uploaded (I ignored the one with _2 in it). It bears very little resemblance to your question.
I can only assume you want the two textboxes (one of which is in a user control) to always have the same value. I was able to do this after making the following changes:
MainPageViewModel.cs: add ClearErrorFromProperty("DPropertyBind"); to the property setter. (Otherwise the validation error never gets cleared.)
MyUserControlWVM.xaml: removed reference to LostFocus event handler, added binding on Text property and added add x:Name attribute to the <UserControl> element. In other words, it now looks like the following:
<UserControl x:Class="DependencyPropertyBinding.MyUserControlWVM"
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"
x:Name="ctlWVM"
d:DesignHeight="300" d:DesignWidth="205">
<StackPanel Orientation="Horizontal" Width="204" Height="32">
<TextBox x:Name="textbox" Height="30" Width="200" Text="{Binding Path=DProperty, ElementName=ctlWVM, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" />
</StackPanel>
</UserControl>
MyUserControlWVM.xaml.cs: renamed dependency property DependencyPropertyValue to DPropertyProperty (the naming convention is that the static readonly field has the name of the property (in this case DProperty) with Property appended). I also removed the TextBox_LostFocus event handler.
If the code above is accurate you have spelt FramePrice as FranePrice in the binding
The output window should have shown this as a binding error when the page loaded.
it is currently
Binding ElementName=FranePrice, Path=DataContext.FranePrice
should be:
Binding ElementName=FramePrice, Path=DataContext.FramePrice
"With great binding capabilities comes great responsibility" :)

Binding a Textbox to a property in WPF

I have a Textbox in a User Control i'm trying to update from my main application but when I set the textbox.Text property it doesnt display the new value (even though textbos.Text contains the correct data). I am trying to bind my text box to a property to get around this but I dont know how, here is my code -
MainWindow.xaml.cs
outputPanel.Text = outputText;
OutputPanel.xaml
<TextBox x:Name="textbox"
AcceptsReturn="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Text="{Binding <!--?????--> }"/> <!-- I want to bind this to the Text Propert in OutputPanel.xmal.cs -->
OutputPanel.xaml.cs
namespace Controls
{
public partial class OutputPanel : UserControl
{
private string text;
public TextBox Textbox
{
get {return textbox;}
}
public string Text
{
get { return text; }
set { text = value; }
}
public OutputPanel()
{
InitializeComponent();
Text = "test";
textbox.Text = Text;
}
}
}
You have to set a DataContext in some parent of the TextBox, for example:
<UserControl Name="panel" DataContext="{Binding ElementName=panel}">...
Then the binding will be:
Text="{Binding Text}"
And you shouldn't need this - referring to specific elements from code behind is usually bad practice:
public TextBox Textbox
{
get {return textbox;}
}
I hope this example will help you.
1) Create UserControl.
2) Add to XAML <TextBlock Text="{Binding Path=DataContext.HeaderText}"></TextBlock>
3) In the code behind of that UserControl add
public partial class MyUserControl: UserControl
{
public string HeaderText { set; get; } // Add this line
public MyUserControl()
{
InitializeComponent();
DataContext = this; // And add this line
}
}
4) Outside of the control and let's say in the MainWindow Load event you have to do like
this.gdMain = new MyUserControl{ HeaderText = "YES" };
If your are starting to bind properties I suggest you check some articles on MVVM.
This is a very powerful architecture you can use on WPF. I found it very useful in my projects.
Check this one.

Resources