#c# #wpf #user-interface #mvvm
Вопрос:
У меня есть ScrollViewer, заполненный зелеными прямоугольниками, и мне нужно сообщать о его значении прокрутки (или процентах) в текстовом блоке при каждом его изменении. Мне также нужно иметь возможность изменять значение прокрутки, изменяя свойство, к которому она привязана.
Я создал вложенное свойство ScrollViewerBehavior
, которое дает мне нужное значение, и я привязываю его к свойству моей viewmodel ( ScrollValue
), однако значение не обновляется, так как сеттер никогда не достигается. Модель представления правильно связана с представлением.
Вот мой код:
Вид
<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>
Модель представления
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);
}
}));
Я не вижу, что я пропустил
Комментарии:
1. не вдаваясь в подробности: у вас где-то установлен текст данных?
2. Да, он задается непосредственно в конструкторе представления
3. Как примечание,
if (scrollViewer == null) { return; } else { ... }
выглядит странно. Так и должно бытьif (scrollViewer != null) { ... }
. Кроме того, нет смысла вызывать SetScrollState в обработчике PropertyChanged свойства ScrollState. Вы должны устанавливать это свойство при прокрутке средства просмотра прокрутки.
Ответ №1:
Я нигде не вижу в коде, где вы меняете значение ScrollValue
. Поскольку ваше прикрепленное свойство связано с этим, оно обновляется только тогда, когда ScrollValue
в вашей модели представления обновляется. Если я не неправильно понимаю ваше объяснение, вы хотите обновлять ScrollValue
его каждый раз, когда изменяется значение полосы прокрутки. Для этого вы можете подключиться к ScrollChanged
событию:
(Я только обновил ваш код, просто покажите, что было нужно)
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);
}
}