【发布时间】: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。