Search code examples
wpfxamlwpfdatagriditemscontrol

How to bind ItemsControl in DataGrid behavior


I have this custom vertical scrollbar that is defined in UserControl.Resources, it has a ItemsControl in it called 'ItemsSelected'.

What I would to do is bind it to the DependencyProperty ItemsControlObject in behavior DataGridSelectionChanged. The example binding does not work but shows what I'd like to achieve. What am I missing to bind ItemsSelected?

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=ItemsSelected'. BindingExpression:(no path); DataItem=null; target element is 'DataGridSelectionChanged' (HashCode=43407976); target property is 'ItemsControlObject' (type 'ItemsControl')

<UserControl>
    <UserControl.Resources>
        <ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
            <Grid>
                ...
                <!-- BEGIN -->
                <ItemsControl Name="ItemsSelected" VerticalAlignment="Stretch"
                              ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.MarkerCollection}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Rectangle Fill="Gray" Width="18" Height="4"/>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemContainerStyle>
                        <Style TargetType="ContentPresenter">
                            <Setter Property="Canvas.Top" Value="{Binding}" />
                        </Style>
                    </ItemsControl.ItemContainerStyle>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Canvas/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
                <!-- END -->
            </Grid>
        </ControlTemplate>

        <Style TargetType="{x:Type DataGrid}" >
            <Style.Resources>
                <Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
                    <Setter Property="SnapsToDevicePixels" Value="True" />
                    <Setter Property="OverridesDefaultStyle" Value="true" />
                    <Style.Triggers>
                        <Trigger Property="Orientation" Value="Horizontal">
                            <Setter Property="Width" Value="Auto" />
                            <Setter Property="Height" Value="18" />
                            <Setter Property="Template" Value="{StaticResource HorizontalScrollBar}" />
                        </Trigger>
                        <Trigger Property="Orientation" Value="Vertical">
                            <Setter Property="Width" Value="18" />
                            <Setter Property="Height" Value="Auto" />
                            <Setter Property="Template" Value="{StaticResource VerticalScrollBar}" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Style.Resources>
        </Style>
    </UserControl.Resources>

    <Grid Name="gridUsers" Background="Transparent">
        <DockPanel>
            <DataGrid Name="GenericDataGrid">
                <i:Interaction.Behaviors>
                    <helpers:DataGridSelectionChanged ItemsControlObject="{Binding ElementName=ItemsSelected}" />
                </i:Interaction.Behaviors>
                <DataGrid.Columns>
                    ...
                </DataGrid.Columns>
            </DataGrid>
        </DockPanel>
    </Grid>
</UserControl>

[EDIT]

public static class ScrollBarMarkers
{
    public static readonly DependencyProperty MarkersSelectedCollectionProperty =
        DependencyProperty.RegisterAttached("MarkersSelectedCollection", typeof(ObservableCollection<double>), typeof(ScrollBarMarkers), new PropertyMetadata(null));

    public static ObservableCollection<double> GetMarkersSelectedCollection(DependencyObject obj)
    {
        return (ObservableCollection<double>)obj.GetValue(MarkersSelectedCollectionProperty);
    }

    public static void SetMarkersSelectedCollection(ItemsControl obj, ObservableCollection<double> value)
    {
        obj.SetValue(MarkersSelectedCollectionProperty, value);
    }
}

Solution

  • Implementing things like this stops the need for binding the actual ItemsControl

    Here is the binding:

    <ItemsControl ItemsSource="{Binding Source={x:Static helpers:MyClass.Instance}, Path=SelectedMarkers}">
    

    Here is the class with singleton pattern

    public class MyClass : INotifyPropertyChanged
    {
        public static ObservableCollection<double> m_selectedMarkers = new ObservableCollection<double>();
        public ObservableCollection<double> SelectedMarkers
        {
            get
            {
                return m_selectedMarkers;
            }
            set
            {
                m_selectedMarkers = value;
                NotifyPropertyChanged();
            }
        }
    
    
        private static MyClass m_Instance;
        public static MyClass Instance
        {
            get
            {
                if (m_Instance == null)
                {
                    m_Instance = new MyClass();
                }
    
                return m_Instance;
            }
        }
    
        private MyClass()
        {
        }
    
        #region INotifyPropertyChanged Members
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        #endregion
    }