如何在RadioButton选择完成更改之前延迟加载控件?

Rac*_*hel 5 wpf xaml dispatcher

我有一个ListBox风格使用RadioButtons,并更改它SelectedItem也会更改UserControl显示在它ContentControl下面.该应用程序如下所示:

应用程序的样机

<ListBox ItemsSource="{Binding AvailableViewModels}"
         SelectedItem="{Binding SelectedViewModel}"
         Style="{StaticResource RadioButtonListBoxStyle}" />

<ContentControl Content="{Binding SelectedViewModel}" />
Run Code Online (Sandbox Code Playgroud)

我的问题是UserControls每个都包含一个自定义的网格控件(Telerik RadGridView),由于它包含的数据量,它在加载时有明显的延迟.

我在Grid加载后ItemsSourceLoaded事件中设置绑定以防止UI在Grid加载时锁定,但无论我如何尝试运行它,RadioButtons仍然反映加载时的延迟,这给出了冻结的错觉UI

加载时单选按钮的屏幕截图

我尝试使用尽可能低的DispatcherPriority来设置绑定,但它似乎没有什么区别.

XAML:

<telerik:RadGridView x:Name="MyGrid" Loaded="MyGrid_Loaded" Unloaded="MyGrid_Unloaded">
     <!--....-->
</telerik:RadGridView>
Run Code Online (Sandbox Code Playgroud)

C#:

private void MyGrid_Loaded(object sender, RoutedEventArgs e)
{
    this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle,
        new Action(delegate()
    {
        BindingOperations.SetBinding(
            MyGrid,
            RadGridView.ItemsSourceProperty,
            new Binding("ViewModelProperty")
        );
    }));
}

private void MyGrid_Unloaded(object sender, RoutedEventArgs e)
{
    MyGrid.ItemsSource = null;
}
Run Code Online (Sandbox Code Playgroud)

应该注意的是,每次UserControl加载时,它都会很好地加载,RadioButton选择立即改变,并在几秒钟后加载网格.它只能切换到一个UserControl并且再次返回,导致RadioButtons在被选中时暂停.

有没有人知道在切换视图时导致UI出现冻结的原因,或者如何解决它?

编辑

我创建了一个小问题的复制品,发现它只发生在我使用RadioButtons我的ListBox物品时.使用常规ListBox不会导致选择行为的延迟相同.

XAML:

<Window.Resources>

    <!-- Need two separate DataTemplates -->
    <DataTemplate DataType="{x:Type local:Test}">
        <StackPanel>
            <TextBlock Text="Test" />
            <TextBlock Margin="10" Loaded="TextBlock_Loaded" />
            <TextBlock Text="Test" />
        </StackPanel>
    </DataTemplate>

    <DataTemplate DataType="{x:Type local:Test2}">
        <StackPanel>
            <TextBlock Text="Abc" />
            <TextBlock  Margin="10" Loaded="TextBlock_Loaded" />
            <TextBlock Text="Abc" />
        </StackPanel>
    </DataTemplate>

    <Style x:Key="RadioButtonListBoxStyle" TargetType="{x:Type ListBox}">
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemContainerStyle">
            <Setter.Value>
                <Style TargetType="{x:Type ListBoxItem}" >
                    <Setter Property="Margin" Value="2, 2, 12, 2" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate>
                                <Border Background="Transparent">
                                    <RadioButton
                                            Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"
                                            ContentTemplate="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Path=ItemTemplate}"
                                            IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Setter.Value>
        </Setter>
    </Style>

</Window.Resources>

<StackPanel>
    <ListBox x:Name="TestListBox"
             ItemsSource="{Binding Test}"
             Style="{StaticResource RadioButtonListBoxStyle}">

        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="Option" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <ContentControl Content="{Binding ElementName=TestListBox, Path=SelectedItem}" />
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

C#:

private void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
    this.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle,
        new Action(delegate()
        {
            System.Threading.Thread.Sleep(1000);
            ((TextBlock)sender).Text = "Delay Loaded Test";
        }));
}
Run Code Online (Sandbox Code Playgroud)

Test只是一个ObservableCollection<ITest>,包含TestTest2对象.仅在两个不同对象之间切换时才会发生延迟,因为DataTemplate绘制了一个新对象而不是重新使用现有对象DataTemplate.

Col*_*inE 4

使用调度程序和一些低优先级的问题是,无法真正保证代码何时执行。您希望确保在 UI 更新后执行运行缓慢的代码。A 可以想出一个非常巧妙的方法来做到这一点......

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = Timespan.FromMilliseconds(100);
timer.Tick += (s, e2) =>
{
  // update your binding
  BindingOperations.SetBinding(
        MyGrid,
        RadGridView.ItemsSourceProperty,
        new Binding("ViewModelProperty")
    );

  timer.Stop();
};
timer.Start();
Run Code Online (Sandbox Code Playgroud)

上面创建了一个在 100 毫秒后执行的“滴答”计时器。