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.
Related
I need to add some logic to user control with DependencyProperty.
My logic is supposed to change properties on controls inside my UserControl.
I want to avoid building huge "dependency tree" because I have a lot of user controls. I just want to use binding in my windows (not in nested user controls).
This is my control:
public partial class BucketElevatorControl : UserControl
{
public BucketElevatorControl()
{
InitializeComponent();
}
public bool On
{
get
{
return (bool)GetValue(OnProperty);
}
set
{
SetValue(OnProperty, value);
}
}
// Using a DependencyProperty as the backing store for IsOn. This enables animation, styling, binding, etc...
public static readonly DependencyProperty OnProperty = DependencyProperty.Register(
"On",
typeof(bool),
typeof(BucketElevatorControl),
new PropertyMetadata(
false, PropertyChangedCallback
));
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
// I want to do something with my UserControl child controls
}
}
The question is: how can I do some logic in contol code behind and take advantage of data binding?
My logic is complicated (drawing graphics, animations etc.).
You should create CoerceValueCallbacks for the properties you want to change. Those callbacks set the new values. When this property changes, you then coerce the others, like so:
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
dependencyObject.CoerceValue(MinReadingProperty);
dependencyObject.CoerceValue(MaxReadingProperty);
}
I have no idea what you mean by "dependency tree", but if you want to alter the state of stuff in your template according to changes in your control's dependency properties, you can do that with TemplateBinding and/or triggers in your control template. Write value converters if you need to. Most of what you need to do can probably be done that way.
If you need more complicated logic, you can also override OnApplyTemplate() in your control, and call GetTemplateChild() to get named controls within the control's template. For example, you might require the template to have a TextBox somewhere in it called PART_FooText; throw an exception if you get null from GetTemplateChild("PART_FooText") as TextBox. If the TextBox is there, do anything you like to it: Handle events, set properties, etc. If you like, keep a private field TextBox _PART_FooText; to fiddle with it later on, in your property-changed callbacks, other events, or whatever.
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;
}
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...
I have the following code to subscribe to property changed event for VisiblePosition property of Column class:
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(ColumnBase.VisiblePositionProperty, typeof(Column));
if (dpd != null)
{
dpd.AddValueChanged(col, ColumnVisiblePositionChangedHandler);
}
Here is the definition of the ColumnVisiblePositionChangedHandler method:
static internal void ColumnVisiblePositionChangedHandler(object sender, EventArgs e)
The problem is I need to get the old value of the property. How do I do that?
Thanks,
Unfortunately, you don't get old value information when registering property changed event handler this way.
One workaround is to store property value somewhere (this is your 'old' value) and then compare it to current value in the event handler.
Another workaround is to create your own dependency property (DP) and create binding between your DP and the control's DP. This will give you change notification in the WPF style.
Here is an article about this.
You can do that when you register your dependency property in the attached event handler. Please find below the syntax for a dependency property and how to get the old value on PropertyChanged event handler:
//Declaration of property
public static readonly DependencyProperty MyNameProperty =
DependencyProperty.Register("MyName",
typeof(PropertyType),
typeof(ClassName),
new PropertyMetadata(null,
new PropertyChangedCallback(MyNameValueChanged)));
//PropertyChanged event handler to get the old value
private static void MyNameValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
{
object oldValue = eventArgs.OldValue; //Get the old value
}
I've got a custom control which has a DependencyProperty MyAnimal - I'm binding an Animal Property on my ViewModel to the MyAnimal DependencyProperty.
I've stuck a TextBox on the Control so I can trigger an Event - whenever I trigger the event the MyAnimal property has been set - however if I put a break point on the Setter of the MyAnimal property it never gets fired!
I guess I'm missing something fundamental about WPF Dependency Properties/Binding?!
And so my question is, if I can't use the Setter how can I find out when its been set? If I put if I put a break point after InitializeComponent() its null and I had a look to see if theres an Event a can hook up to - DatabindingFinished or similar? but can't see what it would be ...
Can anyone assist please?
Thanks,
Andy
public partial class ControlStrip
{
public ControlStrip()
{
InitializeComponent();
}
public Animal MyAnimal
{
get
{
return (Animal)GetValue(MyAnimalProperty);
}
set
{
SetValue(MyAnimalProperty, value);
}
}
public static readonly DependencyProperty MyAnimalProperty =
DependencyProperty.RegisterAttached("MyAnimal", typeof (Animal), typeof (ControlStrip));
private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
var myAnimal = MyAnimal;
MessageBox.Show(myAnimal.Name);
}
}
The setter methods are never called by the runtime. They go directly to the DependencyProperty. You will need to add an additional argument to your call to RegisterAttached(). There you can add a PropertyChangedCallback.
Here is some sample code:
public static readonly DependencyProperty MyAnimalProperty =
DependencyProperty.RegisterAttached("MyAnimal", typeof (Animal), typeof (ControlStrip), new PropertyMetadata(AnimalChanged));
private static void AnimalChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
// Do work here
}
The setter is only there for your use - you actually can leave the property off entirely, since DataBinding uses the actual DependencyProperty itself, not the CLR property.
If you need to see when the property changes, you will need to specify PropertyMetadata on your dependency property, and provide a PropertyChangedCallback.
For details, I recommend reading Dependency Property Metadata.