Search code examples
c#wpfxamlitemscontrolattached-properties

How to create attached property for ItemsControl


I have the following ItemsControl, as shown it has hard-coded values, I would like to shift these values into an attached property, probably an ObservableCollection or something similar.

How to create this attached property and how to bind it.

<ItemsControl Grid.Column="0" VerticalAlignment="Stretch" Name="ItemsSelected">
    <sys:Double>30</sys:Double>
    <sys:Double>70</sys:Double>
    <sys:Double>120</sys:Double>
    <sys:Double>170</sys:Double>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Rectangle Fill="SlateGray" 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>

[EDIT] So I think I have the attached property figured:

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);
    }
}

What I'm wondering now is the best way to get the ItemsControl object before calling the following in the selection changed behavior:

ScrollBarMarkers.SetMarkersSelectedCollection(ItemsControl, initSelected);

The style of the customized vertical scrollbar is setup in the Window.Resources

The behavior is set up on the DataGrid like so:

<DataGrid Name="GenericDataGrid">
    <i:Interaction.Behaviors>
        <helpers:DataGridSelectionChanged />
    </i:Interaction.Behaviors>
</DataGrid>

My selection changed behavior:

public class DataGridSelectionChanged : Behavior<DataGrid>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.SelectionChanged += DataGrid_SelectionChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.SelectionChanged -= DataGrid_SelectionChanged;
    }

    void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ObservableCollection<double> initSelected = new ObservableCollection<double>();
        initSelected.Add(30);
        initSelected.Add(60);
        initSelected.Add(100);
        //Just trying to figure out how best to get the ItemsControl object.
        ScrollBarMarkers.SetMarkersSelectedCollection(itemsControlObj, initSelected);
    }
}

Below is an example of the markers in the scrollbar, a ItemsControl has been added to the custom vertical scrollbar as per the code right at the top of the question. enter image description here


Solution

  • Went down the wrong track with this instead of creating a DependencyProperty I should have just created a plain property, however because it is UI related I did not want it with my ViewModel. So I created a class with singleton pattern in the same namespace as my behavior and other attached properties. This also means I can set the collection from any behaviors.

    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
    }