dva
dva

Reputation: 352

WPF: How do I bind to property located down the visual tree of an adjacent control?

I have a WPF Window and UserControl which I use inside the Window

Window:

<Window x:Class="AdjacentControlVisualTree.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:AdjacentControlVisualTree"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <StackPanel Orientation="Vertical">
        <local:AdjacentControl x:Name="AdjacentControl"/>
        <Button Content="Foo"
            CommandParameter="{Binding SelectedItem, ElementName=AdjacentControl.BarDataGrid}"
            Command="{Binding FooCommand}"/>
    </StackPanel>
</Window>

UserControl:

<UserControl x:Class="AdjacentControlVisualTree.AdjacentControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:AdjacentControlVisualTree">

    <UserControl.DataContext>
        <local:AdjacentViewModel/>
    </UserControl.DataContext>

    <Grid>
        <DataGrid x:Name="BarDataGrid"
            ItemsSource="{Binding Collection}"
            IsReadOnly="True"
            AutoGenerateColumns="False"
            SelectionUnit="FullRow"
            SelectionMode="Single">
            <DataGrid.Columns>
                <DataGridTextColumn Header="String" Binding="{Binding}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</UserControl>

Now, the thing is, that I would like to pass SelectedItem property of DataGrid inside the AdjacentControl to the FooCommand command but the binding always passes null:

CommandParameter="{Binding SelectedItem, ElementName=AdjacentControl.BarDataGrid}"

Is there a way how to make the binding work without having to change the structure of the controls?

Upvotes: 0

Views: 612

Answers (1)

Clemens
Clemens

Reputation: 128060

The probably most simply way would be to expose BarDataGrid as a property.

Change the XAML name (e.g. to x:Name="barDataGrid") and add this property to the UserControl's code behind:

public DataGrid BarDataGrid { get { return barDataGrid; } }

Then bind to the DataGrid's SelectedItem property like this:

CommandParameter="{Binding BarDataGrid.SelectedItem, ElementName=AdjacentControl}"

A cleaner solution would be not to expose the DataGrid child, but only its SelectedItem, by means of a dedicated dependency property.

public static readonly DependencyProperty SelectedItemProperty =
    System.Windows.Controls.Primitives.Selector.SelectedItemProperty.AddOwner(
        typeof(AdjacentControl));

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

You would bind the DataGrid's SelectedItem to this property by a RelativeSource Binding

<DataGrid SelectedItem="{Binding SelectedItem,
                         RelativeSource={RelativeSource AncestorType=UserControl}}"

and bind the CommandParameter like this:

CommandParameter="{Binding SelectedItem, ElementName=AdjacentControl}"

Upvotes: 2

Related Questions