4

I have UserControl, lets call it as CustomDataGrid, that contains DataGrid. Remained content doesn't matter. SelectedItem property of DataGrid must be SelectedItem property of CustomDataGrid. And I wanna be able to use Binding with this property, cause I use MVVM pattern. So I have to declare SelectedItem as DependencyProperty in CustomDataGrid. But I have no ideas haw can I make it properly...

This is how DepedencyProperty-s is declared usually:

public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
        "SelectedItem", typeof(Object), typeof(CustomDataGrid),
        new FrameworkPropertyMetadata(default(Object), SelectedItemPropertyCallback)
        {
            BindsTwoWayByDefault = true, 
            DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
        });

// Optionally
private static void SelectedItemPropertyCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    // dataGrid - `DataGrid` nested in `UserControl` 
    ((CustomDataGrid)obj).dataGrid.SelectedItem = e.NewValue;
}

// Obviously, it has no any link with nested `dataGrid`. This is the problem.  
public Object SelectedItem
{

    get { return GetValue(SelectedItemProperty); }
    set { SetValue(SelectedItemProperty, value); }
}

So, how can I declare SelectedItem property correctly?

pushpraj
  • 13,458
  • 3
  • 33
  • 50
monstr
  • 1,680
  • 1
  • 25
  • 44

2 Answers2

2

You could leverage the binding framework for wiring such properties from underlying objects to outer containers

example assuming CustomDataGrid as UserControl

        class CustomDataGrid : UserControl
        {
            public CustomDataGrid()
            {
                Binding b = new Binding("SelectedItem");
                b.Source = this;
                b.Mode = BindingMode.TwoWay;
                dataGrid.SetBinding(DataGrid.SelectedItemProperty, b);
            }

            public object SelectedItem
            {
                get { return (object)GetValue(SelectedItemProperty); }
                set { SetValue(SelectedItemProperty, value); }
            }

            // Using a DependencyProperty as the backing store for SelectedItem.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty SelectedItemProperty =
                DependencyProperty.Register("SelectedItem", typeof(object), typeof(CustomDataGrid), new PropertyMetadata(null));
        }

I have created a property called SelectedItem in CustomDataGrid and set a two way binding to SelectedItem of the actual dataGrid inside.

so this will wire up these properties and will propagate any changes to and fro.

pushpraj
  • 13,458
  • 3
  • 33
  • 50
  • Not acceptable for me to hardcode `Binding` in constructor. I found this [link]http://stackoverflow.com/questions/23381560/wpf-usercontrol-selecteditem-of-a-usercontrol-datagrid-to-bind-to-a-itemsource. It works, but not enough. What if I want to set `SelectedItem` from outer code? How value will pass to `dataGrid`? – monstr Jul 02 '14 at 05:45
  • if you set SelectedItem from the outer code, binding will push the value to datagrid's SelectedItem. just give it a try. secondly writing any such code is a kind of hardcoding, no matter you do in constructor, in property setter, property changed events or any other event handlers. otherwise you can combine your solution with the one in the link and make a complete wiring of properties. – pushpraj Jul 02 '14 at 05:52
  • You right, nice solution, it works even better then in link I posted – monstr Jul 02 '14 at 05:55
2

XAML solution!

Use this DependencyProperty:

public object SelectedItem
{
    get { return GetValue(SelectedItemProperty); }
    set { SetValue(SelectedItemProperty, value); }
}  

public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(CustomDataGrid ), new FrameworkPropertyMetadata(null)
{
    BindsTwoWayByDefault = true,
    DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});

Then make your outer CustomDataGrid UserControl XAML look like this:

<UserControl x:Class="CustomDataGrid">
    <DataGrid ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type CustomDataGrid}}}"
              SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type CustomDataGrid}}}">

    </DataGrid>
</UserControl>

You can then use the CustomDataGrid control the same way as the DataGrid control when binding ItemsSource and SelectedItem to your view model.

bugged87
  • 3,026
  • 2
  • 26
  • 42