I have a ScrollViewer filled with green rectangles and I need to report its scroll value (or percentage) on a TextBlock everytime it changes. I also need to be able to change the scroll value by changing the property it is bind to.
I have created an Attached property ScrollViewerBehavior
which gives me the value I need, and I bind it to a property of my viewmodel (ScrollValue
) however the value is not updated as the setter is never reached. The viewmodel is correctly linked with the view.
Here is my code:
View
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="6*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" Background="Gray" local:ScrollViewerBehavior.ScrollState="{Binding ScrollValue, Mode=TwoWay}" >
<StackPanel>
<Rectangle Width="50" Height="50" Fill="Green" Margin="5" />
<Rectangle Width="50" Height="50" Fill="Green" Margin="5" />
<Rectangle Width="50" Height="50" Fill="Green" Margin="5" />
<Rectangle Width="50" Height="50" Fill="Green" Margin="5" />
<Rectangle Width="50" Height="50" Fill="Green" Margin="5" />
</StackPanel>
</ScrollViewer>
<TextBlock Grid.Row="1" Text="{Binding ScrollValue}" />
</Grid>
ViewModel
public class MainViewModel : BaseViewModel
{
private double _scrollValue = 0;
public double ScrollValue
{
get { return _scrollValue; }
set
{
// This code is never reached
_scrollValue = value;
OnPropertyChanged("ScrollValue");
}
}
}
ScrollViewerBehavior
public static double GetScrollState(DependencyObject obj)
{
return (double)obj.GetValue(ScrollStateProperty);
}
public static void SetScrollState(DependencyObject obj, double value)
{
obj.SetValue(ScrollStateProperty, value);
}
public static readonly DependencyProperty ScrollStateProperty =
DependencyProperty.RegisterAttached("ScrollState", typeof(double), typeof(ScrollViewerBehavior), new PropertyMetadata(0.5, (o, e) =>
{
var scrollViewer = o as ScrollViewer;
if (scrollViewer == null)
{
return;
}
else
{
double newVO = (double)e.NewValue * scrollViewer.ScrollableHeight;
scrollViewer.ScrollToVerticalOffset(newVO);
SetScrollState(o, newVO);
}
}));
I can't see what I missed
CodePudding user response:
I do not see anywhere in the code where you are changing the value of ScrollValue
. Since your attached property is bound to this, it only updates when ScrollValue
in your view model is updated. Unless I am misunderstanding your explanation, you want to update ScrollValue
everytime the scroll bar value changes. To do that you can hook into the ScrollChanged
event:
(I only updated your code just show what was needed)
public static readonly DependencyProperty ScrollStateProperty =
DependencyProperty.RegisterAttached("ScrollState", typeof(double), typeof(ScrollViewerBehavior), new PropertyMetadata(0.5, (o, e) =>
{
if (o is ScrollViewer scrollViewer)
{
scrollViewer.ScrollChanged = OnScrollChanged;
}
}));
private static void OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (sender is ScrollViewer scrollViewer)
{
SetScrollState(scrollViewer, scrollViewer.VerticalOffset);
}
}