.NET Framework Developer Center > .NET Framework Forums > Windows Presentation Foundation (WPF) > TabPanel with a ScrollViewer on each TabItem - Problem

Unanswered TabPanel with a ScrollViewer on each TabItem - Problem

  • Wednesday, August 05, 2009 6:07 PM
     
     
    Hi,

    I'm having a strange problem with my WPF-application. I create a tabpanel that holds multiple tabitems and in each tabitem I put a scrollviewer. Now this works fine for the scrolling, but when I scroll in one tab all the other tabs scroll to. (When I switch to another tab, the scollbars there have the same position) ... but I would like to scroll each panel seperatly ... .

    Maybe it's important to say that the tabitems are generated by using an item- and datatemplate, I also use binding (MVVM-pattern)...

    Greetz kevin

    EDIT:

    It seems that it only occurs when I make use of Bindings. It can't be that I should remove each eventhandler from a tab when it is not selected ? Can it ? I think it has something to do with the MVVM, maybe an indication that it should react on events or not ? ...

    EDIT2:

    Is is definitely a binding issue. I tried it with comboboxes and had the same problems ... . However after I bound the selecteditem to my viewmodel the problem disappeared. Strange that WPF doesn't keep the state of each instance its holds ... . But now I still have the problem with my scrollviewer ... since it isn't possible to bind the offset of the scrollbars to my viewmodel ... or is there a way to bind the scrollviewer itself to my viewmodel ?

    • Edited by kevin verfaille Thursday, August 06, 2009 9:01 AM Problem update
    •  

All Replies

  • Friday, August 07, 2009 10:34 AM
     
      Has Code
    Hello,

    So it isn't possible to achieve what I wan't so I need to bind the offset of an scrollviewer to my viewmodel. Now the problem is that my scrollviewer hasn"t got a setter for it's offset, so I'm trying to get it done with Bindind to custom dependencypropertys.

    No I'm able to bind from my viewmodel to my offset, but the binding doesn"t happen from my viewer to my viewmodel. It seems that my PropertyChanged event never has any subscribers ... althought I bind to it when the Datacontext of my panel changed ...

    Any ideas ?

    Here my class (only Horizontal scrolling should be finished ... vertical I'll do when horzintal works :)).

        /// <summary>
        /// Interaction logic for TimeLinePanel.xaml
        /// </summary>
        public partial class ProjectPanel : UserControl, INotifyPropertyChanged
        {
            public static DependencyProperty VerticalScrollbarOffsetDP =
                        DependencyProperty.Register("VerticalScrollViewerOffset", typeof(double), typeof(ProjectPanel),new PropertyMetadata(OnVerticalScrollViewerPropertyChanged));
            public static DependencyProperty HorizontalScrollbarOffsetDP =
                        DependencyProperty.Register("HorizontalScrollViewerOffset", typeof(double), typeof(ProjectPanel), new PropertyMetadata(OnHorizontalScrollViewerPropertyChanged));
    
            private static void OnVerticalScrollViewerPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                if (obj is ProjectPanel == true)
                {
                    ((ProjectPanel)obj).VerticalScrollbarOffset = (double)e.NewValue;
                }
            }
    
            private static void OnHorizontalScrollViewerPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                if (obj is ProjectPanel == true)
                {
                    ((ProjectPanel)obj).HorizontalScrollbarOffset = (double)e.NewValue;
                }
            }
    
            public ProjectPanel()
            {
                InitializeComponent();
                this.DataContextChanged +=new DependencyPropertyChangedEventHandler(ProjectPanel_DataContextChanged);
            }
    
            void ProjectPanel_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
            {
                ProjectPanelViewModel panel = (ProjectPanelViewModel)this.DataContext;
                Binding b = new Binding();
                b.Source = panel;
                b.UpdateSourceTrigger = UpdateSourceTrigger.Default;
                b.Path = new PropertyPath("HorizontalScrollViewerOffset");
                b.Mode = BindingMode.TwoWay;
                this.SetBinding(HorizontalScrollbarOffsetDP,b);
            }
    
            public double VerticalScrollbarOffset
            {
                get 
                {
                    return scrollViewer.VerticalOffset;
                }
                set
                {
                    scrollViewer.ScrollToVerticalOffset(value);                
                    OnPropertyChanged("VerticalScrollViewerOffset");
                }
            }
            public double HorizontalScrollbarOffset
            {
                get
                {
                    return (double)GetValue(HorizontalScrollbarOffsetDP);
                }
                set
                {
                    scrollViewer.ScrollToHorizontalOffset(value);
                    //SetValue(HorizontalScrollbarDP, value);
                    OnPropertyChanged("HorizontalScrollViewerOffset");
                }
            }
    
            #region INotifyPropertyChanged Members
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void OnPropertyChanged(string name)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
                }
            }
    
            #endregion
    
            private void scrollViewer_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
            {
                OnPropertyChanged("VerticalScrollViewerOffset");
                OnPropertyChanged("HorizontalScrollViewerOffset");
            }
        }
    greetz kevin
  • Wednesday, March 31, 2010 6:18 PM
     
     

    The problem might occur because WPF reuses control (user control) instances when they are registered as data template.

    One solution is not to use data templates here. Create an own View (control) instance for every TabItem. This way the scrolling of the views doesn’t affect other views.

    The Writer sample application of the WPF Application Framework (WAF) shows how this can be done.