I am using Expression Blend.
Let's say I got:
Public string FirstName{get;set;}
Edit: thanks for the answers, but I'm afraid people didn't understand my question. I do know how to Bind Data in Code or in XAML.
My question is if there is a way to do all that with the Expression Blend Interface without writing it directly. Only with mouse movements.
You would actually want to put the property on a View Model, and use XAML binding, but that is another story.
As you describe your example, you would first need to implement the "FirstName" property as a Dependency Property and not a simple get/set. Here is a great code-snippet from Shawn Wildermuth to save lots of typing (there is a single typo in the snippet you need to fix - "($type$)args.NewValue;"... NewValue has the wrong case in the snippet).
You can bind in XAML to a simple get/set property, but it is a one-way/one-time binding and will not update with changes.
In code, the binding requires two things to be set.
Set the DataContext of the control (or the page) and
Set a data binding on the control.
For the example you mention you could use code like the following (assumes a TextBox control called myTextBox in the Xaml):
using System.Windows;
using System.Windows.Controls;
namespace BindingCodeTest
{
public partial class BindingCode : UserControl
{
public string FirstName
{
get { return (string)GetValue(FirstNameProperty); }
set { SetValue(FirstNameProperty, value); }
}
// Using a DependencyProperty as the backing store for FirstName.
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty FirstNameProperty =
DependencyProperty.Register("FirstName",
typeof(string),
typeof(BindingCode),
new PropertyMetadata(string.Empty,
new PropertyChangedCallback(OnFirstNameChanged)));
static void OnFirstNameChanged(object sender, DependencyPropertyChangedEventArgs args)
{
// Get reference to self
BindingCode source = (BindingCode)sender;
// Add Handling Code
string newValue = (string)args.NewValue;
}
public BindingCode()
{
InitializeComponent();
myTextBox.DataContext = this;
myTextBox.SetBinding(TextBox.TextProperty, new System.Windows.Data.Binding("FirstName"));
FirstName = "First name"; // Sample change
}
}
}
In Blend 4, on the 'Data' tab > New sample Data.. > name data source as you like, f.e. 'MySampleDataSource'. Then your 'MySampleDataSource' will have a '+' button (the same Data tab on the right) with 3 options. Choose 'Add simple property' and name it 'FirstName'. Then drag that property on your TextBox or TextBlock.
The result is like this:
<TextBlock x:Name="firstName" Text="{Binding FirstName}"/>
Related
I'm very new to WPF and while studying (particularly creating a user control), I stumbled upon this thing called "DependencyProperty".
I understand how it works in code but why and when do we need it when I can just create a property and expose it for public use.
Example:
XAML:
<UserControl.....>
<StackPanel Orientation="Vertical">
<TextBlock x:Name="label" Text="Hello"/>
<TextBlock x:Name="text" Text="World!" />
</StackPanel>
</UserControl>
CS file:
public partial SampleUserCtrl : UserControl
{
public string LabelText { get { return this.label.Text; } set { this.label.Text = value; } }
public string TextBoxText { get { return this.text.Text; } set { this.text.Text = value; } }
}
DependecyProperty in WPF has different uses.
Advantages compared to normal .NET property
Reduced memory footprint It's a huge dissipation to store a field for
each property when you think that over 90% of the properties of a UI
control typically stay at its initial values. Dependency properties
solve these problems by only store modified properties in the
instance. The default values are stored once within the dependency
property.
Value inheritance When you access a dependency property the value is
resolved by using a value resolution strategy. If no local value is
set, the dependency property navigates up the logical tree until it
finds a value. When you set the FontSize on the root element it
applies to all textblocks below except you override the value.
Change notification Dependency properties have a built-in change
notification mechanism. By registering a callback in the property
metadata you get notified, when the value of the property has been
changed. This is also used by the databinding.
As you dig deeper to WPF you will also stumble upon DataBinding and object-oriented design patterns like MVVM or MVPVM. Both patterns rely on DataBinding which is achieved through using of Dependency Properties. You cannot perform data binding if it is not a dependency property.
Basically data binding through dependency properties allow the user to update the view when updating a value through code.
Ex: In Windows Forms in order to update a label text you assign its value on the code behind like this:
lbl1.Text = "foo";
In data binding where as you bind in the XAML (View)
<label Text = "{Binding foo}"></label>
and update the values in your code behind:
foo = "foo";
I am not an expert myself so sorry if I might sound confusing.
Dependency property has many benefits over normal property.
A dependency property value can be set by referencing a resource
It can reference a value through data binding
It can be animated. When an animation is
applied and is running, the animated value operates at a higher
precedence than any value (such as a local value) that the property
otherwise has.
You can learn more about it from msdn.
The main advantage of DP property you can find anything in DP like your Control info and you current DataContext info.
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string), typeof(MyUserControl), new PropertyMetadata(null, (s, e) => OnChangedValue(s, e)));
private static void OnChangedValue(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
throw new NotImplementedException();
}
I just discovered than I can do the following:
var button = new Button();
button.SetValue(TextBlock.TextProperty, "text");
var text = (string)button.GetValue(TextBlock.TextProperty); // text is "text"
While the above example is a bit unrealistic, it does show that I can attach a regular dependency property onto another object. It doesn't have to be a an attached property (TextBlock.TextProperty is not registerd with DependencyProperty.RegisterAttached().
This bares the questions why are there attached properties in the first place? The only difference I can see for now ist that I can't attach regular dependency properties in XAML. But that's about it. Are there any other differences?
Update:
To make it more clear, the below code works and looks pretty close to an attached property from the end users perspective:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(Button),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
...
button.SetValue(AttachedPropertyDeclarer.TextProperty, "text");
var text = (string)button.GetValue(AttachedPropertyDeclarer.TextProperty);
Compare this to the attached property way:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
"Text",
typeof(string),
typeof(AttachedPropertyDeclarer),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
The only effective differnce to an attached property here is that I have to declare the owner of type Button whereas in a attached property it would usually be AttachedPropertyDeclarer. But this only needs to be done if I need a changed event handler (i.e. OnTextChanged).
Regarding your example, you have not as you say, attached a regular dependency property onto another object. All your code has achieved is to store a string value in a Dictionary along with a reference to your object. That does not make it an Attached Property - importantly, you cannot access that string value from the Button directly, as there is no Text property on a Button.
What your code does is actually very similar to this:
Dictionary<object, object> values2 = new Dictionary<object, object>();
var button = new Button();
values2.Add(button, "text");
string text = values2[button].ToString();
Now to answer your question:
The main reason to declare an Attached Property is in order to add a property to a type that you didn't declare, thereby extending its functionality.
A great example of this would be to add a SelectedItems property to the ItemsControl or ListBox class. In doing so, we extend the current, or default functionality of the class. Another good example would be declaring an Attached Property that automatically brings added items into view (again in an ItemsControl or ListBox class).
UPDATE >>>
According to your comments, you seem to be refusing to accept the differences that I have outlined... you said:
There is literally no difference from the end users perspective except that I can't use it in XAML.
Firstly, do you not think that this is a huge difference?.. you won't be able to use it for data binding for a start. Furthermore, you keep saying that you can attach a property to a type that you haven't declared using a DependencyProperty, but you are 100% incorrect. You can reference an Attached Property directly in both code and XAML, while you can't reference what you are calling your attached property directly in either XAML or code.
All you are doing is storing a value in a Dictionary and you certainly don't need the overhead of a DependencyProperty to do that. There really is no comparison between doing that and declaring an Attached Property. From the Attached Properties Overview page on MSDN:
You might create an attached property when there is a reason to have a property setting mechanism available for classes other than the defining class.
Note the following part: a property setting mechanism
Adding values into a Dictionary is not a property setting mechanism. So again, you lose the ability to use your pretend Attached Property in Styles, Animations, Triggers, etc.
To clarify this situation for once and for all, you can develop a simple test project. Implement the IList SelectedItems Attached Property for a ListBox that I mentioned (you can find online tutorials for this) and then do the same using your pretend Attached Property (if it is even possible). The difference in the simplicity of development bewteen the two will clearly show you why you should use an Attached Property instead of a regular DependencyProperty.
If you look closely at dependency property identifier, all DP's are registered with class DependencyProperty and we pass the Owner class type and property name at time of registration.
Sample:
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean), typeof(OwnerClass));
At time of registration it creates some unique hash code combining property name and owner class type to represent each DP uniquely.
So, when you set value for that DP on some object like in your case on Button, code flow is like this:
First it will get the unique value generated at time of registration of property and add the key value pair in private dictionary named _effectiveValues declared in class Dependency Object with Key set to unique hashcode at time of registration and value being the value set by user.
Note - No written documentation for this on MSDN but verified this by peeking into source code using reflector.
So, when you set the value from code behind it will work like I mentioned above because it does not validate before adding value in the dictionary if it belongs to that type or not and fetching value will get you the value from dictionary.
Not sure but might be constraint is there in XAML only where WPF guys enforced the type check. Sadly there is no written documentation for this on MSDN.
Attached properties are discovered, when you want to have control over an existing control, but dont want to extend it. A pretty good example is, there is no way to bind BlackOutDates property in XAML for WPF DatePicker. In that case you can use an Attached Property to attach a custom functionality to map the BlackOutDates. This suits good in MVVM, since attached properties provided way for binding in XAML.
public class BlackOutDatesAdapter
{
public static List<DateTime> GetBlackOutDates(DependencyObject obj)
{
return (List<DateTime>)obj.GetValue(BlackOutDatesProperty);
}
public static void SetBlackOutDates(DependencyObject obj, List<DateTime> value)
{
obj.SetValue(BlackOutDatesProperty, value);
}
// Using a DependencyProperty as the backing store for BlackOutDates. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BlackOutDatesProperty =
DependencyProperty.RegisterAttached("BlackOutDates", typeof(List<DateTime>), typeof(BlackOutDatesAdapter), new PropertyMetadata(null, OnBlackOutDatesChanged));
private static void OnBlackOutDatesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as DatePicker;
var list = (List<DateTime>)e.NewValue;
foreach(var date in list)
{
control.BlackoutDates.Add(new CalendarDateRange(date));
}
}
}
Binding in XAML will look like this,
<DatePicker VerticalAlignment="Center"
Width="200"
local:BlackOutDatesAdapter.BlackOutDates="{Binding BlackOutDates}"
DisplayDate="{Binding DisplayDate}" />
In the callback of property, you can do your own mapping of adding the dates to DatePicker. For more information, please read this post.
If I create a custom control like this:
public class MyControl : ContentControl
{
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register(
"Items",
typeof(ObservableCollection<object>),
typeof(MyControl),
new PropertyMetadata(null));
public MyControl()
{
// Setup a default value to empty collection
// so users of MyControl can call MyControl.Items.Add()
Items = new ObservableCollection<object>();
}
public ObservableCollection<object> Items
{
get { return (ObservableCollection<object>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
}
And then allow the user to bind to it in Xaml like this:
<DataTemplate>
<MyControl Items="{Binding ItemsOnViewModel}"/>
</DataTemplate>
Then the binding never works! This is due to the Dependency Property Precedence, which puts CLR Set values above Template bindings!
So, I understand why this isn't working, but I wonder if there is a solution. Is it possible to provide a default value of ItemsProperty to new ObservableCollection for lazy consumers of MyControl that just want to add Items programmatically, while allowing MVVM power-users of My Control to bind to the same property via a DataTemplate?
This is for Silverlight & WPF. DynamicResource setter in a style seemed like a solution but that won't work for Silverlight :(
Update:
I can confirm SetCurrentValue(ItemsProperty, new ObservableCollection<object>()); does exactly what I want - in WPF. It writes the default value, but it can be overridden by template-bindings. Can anyone suggest a Silverlight equivalent? Easier said than done! :s
Another Update:
Apparently you can simulate SetCurrentValue in .NET3.5 using value coercion, and you can simulate value coercion in Silverlight using these techniques. Perhaps there is a (long-winded) workaround here.
SetCurrentValue workaround for .NET3.5 using Value Coercion
Value Coercion workaround for Silverlight
Can't you just specify the default property of the dependency property:
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
"Items",
typeof(ObservableCollection<object>),
typeof(CaseDetailControl),
new PropertyMetadata(new ObservableCollection<object>()));
or am I missing what you are after?
Edit:
ah... in that case how about checking for null on the getter?:
public ObservableCollection<object> Items
{
get
{
if ((ObservableCollection<object>)GetValue(ItemsProperty) == null)
{
this.SetValue(ItemsProperty, new ObservableCollection<object>());
}
return (ObservableCollection<object>)GetValue(ItemsProperty);
}
set
{
this.SetValue(ItemsProperty, value);
}
}
When ObservableCollection properties misbehave, I try throwing out assignments to that property. I find that the references don't translate right and bindings get lost, somehow. As a result, I avoid actually setting ObservableCollection properties (preferring, instead, to clear the existing property and add elements to it). This becomes really sloppy with a DependencyProperty because you're going to call your getter multiple times in your setter. You might want to consider using INotifyPropertyChanged instead. Anyway, here's what it'd look like:
EDIT: Blatantly stole the getter from SteveL's answer. I reworked it a touch so that you only have a single call to GetValue, is all. Good work around.
public ObservableCollection<object> Items
{
get
{
ObservableCollection<object> coll = (ObservableCollection<object>)GetValue(ItemsProperty);
if (coll == null)
{
coll = new ObservableCollection<object>();
this.SetValue(ItemsProperty, coll);
}
return coll;
}
set
{
ObservableCollection<object> coll = Items;
coll.Clear();
foreach(var item in value)
coll.Add(item);
}
}
Note that this is depending on your default to set correctly. That means changing the static ItemsProperty default to be a new ObservableCollection of the correct type (i.e. new PropertyMetadata(new ObservableCollection()). You'll also have to remove that setter in the constructor. And note, I've no idea if that'll actually work. If not, you'll want to move to using INotifyPropertyChanged for sure...
New to WPF. I am creating UserControls that need read access to the ViewModel state to do their thing. I currently use the following technique:
public partial class ControlBar : UserControl
{
private static readonly DependencyProperty URLProperty =
DependencyProperty.Register("URL", typeof(string), typeof(ControlBar),
new UIPropertyMetadata(null));
public ControlBar()
{
InitializeComponent();
SetBinding(URLProperty, "CurrentPage.URL");
Pin.Click += Pin_Click;
}
private void Pin_Click(object sender, RoutedEventArgs e)
{
var URL = (string)GetValue(URLProperty);
}
}
Is this the correct way and is it not overkill to set up a long-term binding for each variable I need access to? Or can you do something like:
GetValue(new Path("CurrentPage.URL.....
I made up the above obviously.
Thanks!
In general data-binding is the way to go. However sometimes when you are creating controls that have view-specific concerns for which data-binding will not be appropriate.
In those cases you will want to be able to interact with the DependencyProperty to set it and know when it changes. I have been following a pattern that I picked up from a Charles Petzold article in MSDN magazine.
My answer to another question shows the pattern for creating a DependencyProperty for a UserControl Stack Overflow: Dependency Property In WPF/SilverLight
Again, data-binding to a view model will likely solve your problem, but a DependencyProperty may come in useful depending on the situation.
Update in response to comment:
In many situations you can data bind your in a UserControl without using a DependencyProperty. For example if you have a TextBlock that displays a name you would put a TextBlock in the XAML of the UserControl
<TextBlock Text="{Binding Path=NameString}" />
In the view model which is present in the DataContext you would have a property NameString and if the TextBlock is to update the display when the NameString property changes the view model should implement INotifyPropertyChanged and the property should fire the PropertyChanged event with the name of the property sent along with the event.
protected string _NameString;
public string NameString
{
get { return _NameString; }
set { _NameString = value: Notify("NameString"); }
}
Where Notify is a method that checks the PropertyChanged event for null and sends the event if not null.
This works well if everywhere that you want to use the UserControl has a view model with a Name property. The great thing is that the UserControl can pick up on the DataContext of wherever it is hosted and bind to an external view model.
When you want to start binding the same UserControl to different properties is one place that you may want to use a DependencyProperty. In that case you could make a UserControl with a DependencyProperty and bind it to different properties
<my:SampleControl NameString="{Binding Path=GivenName}" />
<my:SampleControl NameString="{Binding Path=FamilyName}" />
And then have an internal view model that the DependencyProperty change handler updates when the bound property changes.
Update: No DependencyProperty or binding
You can always add an ordinary C# property to the UserControl and pass the data in that way.
public MyClass Data { get; set; }
Then in the code-behind of the UserControl you can simply use the property:
if (this.Data != null)
{
this.textBox1.Text = Data.NameString;
}
Update in response to comment:
Another way to access the view model in code is to cast the DataContext to your view model type:
MyClass data = this.DataContext as MyClass;
if (data != null)
{
// do something
this.textBox1.Text = data.NameString;
}
I've seen a library that allows me to do this inside my XAML, which sets the visibility of the control based on whether or not the user is in a role:
s:Authorization.RequiresRole="Admin"
Using that library with my database requires a bunch of coding that I can't really do right now. Ultimately here's what I want to know...
I have received the authenticated users role from my SPROC, and its currently stored in my App.xaml.cs as a property (not necessary for the final solution, just FYI for now). I want to create a property (dependency property? attached property?) that allows me to say something very similar to what the other library has: RequiresRole="Admin", which would collapse the visibility if the user is not in the Admin role. Can anyone point me in the right direction on this?
EDIT
After building the authorization class, I get the following error:
"The property 'RequiredRole' does not exist on the type 'HyperlinkButton' in the XML Namespace clr-namespace:TSMVVM.Authorization"
I'm trying to add this xaml:
<HyperlinkButton x:Name="lnkSiteParameterDefinitions"
Style="{StaticResource LinkStyle}"
Tag="SiteParameterDefinitions"
Content="Site Parameter Definitions"
Command="{Binding NavigateCommand}"
s:Authorization.RequiredRole="Admin"
CommandParameter="{Binding Tag, ElementName=lnkSiteParameterDefinitions}"/>
When I started typing the s:Authorization.RequiredRole="Admin", intellisense picked it up. I tried setting the typeof(string) and typeof(ownerclass) to HyperlinkButton to see if that would help, but it didn't. Any thoughts?
Attached property is the way to implement it. You should define a property like this:
public class Authorization
{
#region Attached DP registration
public static string GetRequiredRole(UIElement obj)
{
return (string)obj.GetValue(RequiredRoleProperty);
}
public static void SetRequiredRole(UIElement obj, string value)
{
obj.SetValue(RequiredRoleProperty, value);
}
#endregion
// Using a DependencyProperty as the backing store for RequiredRole. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RequiredRoleProperty =
DependencyProperty.RegisterAttached("RequiredRole", typeof(string), typeof(Authorization), new PropertyMetadata(RequiredRole_Callback));
// This callback will be invoked when some control will receive a value for your 'RequiredRole' property
private static void RequiredRole_Callback(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
var uiElement = (UIElement) source;
RecalculateControlVisibility(uiElement);
// also this class should subscribe somehow to role changes and update all control's visibility after role being changed
}
private static void RecalculateControlVisibility(UIElement control)
{
//Authorization.UserHasRole() - is your code to check roles
if (Authentication.UserHasRole(GetRequiredRole(control)))
control.Visibility = Visibility.Visible;
else
control.Visibility = Visibility.Collapsed;
}
}
PS: Have noticed too late that you were asking about Silverlight. Though I believe it works in the same way there, but I've tried it only on WPF.