【问题标题】:C# WPF - ScrollContentPresenter not found inside ListView after template changeC# WPF - 模板更改后在 ListView 中找不到 ScrollContentPresenter
【发布时间】:2018-09-05 19:43:31
【问题描述】:

我有一个程序,其中列表视图模板必须根据用户偏好进行更改。

如果代码片段过多,我深表歉意,但我希望尽可能完整。

我已尝试将代码减少到最少,使其尽可能清晰且易于阅读。

XAML:

<Style TargetType="{x:Type ListView}">
        <Style.Triggers>

            <!-- Details View -->
            <DataTrigger Binding="{Binding View}" Value="0">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListView}" >
                            <Border Margin="5" Name="Border" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true" >
                                <ScrollViewer x:Name="scroll" Padding="{TemplateBinding Padding}" Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}">
                                    <VirtualizingStackPanel IsItemsHost="True" x:Name="ItemsHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                </ScrollViewer>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Setter Property="View">
                    <Setter.Value>
                        <GridView>
                            <GridViewColumn Header="Name">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal">
                                            <Image Height="20" Width="20" Stretch="Uniform" Source="{Binding Image}" />
                                            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                                                <TextBlock Margin="2,0,6,0" Text="{Binding First}" />
                                                <TextBlock Text="{Binding Last}" />
                                            </StackPanel>
                                        </StackPanel>
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                        </GridView>
                    </Setter.Value>
                </Setter>
            </DataTrigger>

            <!-- Tiles View -->
            <DataTrigger Binding="{Binding View}" Value="1">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListView}">
                            <Border Name="Border" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                                <ScrollViewer x:Name="scroll" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Padding="{TemplateBinding Padding}">
                                    <WrapPanel IsItemsHost="True" x:Name="ItemsHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                </ScrollViewer>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Setter Property="ItemTemplate" >
                    <Setter.Value>
                        <DataTemplate DataType="{x:Type src:ItemModel}">
                            <Grid Width="100">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="80" />
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Image Grid.Row="0" Stretch="Uniform" Source="{Binding Image}" />
                                <TextBox HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Row="1" Text="{Binding First}" TextWrapping="Wrap" Height="Auto" MaxLines="10"/>
                            </Grid>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>

ListViewModel:

public class ListViewModel : INotifyPropertyChanged
{
    private int _view = 0;
    public int View
    {
        get { return _view; }
        set
        {
            _view = value;
            RaisePropertyChanged("View");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

主窗口:

private ListView listView;
private ListViewModel listViewModel;

public MainWindow()
{
    InitializeComponent();

    listView = mylistview; //defined in xaml
    listViewModel = new ListViewModel();
    this.DataContext = listViewModel;
}

public void ChangeView(int view)
{
    listViewModel.View = view;
    ScrollContentPresenter scrollContent = FindChild<ScrollContentPresenter>(this.listView);
    //Error : ScrollContentPresenter not found.
    //It needs a further search a few seconds later, to be found.
}

private static T FindChild<T>(DependencyObject reference) where T : class
{
     var queue = new Queue<DependencyObject>();
     queue.Enqueue(reference);
     while (queue.Count > 0)
     {
         DependencyObject child = queue.Dequeue();
         T obj = child as T;
         if (obj != null)
         {
             return obj;
         }

         for (int i = 0; i < VisualTreeHelper.GetChildrenCount(child); i++)
         {
             queue.Enqueue(VisualTreeHelper.GetChild(child, i));
         }
     }

     return null;
}

一切都很好,当我需要更改列表视图模板时出现问题[示例:ChangeView(0); ].

更改模板后,ScrollContentPresenter 找不到了。 找到它的唯一方法是等待几秒钟后再试。

谁能给我解释一下为什么,如果有办法解决这个问题?


我尝试使用自定义 ListView 控件在 OnApplyTemplate() 事件中调用 ScrollContentPresenter 搜索,但问题仍然存在。

示例:

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    ScrollContentPresenter scrollContent = FindChild<ScrollContentPresenter>(this.listView);
}

【问题讨论】:

  • 请问,您为什么要从ListView 中找到ScrollContentPresenter?你在做一些操作吗?
  • 我已经构建了一个系统,允许您通过用鼠标绘制选择区域来选择列表视图项(就像在 Windows 资源管理器中一样),并且每次更改模板时我都需要使用 ScrollContentPresenter。

标签: c# wpf listview templates


【解决方案1】:

在调用FindChild 方法之前,您需要等到新视图实际加载或强制更新布局:

public void ChangeView(int view)
{
    listViewModel.View = view;
    listView.Measure(new Size(listView.ActualWidth, listView.ActualHeight));
    listView.Arrange(new Rect(0, 0, listView.ActualWidth, listView.ActualHeight));
    ScrollContentPresenter scrollContent = FindChild<ScrollContentPresenter>(this.listView);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-26
    • 1970-01-01
    • 2019-09-24
    • 2021-09-05
    • 2023-01-15
    • 1970-01-01
    • 2011-03-14
    • 2015-10-01
    相关资源
    最近更新 更多