背景:I有一个在ScrollViewer
中定义的usercontrol
和一个ContentControl
,ContentControl
将始终可见,其中有一个Button
,当单击按钮时将usercontrol
设置为Visible
,当usercontrol
显示(Visiblility="Visible"
)时,我希望将其滚动到视图中。我有过
XAML
<ScrollViewer VerticalScrollBarVisibility="Auto" MaxHeight="465">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding MyOtherViewModel}" Width="960" ></ContentControl>
<local:MyView IsVisibleChanged="MyView_IsVisibleChanged" Grid.Row="1" Visibility="{Binding IsNonCompliant, Converter={StaticResource BooltoVisible}, UpdateSourceTrigger=PropertyChanged}" />
</ScrollViewer>
代码背后
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
(sender as Control).BringIntoView();
}
问题:--它不起作用,或者更准确地说,我的usercontrol
先滚动到视图中,然后在眨眼之间恢复到ScrollViewer
的底部。
奇怪的事情:在调用BringIntoView
之前显示了一个messagebox
,它将正确地将my usercontrol
显示在视图的中间
当前黑客解决方案:--您可以看到它甚至可以在Window
的loaded
之后立即关闭
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Window ss = new Window();
ss.Loaded += new RoutedEventHandler(ss_Loaded);
ss.ShowDialog();
(sender as Control).BringIntoView();
}
private void ss_Loaded(object sender, RoutedEventArgs e)
{
(sender as Window).Close();
}
问题:--我知道肯定有别的事情发生了,但我只是无法辨认,但是我真的想知道当一个窗口显示在ShowDialog
上时发生了什么?这是因为它刷新window
以便BringIntoView
只在加载usercontrol
之后才会发生吗?(与我现在遇到的问题不同:BringIntoView
首先发生,然后window
被刷新,并将scrollbar
重新放到顶部)。对我的问题有什么正确的解决办法?
发布于 2013-09-13 15:02:21
它看起来像是在我的BringIntoView
被呈现之前调用的,因此当它被完全呈现时,scrollbar
会恢复到顶部(正如我在我的问题中所描述的)。感谢@Evgeny发布的另一个问题的答案,我现在得到了一个更好的解决方案(也许更少的黑客攻击?)还想看看是否有更好的解决方案。
private void MyView_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var border = (FrameworkElement)sender;
if (border.IsVisible)
{
//Window ss = new Window();
//ss.Loaded += new RoutedEventHandler(ss_Loaded);
//ss.ShowDialog();
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
Tuple<FrameworkElement, double> b = new Tuple<FrameworkElement, double>(border, border.Height);
bg.RunWorkerAsync(b);
}
}
}
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
(e.Result as UserControl).BringIntoView();
}
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
int maxwait = 300 //not scrolled to the view is not a disaster, but if the program hangs forever it will be a disaster, so set this to prevent that from happening
while (maxwait!=0
&&
(e.Argument as Tuple<FrameworkElement, double>).Item1.ActualHeight != (e.Argument as Tuple<FrameworkElement, double>).Item2)
{
Thread.Sleep(1);
maxwait --;
}
e.Result = (e.Argument as Tuple<FrameworkElement, double>).Item1;
}
发布于 2014-11-24 10:52:38
我不敢相信使用背景工作者是一个正确的解决方案!您可以使用LayoutUpdated事件轻松查找何时加载并最终显示控件。
userControl.LayoutUpdated+=OnLayoutUpdated;
private bool loaded=false;
private void OnLayoutUpdated(object sender,EventArgs e)
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// Unsubscribe or set a flag.
userControl.LayoutUpdated -= OnLayoutUpdated;
loaded = true;
}
}
因此,您可以在更新布局和设置高度或宽度时执行该代码。这意味着将加载并显示控件。无法取消订阅或设置初始化已完成的标志。
https://stackoverflow.com/questions/18724686
复制相似问题