我有一个程序,其中listview模板必须根据用户的喜好进行更改。
很抱歉,如果有更多的代码段超出了必要范围,但我希望代码尽可能完整。
我试图将代码减少到最少,以便代码尽可能清晰易读。
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));
}
}
MainWindow:
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);
}
答案 0 :(得分: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);
}