Windows Phone 7.1 project (WP 8.0 SDK), I want to pass current item in ItemTemplate to a user control.
XAML:
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:ShipControl Ship="{Binding}" x:Name="ShipControl"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
Code behind ShipControl:
public object Ship
{
get
{
return GetValue(ShipProperty);
}
set
{
SetValue(ShipProperty, value);
}
}
//Used by xaml binding
public static readonly DependencyProperty ShipProperty = DependencyProperty.Register("Ship", typeof(Ship), typeof(Ship), new PropertyMetadata(null, new PropertyChangedCallback(OnShipChanged)));
private static void OnShipChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//TODO: Set break point here
return;
}
However, when debugging Ship an object of value DataBinding is passed as value, not a Ship (therefore return type is object instead of Ship). That eventually causes an exception on SetValue.
Other bindings on Ship-properties do work, so I really have no idea. According to this question, above should work:
WPF Pass current item from list to usercontrol
See here for sample project which throws exception on data binding, because passed object is Binding instead of data object. http://dl.dropbox.com/u/33603251/TestBindingApp.zip
You need to put a x:Name="MyControl" in your control, and then your binding will look like Ship="{Binding ElementName=MyList, Path=CurrentItem}" instead of just {Binding} (which does not mean much AFAIK). Your control needs to expose the CurrentItem property.
If you do not want to explicity name your control, you can try to play with Relative Source but I did not try myself so cannot help you on this one.
Your Dependency Property is badly formed so the XAML parser does not treat it as such.
You need to change your instance property type to Ship, and DependencyProperty owner type to ShipControl. Then the Binding will work (assuming that you are binding to a list of Ships).
public Ship Ship
{
get { return (Ship)GetValue(ShipProperty); }
set { SetValue(ShipProperty, value); }
}
public static readonly DependencyProperty ShipProperty =
DependencyProperty.Register("Ship", typeof(Ship), typeof(ShipControl), new PropertyMetadata(null, new PropertyChangedCallback(OnShipChanged)));
private static void OnShipChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//TODO: Set break point here
return;
}
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'm new to the development of custom controls in WPF, but I tried to develop a single one to use in a application that I'm developing. This control is an autocomplete textbox. In this control, I have a DependencyProprety that has a list of possible entries so a person can choose from while entering the text
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource",typeof (IList<object>),typeof (AutoCompleteTextBox),new PropertyMetadata(null));
public IList<object> ItemsSource
{
get { return (IList<object>) GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
RaiseOnPropertyChanged("ItemsSource");
}
}
I use this control in a usercontrol and associate this control to a property in the viewmodel
<CustomControls:AutoCompleteTextBox Height="23" Width="200"
VerticalAlignment="Center" Text="{Binding Path=ArticleName, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Path=Articles,
Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
</CustomControls:AutoCompleteTextBox>
I have a viewmodel that I assign on the usercontrol load to the datacontext of the usercontrol load
protected virtual void Window_Loaded(object sender, RoutedEventArgs e)
{
if (!DesignerProperties.GetIsInDesignMode(this))
{
this.DataContext = viewModel;
SetLabels();
}
}
This viewmodel has the property Articles with values but the ItemsSource property of the control is null when I try to search in the list after the user enter some text.
Is there any special step that I missed when I create the control so use the mvvm pattern.
I hope that the explain the problem in a understandable way. Any help/hints would be welcome.
There are two issues here:
First, you're dependency property is defining the "default" value for this property to be null. You can change that by changing the metadata to specify a new collection:
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource",typeof (IList<object>),typeof (AutoCompleteTextBox),
new PropertyMetadata(new List<object>));
Secondly, when using dependency properties, the setter can't contain any logic. You should keep your property set as:
public IList<object> ItemsSource
{
get { return (IList<object>) GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
This is because the setter doesn't actually get called by the binding system - only when you use code. However, since the class is a DependencyObject and this is a DP, you don't need to raise property changed events.
How can i get the itemsourcechangedevent in listbox?
For eg. the itemsource changes from null to ListA then to ListB
I know there is no such event. But is there any workaround for this?
Thanks in advance :)
A commonly used (answered) approach is use the PropertyChangedTrigger from the Blend SDK. However I don't like recommending the use of other SDKs unless there is a clear indication the SDK is already in use.
I'll assume for the moment that its in code-behind that you want listen for a "ItemsSourceChanged" event. A technique you can use is to create a DependencyProperty in your UserControl and bind it to the ItemsSource of the control you want to listen to.
private static readonly DependencyProperty ItemsSourceWatcherProperty =
DependencyProperty.Register(
"ItemsSourceWatcher",
typeof(object),
typeof(YourPageClass),
new PropertyMetadata(null, OnItemsSourceWatcherPropertyChanged));
private static void OnItemsSourceWatcherPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
YourPageClass source = d As YourPageClass;
if (source != null)
source.OnItemsSourceWatcherPropertyChanged();
}
private void OnItemsSourceWatcherPropertyChanged()
{
// Your code here.
}
Now given that your ListBox has a name "myListBox" you can set up watching with:-
Binding b = new Binding("ItemsSource") { Source = myListBox };
SetBinding(ItemsSourceWatcherProperty, b);
There is no ItemsSourceChanged event in Silverlight.
But, there is a workaround. Use RegisterForNotification() method mentioned in this article to register a property value change callback for ListBox's ItemsSource property.
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.
I am making a custom control I need to add some default keybindings, microsoft has already done with copy and paste in a textbox. However one of the keybindings needs to pass a parameter to the command which it is bound to. It is simple to do this in xaml, is there any way to do this in code?
this.InputBindings.Add(new KeyBinding(ChangeToRepositoryCommand, new KeyGesture(Key.F1)));
I found the answer:
InputBindings.Add(new KeyBinding(ChangeToRepositoryCommand, new KeyGesture(Key.F1)) { CommandParameter = 0 });
I apologize if my question was unclear.
The copy and paste commands are handled by the text box so parameters are not strictly passed, but i know what you are getting at.
I do this using a hack - and an attached property, like so
public class AttachableParameter : DependencyObject {
public static Object GetParameter(DependencyObject obj) {
return (Object)obj.GetValue(ParameterProperty);
}
public static void SetParameter(DependencyObject obj, Object value) {
obj.SetValue(ParameterProperty, value);
}
// Using a DependencyProperty as the backing store for Parameter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ParameterProperty =
DependencyProperty.RegisterAttached("Parameter", typeof(Object), typeof(AttachableParameter), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
}
then in the xaml
<ListBox local:AttachableParameter.Parameter="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItems}" />
which makes the parameter the selected items
then when the command fires on the window i use this to see if the command parameter is there (i call this from the can execute and the Executed)
private Object GetCommandParameter() {
Object parameter = null;
UIElement element = FocusManager.GetFocusedElement(this) as UIElement;
if (element != null) {
parameter = AttachableParameter.GetParameter(element as DependencyObject);
}
return parameter;
}
It is a hack, but i have not found another way to get the command parameter for a binding that is fired from a key binding. (I would love to know a better way)