的背景 的
我在usercontrol
中定义ScrollViewer
以及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
首先滚动到视图中然后恢复到{{1的底部眨眼间。
奇怪的事情: 在调用ScrollViewer
之前显示messagebox
会正确地将BringIntoView
显示在视图的中间< / p>
当前黑客解决方案 您可以看到,即使在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
放回顶部。什么是我的问题的正确解决方案?
答案 0 :(得分:1)
在BringIntoView
渲染之前看起来像是Usercontrol
,因此当它完全呈现时,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;
}
答案 1 :(得分:0)
将背景工作者用于此类事情是不正确的!如果您只能使用LayoutUpdated事件,那么它将是最佳选择。当实际宽度或高度不等于0或使用计时器而不是bg worker时执行。
userControl.LayoutUpdated+=OnLayoutUpdated;
private bool loaded=false;
private void OnLayoutUpdated(object sender,EventArgs e)
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// Unsubscribe.
userControl.LayoutUpdated-=OnLayoutUpdated;
loaded =true;
}
}