I created an attached property for ListBox like this:
using ListBoxControl = System.Windows.Controls.ListBox;
namespace App.Ui.Views.AttachedProperties
{
public class ListBox
{
public static readonly DependencyProperty autoScrollProperty =
DependencyProperty.RegisterAttached(
"AutoScroll",
typeof(bool),
typeof(ListBoxControl),
new PropertyMetadata(false));
public static void SetAutoScroll(ListBoxControl element, bool value)
{
element.SetValue(autoScrollProperty, value);
if (value)
{
element.SelectionChanged += Element_SelectionChanged;
}
else
{
element.SelectionChanged -= Element_SelectionChanged;
}
}
public static bool GetAutoScroll(ListBoxControl element)
{
return (bool)element.GetValue(autoScrollProperty);
}
private static void Element_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = (ListBoxControl)sender;
listBox.ScrollIntoView(listBox.SelectedItem);
}
}
}
When I use a static True/False value in the xaml, it works fine:
<ListBox ap:ListBox.AutoScroll="True">
...
</ListBox>
But if I data bind to a property in my view model:
<ListBox ap:ListBox.AutoScroll="{Binding Path=Settings.EnableAutoScroll}">
...
</ListBox>
Then I get the following exception: A 'Binding' cannot be set on the 'SetAutoScroll' property of type 'ListBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
Is this possible, or am I going to need to derive my own custom list box to accomplish this?
Problem in this line typeof(ListBoxControl). You should specify the name of the class where custom attached property seats.
I would recommend rename class from ListBox to ListBoxExtensions, also, make it static. Then you don't have to use alias ListBoxControl.
Your final code will look like:
public static class ListBoxExtensions
{
public static readonly DependencyProperty autoScrollProperty =
DependencyProperty.RegisterAttached(
"AutoScroll",
typeof(bool),
typeof(ListBoxExtensions),
new PropertyMetadata(false));
...
}
Edit:
OK, your code has another problem.
Remove attachment of the listener from setter (SetAutoScroll) and put this logic into dependency property callback.
public static class ListBoxExtensions
{
public static readonly DependencyProperty autoScrollProperty =
DependencyProperty.RegisterAttached(
"AutoScroll",
typeof(bool),
typeof(ListBoxExtensions),
new PropertyMetadata(false, AutoScrollChangedCallback));
public static void SetAutoScroll(ListBox element, bool value)
{
element.SetValue(autoScrollProperty, value);
}
public static bool GetAutoScroll(ListBox element)
{
return (bool)element.GetValue(autoScrollProperty);
}
private static void AutoScrollChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListBox control = (ListBox)d;
if ((bool)e.NewValue)
{
control.SelectionChanged += Element_SelectionChanged;
}
else
{
control.SelectionChanged -= Element_SelectionChanged;
}
}
private static void Element_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listBox = (ListBox)sender;
listBox.ScrollIntoView(listBox.SelectedItem);
}
}
I'm having really hard time trying to make listbox multiselection bindable, basically the same as this article : http://blogs.microsoft.co.il/miziel/2014/05/02/wpf-binding-listbox-selecteditems-attached-property-vs-style/
This is my class for the listbox :
public partial class ListBoxMultipleSelection : UserControl
{
public ListBoxMultipleSelection()
{
InitializeComponent();
this.DataContext = this;
}
public static readonly DependencyProperty ItemSourceProperty =
DependencyProperty.Register("ItemSource", typeof(ObservableCollection<string>), typeof(ListBoxMultipleSelection), new PropertyMetadata(new ObservableCollection<string>()));
public ObservableCollection<string> ItemSource
{
get { return (ObservableCollection<string>)this.GetValue(ItemSourceProperty); }
set { this.SetValue(ItemSourceProperty, value); }
}
private static ListBox list;
private static bool _isRegisteredSelectionChanged = false;
///
/// SelectedItems Attached Dependency Property
///
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.RegisterAttached("SelectedItems", typeof(IList),
typeof(ListBoxMultipleSelection),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnSelectedItemsChanged)));
public static IList GetSelectedItems(DependencyObject d)
{
return (IList)d.GetValue(SelectedItemsProperty);
}
public static void SetSelectedItems(DependencyObject d, IList value)
{
d.SetValue(SelectedItemsProperty, value);
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!_isRegisteredSelectionChanged)
{
var listBox = (ListBox)d;
list = listBox;
listBox.SelectionChanged += listBox_SelectionChanged;
_isRegisteredSelectionChanged = true;
}
}
private static void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
IEnumerable listBoxSelectedItems = list.SelectedItems;
IList ModelSelectedItems = GetSelectedItems(list);
ModelSelectedItems.Clear();
if (list.SelectedItems != null)
{
foreach (var item in list.SelectedItems)
ModelSelectedItems.Add(item);
}
SetSelectedItems(list, ModelSelectedItems);
}
}
And the XAML for the usercontrol/listbox :
<Grid>
<ListBox SelectionMode="Multiple"
local:ListBoxMultipleSelection.SelectedItems="{Binding DataContext.SelectedItems}"
ItemsSource="{Binding DataContext.ItemSource, ElementName=MultiListBox, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
The problem is "listBox_SelectionChanged" is never fired and so nothing is updated correctly. Any idea ?
Thank you
I am struggling with a dependencyproperty in a control. My dependencyproperty is an object which looks like this:
public class ChartGroupCollection : ObservableCollection<ChartGroup>, INotifyCollectionChanged
{
public void ClearDirty()
{
foreach (var grp in base.Items)
{
foreach(var run in grp.ChartRuns.Where(x=>x.IsDirty))
{
run.IsDirty = false;
}
grp.IsDirty = false;
}
}
[XmlIgnore]
public bool IsDirty //dirty flag for save prompt
{
get
{
....
}
}
}
[Serializable]
public class ChartGroup : INotifyPropertyChanged
{ ... //various properties }
The DependencyProperty is set up as here (named Tree, which is instance of a ChartGroupCollection):
public static readonly DependencyProperty TreeProperty = DependencyProperty.Register("Tree", typeof(ChartGroupCollection), typeof(ChartsControl), new PropertyMetadata(OnTreeChanged));
public ChartGroupCollection Tree
{
get { return (ChartGroupCollection)GetValue(TreeProperty); }
set { SetValue(TreeProperty, value); }
}
private static void OnTreeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var Treee = sender as ChartsControl;
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged)e.OldValue;
coll.CollectionChanged -= Tree_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<ChartGroup>)e.NewValue;
coll.CollectionChanged += Tree_CollectionChanged;
}
}
private static void Tree_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
(sender as ChartsControl).OnTreeChanged();
}
void OnTreeChanged()
{
MessageBox.Show("Do something..."); //RefreshCharts();
}
I seem to be getting to the OnTreeChanged event only at creation of the object, but once i do other work (adding to lists inside ChartGroup or changing properties of ChartGroup objects or even deleting elements of the observablecollection it never seems to trigger a refresh event. I have tried several other methods of getting the dependencyproperty found online but no solution worked for me. I wonder if it is down to the intrinsic nature of my dependencyproperty object or an error from my side
The sender argument in your Tree_CollectionChanged handler is not the ChartsControl instance, but the collection that raised the CollectionChanged event.
The Tree_CollectionChanged method should not be static
private void Tree_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnTreeChanged();
}
and it should be attached and removed like this:
private static void OnTreeChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as ChartsControl;
var oldCollection = e.OldValue as INotifyCollectionChanged;
var newCollection = e.NewValue as INotifyCollectionChanged;
if (oldCollection != null)
{
oldCollection.CollectionChanged -= control.Tree_CollectionChanged;
}
if (newCollection != null)
{
newCollection.CollectionChanged += control.Tree_CollectionChanged;
}
}
Note also that adding a CollectionChanged handler does not care for subscribing to PropertyChanged events of the collection elements. You would also have to attach or remove a PropertyChanged handler whenever an element is added to or removed from the collection. Take a look at the NotifyCollectionChangedEventArgs.Action property.
How could I access a XAML object in my ViewModel? I am really confused. I want to access the <Controls:ModalContentPresenter> object. How could I realise this in a MVVM conform way? On this object I want to call a method ShowModalContent
<Controls:ModalContentPresenter x:Name="modalContent">
<ScrollViewer Behaviors:AdvancedZooming.KeepInCenter="true" Visibility="{Binding LeerformularIsVisible}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Viewbox Stretch="Uniform">
<Grid>
<DataGrid BorderBrush="{x:Null}">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding AddFieldDefinitionCommand}" Header="Feld hinterlegen" Icon="pack://application:,,,/Images/Designer/field.png" />
<MenuItem Command="{Binding AddFunctionCommand}" Header="Funktion hinterlegen" Icon="pack://application:,,,/Images/Designer/FI_Taschenmesser_16x16.png" />
<MenuItem Command="{Binding RemoveFieldDefinitionCommand}" Header="Aktuelle Felddefinition entfernen" Icon="pack://application:,,,/Images/Designer/remove_field.png" />
<MenuItem Command="{Binding CutCommand}" Header="Ausschneiden" Icon="pack://application:,,,/Images/Zwischenablage/FI_Ausschneiden_16x16.png" />
<MenuItem Command="{Binding CopyCommand}" Header="Kopieren" Icon="pack://application:,,,/Images/Zwischenablage/FI_Kopieren_16x16.png" />
<MenuItem Command="{Binding PasteCommand}" Header="Einfügen" Icon="pack://application:,,,/Images/Zwischenablage/FI_Einfuegen_16x16.png" />
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Viewbox>
</ScrollViewer>
<Controls:ModalContentPresenter.ModalContent>
<StackPanel>
<TextBlock>Test</TextBlock>
<Button>Hide</Button>
</StackPanel>
</Controls:ModalContentPresenter.ModalContent>
</Controls:ModalContentPresenter>
The code of ModalContentPresenter can be found here:
using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
namespace Controls
{
[ContentProperty("Content")]
public class ModalContentPresenter : FrameworkElement
{
#region private fields
private Panel layoutRoot;
private ContentPresenter primaryContentPresenter;
private ContentPresenter modalContentPresenter;
private Border overlay;
private object[] logicalChildren;
private KeyboardNavigationMode cachedKeyboardNavigationMode;
private static readonly TraversalRequest traversalDirection;
#endregion
#region dependency properties
public static readonly DependencyProperty IsModalProperty = DependencyProperty.Register("IsModal", typeof(bool), typeof(ModalContentPresenter),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsModalChanged));
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(ModalContentPresenter),
new UIPropertyMetadata(null, OnContentChanged));
public static readonly DependencyProperty ModalContentProperty = DependencyProperty.Register("ModalContent", typeof(object), typeof(ModalContentPresenter),
new UIPropertyMetadata(null, OnModalContentChanged));
public static readonly DependencyProperty OverlayBrushProperty = DependencyProperty.Register("OverlayBrush", typeof(Brush), typeof(ModalContentPresenter),
new UIPropertyMetadata(new SolidColorBrush(Color.FromArgb(204, 169, 169, 169)), OnOverlayBrushChanged));
public bool IsModal
{
get { return (bool)GetValue(IsModalProperty); }
set { SetValue(IsModalProperty, value); }
}
public object Content
{
get { return (object)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public object ModalContent
{
get { return (object)GetValue(ModalContentProperty); }
set { SetValue(ModalContentProperty, value); }
}
public Brush OverlayBrush
{
get { return (Brush)GetValue(OverlayBrushProperty); }
set { SetValue(OverlayBrushProperty, value); }
}
#endregion
#region routed events
public static readonly RoutedEvent PreviewModalContentShownEvent = EventManager.RegisterRoutedEvent("PreviewModalContentShown", RoutingStrategy.Tunnel,
typeof(RoutedEventArgs), typeof(ModalContentPresenter));
public static readonly RoutedEvent ModalContentShownEvent = EventManager.RegisterRoutedEvent("ModalContentShown", RoutingStrategy.Bubble,
typeof(RoutedEventArgs), typeof(ModalContentPresenter));
public static readonly RoutedEvent PreviewModalContentHiddenEvent = EventManager.RegisterRoutedEvent("PreviewModalContentHidden", RoutingStrategy.Tunnel,
typeof(RoutedEventArgs), typeof(ModalContentPresenter));
public static readonly RoutedEvent ModalContentHiddenEvent = EventManager.RegisterRoutedEvent("ModalContentHidden", RoutingStrategy.Bubble,
typeof(RoutedEventArgs), typeof(ModalContentPresenter));
public event RoutedEventHandler PreviewModalContentShown
{
add { AddHandler(PreviewModalContentShownEvent, value); }
remove { RemoveHandler(PreviewModalContentShownEvent, value); }
}
public event RoutedEventHandler ModalContentShown
{
add { AddHandler(ModalContentShownEvent, value); }
remove { RemoveHandler(ModalContentShownEvent, value); }
}
public event RoutedEventHandler PreviewModalContentHidden
{
add { AddHandler(PreviewModalContentHiddenEvent, value); }
remove { RemoveHandler(PreviewModalContentHiddenEvent, value); }
}
public event RoutedEventHandler ModalContentHidden
{
add { AddHandler(ModalContentHiddenEvent, value); }
remove { RemoveHandler(ModalContentHiddenEvent, value); }
}
#endregion
#region ModalContentPresenter implementation
static ModalContentPresenter()
{
traversalDirection = new TraversalRequest(FocusNavigationDirection.First);
}
public ModalContentPresenter()
{
layoutRoot = new ModalContentPresenterPanel();
primaryContentPresenter = new ContentPresenter();
modalContentPresenter = new ContentPresenter();
overlay = new Border();
AddVisualChild(layoutRoot);
logicalChildren = new object[2];
overlay.Background = OverlayBrush;
overlay.Child = modalContentPresenter;
overlay.Visibility = Visibility.Hidden;
layoutRoot.Children.Add(primaryContentPresenter);
layoutRoot.Children.Add(overlay);
}
public void ShowModalContent()
{
if (!IsModal)
IsModal = true;
}
public void HideModalContent()
{
if (IsModal)
IsModal = false;
}
private void RaiseModalContentShownEvents()
{
RoutedEventArgs args = new RoutedEventArgs(PreviewModalContentShownEvent);
OnPreviewModalContentShown(args);
if (!args.Handled)
{
args = new RoutedEventArgs(ModalContentShownEvent);
OnModalContentShown(args);
}
}
private void RaiseModalContentHiddenEvents()
{
RoutedEventArgs args = new RoutedEventArgs(PreviewModalContentHiddenEvent);
OnPreviewModalContentHidden(args);
if (!args.Handled)
{
args = new RoutedEventArgs(ModalContentHiddenEvent);
OnModalContentHidden(args);
}
}
protected virtual void OnPreviewModalContentShown(RoutedEventArgs e)
{
RaiseEvent(e);
}
protected virtual void OnModalContentShown(RoutedEventArgs e)
{
RaiseEvent(e);
}
protected virtual void OnPreviewModalContentHidden(RoutedEventArgs e)
{
RaiseEvent(e);
}
protected virtual void OnModalContentHidden(RoutedEventArgs e)
{
RaiseEvent(e);
}
#endregion
#region property changed callbacks
private static void OnIsModalChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ModalContentPresenter control = (ModalContentPresenter)d;
if ((bool)e.NewValue == true)
{
control.cachedKeyboardNavigationMode = KeyboardNavigation.GetTabNavigation(control.primaryContentPresenter);
KeyboardNavigation.SetTabNavigation(control.primaryContentPresenter, KeyboardNavigationMode.None);
control.overlay.Visibility = Visibility.Visible;
control.overlay.MoveFocus(traversalDirection);
control.RaiseModalContentShownEvents();
}
else
{
control.overlay.Visibility = Visibility.Hidden;
KeyboardNavigation.SetTabNavigation(control.primaryContentPresenter, control.cachedKeyboardNavigationMode);
control.primaryContentPresenter.MoveFocus(traversalDirection);
control.RaiseModalContentHiddenEvents();
}
}
private static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ModalContentPresenter control = (ModalContentPresenter)d;
if (e.OldValue != null)
control.RemoveLogicalChild(e.OldValue);
control.primaryContentPresenter.Content = e.NewValue;
control.AddLogicalChild(e.NewValue);
control.logicalChildren[0] = e.NewValue;
}
private static void OnModalContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ModalContentPresenter control = (ModalContentPresenter)d;
if (e.OldValue != null)
control.RemoveLogicalChild(e.OldValue);
control.modalContentPresenter.Content = e.NewValue;
control.AddLogicalChild(e.NewValue);
control.logicalChildren[1] = e.NewValue;
}
private static void OnOverlayBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ModalContentPresenter control = (ModalContentPresenter)d;
control.overlay.Background = (Brush)e.NewValue;
}
#endregion
#region FrameworkElement overrides
protected override Visual GetVisualChild(int index)
{
if (index < 0 || index > 1)
throw new ArgumentOutOfRangeException("index");
return layoutRoot;
}
protected override int VisualChildrenCount
{
get { return 1; }
}
protected override IEnumerator LogicalChildren
{
get { return logicalChildren.GetEnumerator(); }
}
protected override Size ArrangeOverride(Size finalSize)
{
layoutRoot.Arrange(new Rect(finalSize));
return finalSize;
}
protected override Size MeasureOverride(Size availableSize)
{
layoutRoot.Measure(availableSize);
return layoutRoot.DesiredSize;
}
#endregion
#region layout panel
class ModalContentPresenterPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
Size resultSize = new Size(0, 0);
foreach (UIElement child in Children)
{
child.Measure(availableSize);
resultSize.Width = Math.Max(resultSize.Width, child.DesiredSize.Width);
resultSize.Height = Math.Max(resultSize.Height, child.DesiredSize.Height);
}
return resultSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement child in InternalChildren)
{
child.Arrange(new Rect(finalSize));
}
return finalSize;
}
}
#endregion
}
}
You shouldn't do this (at least, this is definitely not a MVVM-way).
Use IsModal property and data binding instead:
<Controls:ModalContentPresenter x:Name="modalContent" IsModal="{Binding IsModal}">
where IsModal in the binding expression is a bound data property within your view model.
In MVVM, any data going back and forth should be done via data binding properties on your View Model. That includes virtually any properties of the ContentPresenter - just add a binding. However, if you want call a method of a XAML object in an MVVM-friendly way, you can use an Action.
Let's suppose I wanted to set the focus on a textbox via the view model (contrived example, I know there's other MVVM-ways to do this- just wanted an example that requires a child object of the view).
First, give the textbox that should get the focus a name in your XAML, i.e.,
<TextBox x:Name="textBox1"/>
On your view model, add a property for the Action:
public Action FocusAction {get;set;}
Some time before or as your view is loading, get your DataContext (i.e., your view model) and add the Action to the code behind (the view's .cs file):
ViewModel vm = (ViewModel)this.DataContext;
if ( vm.FocusAction == null )
vm.FocusAction= new Action(() => this.textBox1.Focus());
For instance, you might implement the IsLoaded event and do it there. You could also do this in your constructor after InitializeComponent, as long as it either created your view model instance or it was passed in as a paramater. The key is that the view model is already instantiated and assigned to the view's data context.
Then in your view model, wherever you wanted to add focus to that textbox, call:
FocusAction();
Since what I just showed above requires that your view cast the DataContext to a particular view model, what I do is create an interface for the kinds of actions I need, like this:
interface IFocusable
{
Action FocusAction {get;set;}
}
Then I make my view model implement that inteface. With that done, in my view's code-behind, I can say something like:
if(this.DataContext is IFocusable)
((IFocusable)this.DataContext).FocusAction = new Action(() => this.textBox1.Focus());
I think that makes it more MVVM-compliant, since it's not tightly-coupled to a particular view model, the view just knows it can add an action if the view model is the type of view model that can use it.
More details and another example available here: http://jkshay.com/closing-a-wpf-window-using-mvvm-and-minimal-
code-behind/
I know it's been few years but I just faced the same, so here's my answer in case someone will find it useful...
In your xaml file refer to your ViewModel class in the DataContext:
<Window.DataContext>
<local:YourViewModel x:Name="yourViewModel"/>
</Window.DataContext>
In your ViewModel class create a public function with your xaml file as argument and a private member to hold it:
private MainWindow mainWindow;
public void OnViewInitialized(MainWindow mainWindow)
{
this.mainWindow = mainWindow;
}
In your code behind use the function pass the the 'yourViewModel' you defined in the xaml:
public MainWindow()
{
InitializeComponent();
yourViewModel.OnViewInitialized(this);
}
And that's it :)
Now you can access all your xaml elements from your ViewModel by using your mainWindow member, just give them a name.
mainWindow.textBox1
you can create a constructor for view model which accepts the ContentPage as its parameter.
public class ViewModelClass
{
public ViewModelClass(ContentPage p=null)
{...}
}
then set the binding context in Contentpage back code script passing the referenc of contentpage to viewmodel
public class ContentPageClass : ContentPage
{
public ContentPageClass()
{
BindingContext = new ViewModelClass(p:this);
}
}
My window uses MyUserControl and passes to it a collection of items through MyItemsProperty property. MyUserControl converts the items to MyClassBag and adds the items to WrappedItems collection (OnMyItemsChanged->CollectionChanged->AddItem) which is bound to ItemsSource of DataGrid.
The problem is that ItemsSource is not updated (I set a brakepoint on control.WrappedItems.Add(new MyClassBag { ... }); and it does get there).
But, if I put a button inside MyUserControl and add items (WrappedItems.Add(new MyClassBag { ... });) through button's click method the ItemsSource does get updated. What is the problem?
public partial class MyUserControl : UserControl
{
public static readonly DependencyProperty MyItemsProperty =
DependencyProperty.Register("MyItems",
typeof(ObservableCollection<MyClass>),
typeof(MyUserControl),
new PropertyMetadata(
new ObservableCollection<MyClass>(),
new PropertyChangedCallback(OnMyItemsChanged)
)
);
public ObservableCollection<MyClass> MyItems
{
get { return (ObservableCollection<MyItems>)GetValue(MyItemsProperty); }
set { SetValue(MyItemsProperty, value); }
}
private static void OnMyItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
control = d as MyUserControl;
var items = e.NewValue as ObservableCollection<MyClass>;
states.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged);
AddItem(control, items);
}
private static void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var items = sender as ObservableCollection<MyClass>;
if (e.Action == NotifyCollectionChangedAction.Add)
{
control.AddNewItem();
}
}
public ObservableCollection<MyClassBag> WrappedItems { get; set; }
public void AddNewItem()
{
WrappedItems.Add(new MyClassBag { ... });
}
private void Button_Click(object sender, RoutedEventArgs e)
{
AddNewItem();
}
}
MyUserControl.XAML
<DataGrid ItemsSource="{Binding WrappedItems ... />
<Button Click="Button_Click" />
Window.cs
public partial class Window1 : Window
{
public ObservableCollection<MyClass> ItemsForMyUserControl { get; set; }
private void Load()
{
ItemsForMyUserControl.Add(new MyClass(...));
ItemsForMyUserControl.Add(new MyClass(...));
}
}
Window.xaml
<uc:MyUserControl MyItems="{Binding ItemsForMyUserControl}" />
I had a similiar problem some time ago.
Please make the MyClass class inherit from Freezable class and everything may work. Please let me know if it helped.