i m inheriting ListBox to my class and i want to override itemsource property.
i actually want to do someoperation when itemsource is assigned.
how it is possible?
i want in c# code only not in xaml
The way you override a dependency property in WPF is this way....
public class MyListBox : ListBox
{
//// Static constructor to override.
static MyListBox()
{
ListBox.ItemsSourceProperty.OverrideMetadata(typeof(MyListBox), new FrameworkPropertyMetadata(null, MyListBoxItemsSourceChanged));
}
private static void MyListBoxItemsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var myListBox = sender as MyListBox;
//// You custom code.
}
}
Is this what you are looking for?
Why not just set SourceUpdated event handler before setting the item source property?
For Example if MyListBox is your Listbox & MyItemSource is the source, you may set event handler n call it as follows:
void MyFunction()
{
MyListBox.SourceUpdated += new EventHandler<DataTransferEventArgs>(MyListBox_SourceUpdated);
MyListBox.ItemsSource = MyItemSource;
}
void MyListBox_SourceUpdated(object sender, DataTransferEventArgs e)
{
// Do your work here
}
Also, make sure that your data source implements INotifyPropertyChanged or INotifyCollectionChanged events.
Here i have crated a Custom List box which extends from Listbox and it got a dependency property itemssource...
When ever item source got updated you can do your operations and after that you can call the updatesourcemethod of customlistbox which will assign the itemsSource property of BaseClass.
public class CustomListBox : ListBox
{
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
// Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CustomListBox), new UIPropertyMetadata(0, ItemsSourceUpdated));
private static void ItemsSourceUpdated(object sender, DependencyPropertyChangedEventArgs e)
{
var customListbox = (sender as CustomListBox);
// Your Code
customListbox.UpdateItemssSource(e.NewValue as IEnumerable);
}
protected void UpdateItemssSource(IEnumerable source)
{
base.ItemsSource = source;
}
}
Related
My English skill is poor because I'm not a native English speaker.
I have created as following a behavior that working at the TextBox control.
The behavior has a collection-type DP named Items.
class HighlightBehavior : Behavior<TextBox>
{
public List<TextStyle>Items
{
get { return (List<TextStyle>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(List<TextStyle>), typeof(HighlightBehavior), new PropertyMetadata(ItemsChanged));
private static void ItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// break point
}
}
And... I have created a MainWindow to use as following code above behavior.
<MainWindow>
<TextBox>
<i:interaction.Behaviors>
<behavior:HighlightBehavior/>
</i:interaction.Behavior>
</TextBox>
</MainWindow>
And I have written a MainWindowViewModel that has a collection-type DP named HighlightItems.
class MainWindowViewModel : ViewModelBase
{
public List<TextStyle> HighlightItems
{
get { return (List<TextStyle>)GetValue(HighlightItemsProperty ); }
set { SetValue(HighlightItemsProperty , value); }
}
public static readonly DependencyProperty HighlightItemsProperty =
DependencyProperty.Register("HighlightItems", typeof(List<TextStyle>), typeof(HighlightBehavior), new PropertyMetadata(null));
public MainWindowViewModel()
{
SetValue(HighlightItemsProperty, new List<TextStyle>());
}
}
And I have bound the MainWindowViewModel to MainWindow and connected HighlightItems(DP) of MainWindowViewModel with Items(DP) of HighlightBehavior as the following code.
<MainWindow>
<TextBox>
<i:interaction.Behaviors>
<behavior:HighlightBehavior Items="{Binding HighlightItems, Mode=TwoWay}"/>
</i:interaction.Behavior>
</TextBox>
</MainWindow>
To sum up, the structure is the following figure.
I have expected that ItemsChanged of HighlightBehavior is called whenever Items changed.
But it is not called.
I want to get notification whenever collection-type DP(Items) of HighlightBehavior is changed.
What must I do to reach this goal?
Thank you for reading.
I'll wait for an answer.
I believe what you're looking for is ObservableCollection. This is a special type of collection which raises its CollectionChanged event whenever an item is added, removed, changed or moved.
I recommend the following:
Instead of declaring HighlightItems as List<TextStyle>, declare it as ObservableCollection<TextStyle>.
Add another method to HighlightBehavior to handle CollectionChanged, for example:
HighlightItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
Your current implementation of ItemsChanged will be called whenever HighlightItems is set. Use that to attach an event handler to CollectionChanged like so:
var col = (ObservableCollection<TextStyle>)e.NewValue;
if (col != null) { col.CollectionChanged += HighlightItemsCollectionChanged; }
Don't forget to remove any existing event handler to the previous collection in case HighlightItems is set move than once. You can add this to ItemsChanged along with the previous snippet:
col = (ObservableCollection<TextStyle>)e.OldValue;
if (col != null) { col.CollectionChanged -= HighlightItemsCollectionChanged; }
HighlightItemsCollectionChanged will now be called whenever an item is added or removed from HighlightItems. Do whatever you need to do in this method, or if you want the code to also run when the collection itself is replaced, you can make another method that actually does what you want, and then call that method from both ItemsChanged and HighlightItemsCollectionChanged.
Thank you.
I have changed the code following your advice and now I can receive a notification when the element of the collection is changed.
I knew about the ObservableCollection but I didn't know how to use right about CollectionChanged event.
In fact, previous I tried to use the ObservableCollection and registered the CollectionChanged delegate method at the Constructer as following but it is not called.
public ObservableCollection<TextStyle> Items
{
get { return (ObservableCollection<TextStyle>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
// Using a DependencyProperty as the backing store for Items. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(ObservableCollection<TextStyle>), typeof(HighlightBehavior),
new PropertyMetaData(null));
public HighlightBehavior()
{
SetValue(ItemsProperty, new ObservableCollection<TextStyle>());
Items.CollectionChanged += OnCollectionChanged;
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// The code when the collection is changed.
}
Now, I have registered the CollectionChanged delegate method in the PropertyChangedCallback method as following and it(OnCollectionChanged method at the following code) is called.
public ObservableCollection<TextStyle> Items
{
get { return (ObservableCollection<TextStyle>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
// Using a DependencyProperty as the backing store for Items. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(ObservableCollection<TextStyle>), typeof(HighlightBehavior),
new PropertyMetaData(ItemsChanged));
private static void ItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var col = (ObservableCollection<TextStyle>)e.NewValue;
if (col != null) { col.CollectionChanged += OnCollectionChanged; ; }
col = (ObservableCollection<TextStyle>)e.OldValue;
if (col != null) { col.CollectionChanged -= OnCollectionChanged; }
}
public HighlightBehavior()
{
SetValue(ItemsProperty, new ObservableCollection<TextStyle>());
}
Thank you for your answer in detail.
I have a question, someone could help transform this code (used in codebehind ) for use by dependyProperty ?
This code gives the focus to the first item of listview . THX!!!!!!
private void ItemContainerGeneratorOnStatusChanged(object sender, EventArgs eventArgs)
{
if (lvResultado.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
var index = lvResultado.SelectedIndex;
if (index >= 0)
{
var item = lvResultado.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
if (item != null)
{
item.Focus();
}
}
}
}
Specifically, I want to write something like: local:FocusFirstElement.Focus="True" in my XAML instead of writing this code for every list view.
What you are is really an attached behavior, which is implemented via an attached property which is really a special dependency property (which you seem to have hit upon already).
First, create an attached property. This is most easliy accomplished using the propa snippet:
public static bool GetFocusFirst(ListView obj)
{
return (bool)obj.GetValue(FocusFirstProperty);
}
public static void SetFocusFirst(ListView obj, bool value)
{
obj.SetValue(FocusFirstProperty, value);
}
public static readonly DependencyProperty FocusFirstProperty =
DependencyProperty.RegisterAttached("FocusFirst", typeof(bool),
typeof(ListViewExtension), new PropertyMetadata(false));
I'm assuming this is in a static class called ListViewExtenstion. Then, handle the property changed event:
public static readonly DependencyProperty FocusFirstProperty =
DependencyProperty.RegisterAttached("FocusFirst", typeof(bool),
typeof(ListViewExtension), new PropertyMetadata(false, HandleFocusFirstChanged));
static void HandleFocusFirstChanged(
DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
}
In that handler you would check the current value (in e) and register or deregister for the appropriate event on the ListView contained in depObj. Then you would use your existing code to set the focus. Something like:
static void HandleFocusFirstChanged(
DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
ListView lv = (ListView)debObj;
if ((bool)e.NewValue)
lv.StatusChanged += MyLogicMethod;
}
I'm working on a custom WPF UserControl and having an issue with one of my DependencyProperties.
So I built a test scenario that looks like this. In the Custom Control..
public static readonly DependencyProperty MyCollectionItemsSourceProperty = DependencyProperty.Register("DynamicHeaderItemsSource", typeof(IEnumerable), typeof(TestUserControl1),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnMyCollectionItemsSourceChanged)));
public IEnumerable MyCollectionItemsSource
{
get { return (IEnumerable)GetValue(MyCollectionItemsSourceProperty ); }
set { SetValue(MyCollectionItemsSourceProperty , value); }
}
protected static void OnMyCollectionItemsSourceChanged(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
System.Diagnostics.Debug.WriteLine("MyCollection Updated");
}
In my test window's code behind:
public ObservableCollection<string> MyTestStrings { get; set; }
private void Window_Loaded(object sender, RoutedEventArgs e)
{
MyTestStrings.Add("First");
MyTestStrings.Add("Second");
MyTestStrings.Add("Third");
}
And in my test window's XAML:
<Grid>
<local:TestUserControl1 MyCollectionItemsSource="{Binding MyTestStrings}">
</Grid>
The problem is, I never get a notification of any type when the underline collection changes. The OnMyCollectionItemsSourceChanged only ever gets called once: at the beginning when the binding is set. What am I missing?
It is an expected behavior your MyCollectionItemsSource just change when it is set in XAML binding since (one time )t hen those adds in the collection is not changing your property itself (it is doing something inside of the collection).
if you want to get information about changing collection you have to first in OnMyCollectionItemsSourceChanged event test if the vale supports INotifyCollectionChanged this then register for NotifyCollectionChangedEventHandler isndie, do not forget to unregister your handler
protected static void OnMyCollectionItemsSourceChanged(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
if( args.OldValue is INotifyCollectionChanged)
(args.OldValue as INotifyCollectionChanged ).CollectionChanged -= CollectionChangedHandler;
if(args.NewValue is INotifyCollectionChanged)
(args.OldValue as INotifyCollectionChanged).CollectionChanged += CollectionChangedHandler;
}
private static void CollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e)
{
//
}
The PropertyChangedCallback will be called only when the property is set (or nullified) not if there are any changes to the collection itself (adding/removing elements). To do that you will have to hook up to the CollectionChanged event. See this post: https://stackoverflow.com/a/12746855/4173996
As the SelectedItems property of the ListBox control is a normal property and not a dependency property to bind to, I have derived of the ListBox and created a new dependency property SelectedItemsEx.
But my XAML compiler keeps giving me the error
A 'Binding' cannot be set on the 'SelectedItemsEx' property of the
type 'MyListBox'. A 'Binding' can only be set on a DependencyProperty
of a DependencyObject.
Why my property is not recognized as a dependency property? Any help is appreciated, thank you!
XAML:
<MyListBox ItemsSource="{Binding MyData}" SelectedItemsEx="{Binding SelectedEx}"
SelectionMode="Extended"> ... </MyListBox>
ListBox' implementation:
public class MyListBox : ListBox
{
public readonly DependencyProperty SelectedItemsExProperty =
DependencyProperty.Register("SelectedItemsEx",
typeof(ObservableCollection<MyItemsDataType>),
typeof(MyListBox),
new PropertyMetadata(default(ObservableCollection<MyItemsDataType>)));
public ObservableCollection<MyItemsDataType> SelectedItemsEx
{
get
{
var v = GetValue(SelectedItemsExProperty);
return (ObservableCollection<MyItemsDataType>)v;
}
set { SetValue(SelectedItemsExProperty, value); }
}
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
if (SelectedItemsEx != null)
{
SelectedItemsEx.Clear();
foreach (var item in base.SelectedItems)
{
SelectedItemsEx.Add((MyItemsDataType)item);
}
}
}
The DependencyProperty field must be static:
public static readonly DependencyProperty SelectedItemsExProperty = ...
Note also that in order to make your derived ListBox a little more reusable, you should not constrain the type of the SelectedItemsEx property. Use IEnumerable (or IList like SelectedItems) instead. Moreover, there is no need to specify a default value by property metadata, as it is null already and default(<any reference type>) is also null.
You will however have to get notified whenever the SelectedItemsEx property has changed. Therefore you have to register a change callback via property metadata:
public static readonly DependencyProperty SelectedItemsExProperty =
DependencyProperty.Register(
"SelectedItemsEx", typeof(IEnumerable), typeof(MyListBox),
new PropertyMetadata(SelectedItemsExPropertyChanged));
public IEnumerable SelectedItemsEx
{
get { return (IEnumerable)GetValue(SelectedItemsExProperty); }
set { SetValue(SelectedItemsExProperty, value); }
}
private static void SelectedItemsExPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var listBox = (MyListBox)obj;
var oldColl = e.OldValue as INotifyCollectionChanged;
var newColl = e.NewValue as INotifyCollectionChanged;
if (oldColl != null)
{
oldColl.CollectionChanged -= listBox.SelectedItemsExCollectionChanged;
}
if (newColl != null)
{
newColl.CollectionChanged += listBox.SelectedItemsExCollectionChanged;
}
}
private void SelectedItemsExCollectionChanged(
object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
...
}
}
I can't find an event that can be called after a window was loaded, and where i can get access to the ItemsSource of a ListView. The only thing i can think is the Loaded event in the ListView but when this event is fired the ItemsSource remains null.
I probably need another event so i can know what is in the ItemsSource.
So with code i will probably expose better what i am trying to do:
In a custom class:
public class GridViewSomething
{
public static readonly DependencyProperty TestProperty =
DependencyProperty.RegisterAttached("Test",
typeof(bool),
typeof(GridViewSomething),
new UIPropertyMetadata(OnTestChanged));
public static bool GetTest(DependencyObject obj)
{
return (bool)obj.GetValue(TestProperty);
}
public static void SetTest(DependencyObject obj, bool value)
{
obj.SetValue(TestProperty, value);
}
static void OnTestChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ListView listView = sender as ListView;
if (!(bool)e.OldValue && (bool)e.NewValue)
listView.AddHandler(ListView.LoadedEvent, new RoutedEventHandler(ListView_Loaded));
else if (!(bool)e.NewValue && (bool)e.OldValue)
listView.RemoveHandler(ListView.LoadedEvent, new RoutedEventHandler(ListView_Loaded);
}
static void ListView_Loaded(object sender, RoutedEventArgs e)
{
ListView listView = sender as ListView;
if (listView.ItemsSource != null)
{
//Do some work
}
}
}
And the ListView:
(...)
<ListView ItemsSource="{Binding Students}"
test:GridViewSomething.Test="True">
(...)
I am binding the ListView to a Collection in the ViewModel of this Window. I need to know precisely what is in the ItemsSource in that custom class.
So how i can achieve this?
Thanks in advance!
You could subsribe to changes on the ItemsSource property by using a descriptor as shown here. If check the value in that handler it should not be null (unless the bound property was in fact set to null).