2017-08-09 29 views
0

我在ListBox上的UWP中使用DataTemplateSelector,我想强制重新选择现有ListBoxItem的DataTemplate。我可以使它工作的唯一方法是从绑定集合中删除项目,然后重新添加项目。这看起来像一个疯子。我只想简化列表框项目的布局,并让它再次调用数据模板选择器。似乎无法做到这一点。如何强制重新选择DataTemplateSelector

这里是网页...

<Page.Resources> 
    <local:MyTemplateSelector x:Key="TemplateSelector"/> 
</Page.Resources> 
<Page.DataContext> 
    <local:MyViewModel/> 
</Page.DataContext> 

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 
    <StackPanel> 
     <ListBox x:Name="listBox1" Margin="5" ItemsSource="{Binding QuantityRows}" 
      ItemTemplateSelector="{StaticResource TemplateSelector}"> 
      <ListBox.Resources> 
       <DataTemplate x:Key="Detail"> 
        <StackPanel Orientation="Horizontal"> 
         <Button Click="OnShowSummary">Show Summary</Button> 
         <TextBlock Text="Name "/> 
         <TextBox Width="40" Text="{Binding Name}"/> 
        </StackPanel> 
       </DataTemplate> 
       <DataTemplate x:Key="Summary"> 
        <StackPanel Orientation="Horizontal"> 
         <Button Click="OnShowDetail">Show Detail</Button> 
         <TextBlock Text="{Binding Summary}"/> 
        </StackPanel> 
       </DataTemplate> 
      </ListBox.Resources> 
     </ListBox> 
    </StackPanel> 

</Grid> 

这里是模板选择...

public class MyTemplateSelector : DataTemplateSelector 
{ 
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) 
    { 
     QuantityRow row = item as QuantityRow; 
     ListBox lb = UWPUtilities.GetParent<ListBox>(container); 
     if (row != null && lb != null) 
     { 
      if (row.IsDetail) 
      { 
       return lb.Resources["Detail"] as DataTemplate; 
      } 
      else 
      { 
       return lb.Resources["Summary"] as DataTemplate; 
      } 
     } 
     return base.SelectTemplateCore(item, container); 
    } 
} 

这里是视图模型...

public class QuantityRow 
{ 
    public bool IsDetail { get; set; } 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public string Summary 
    { 
     get 
     { 
      return "Name = " + Name; 
     } 
    } 
} 
public class MyViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    public ObservableCollection<QuantityRow> QuantityRows { get; set; } 
    public MyViewModel() 
    { 
     QuantityRows = new ObservableCollection<QuantityRow>(); 
     QuantityRows.Add(new QuantityRow() { IsDetail = false, ID = 1, Name = "Length" }); 
     QuantityRows.Add(new QuantityRow() { IsDetail = true, ID = 2, Name = "Diameter" }); 
     QuantityRows.Add(new QuantityRow() { IsDetail = false, ID = 3, Name = "Temperature" }); 
     QuantityRows.Add(new QuantityRow() { IsDetail = false, ID = 4, Name = "Pressure" }); 
     QuantityRows.Add(new QuantityRow() { IsDetail = true, ID = 5, Name = "Angle" }); 
    } 
} 

这里是后面的代码...

public MyViewModel ViewModel 
    { 
     get 
     { 
      return DataContext as MyViewModel; 
     } 
    } 

    private void OnShowSummary(object sender, RoutedEventArgs e) 
    { 
     QuantityRow row = (sender as Button).DataContext as QuantityRow; 
     row.IsDetail = false; 
    //   UpdateLayout1(row); 
     UpdateLayout2(sender); 
    } 
    private void OnShowDetail(object sender, RoutedEventArgs e) 
    { 
     QuantityRow row = (sender as Button).DataContext as QuantityRow; 
     row.IsDetail = true; 
    //   UpdateLayout1(row); 
     UpdateLayout2(sender); 
    } 
    private void UpdateLayout1(QuantityRow row) 
    { 
     int index = ViewModel.QuantityRows.IndexOf(row); 
     ViewModel.QuantityRows.RemoveAt(index); 
     ViewModel.QuantityRows.Insert(index, row); 
    } 
    private void UpdateLayout2(object sender) 
    { 
     ListBoxItem lbi = UWPUtilities.GetParent<ListBoxItem>(sender as DependencyObject); 
     lbi.InvalidateArrange(); 
    } 

最后这里是一个效用函数...

public static class UWPUtilities 
{ 
    public static T GetParent<T>(DependencyObject d) where T : class 
    { 
     while (d != null && !(d is T)) 
     { 
      d = VisualTreeHelper.GetParent(d); 
     } 
     return d as T; 
    } 
} 

有上总结和详细信息模板之间切换各列表项的按钮。 UpdateLayout1可以正常工作,但代价是绑定列表中有一些流失。 UpdateLayout2不起作用。在我看来,这将是一个更清晰的实现。为什么ListBoxItem上的InvalidateArrange()不强制重新选择模板?

+1

看一看我的答案[这里](https://stackoverflow.com/questions/44249232/uwp-datatemplateselector-and-selecteditem/44251390#44251390),这应该给你一些想法。请注意,您需要在模型上实现INPC,以便在选择器类中使用PropertyChanged事件。 –

+0

这绝对有用,但哇是丑陋的。因此,您将模板选择器设置为null,然后将其设置回。 Pffffffffffft。 – AQuirky

回答

0

非常感谢@Justin XL的这个想法。为了让模板选择器再次触发,必须将其设置为null,然后将其设置回相同的引用。这确实是另一种方式,但我喜欢它比我的第一个更好。没有优雅在这里找到。

private void UpdateLayout2(object sender) 
    { 
     ListBoxItem lbi = UWPUtilities.GetParent<ListBoxItem>(sender as DependencyObject); 
     DataTemplateSelector dts = lbi.ContentTemplateSelector; 
     lbi.ContentTemplateSelector = null; 
     lbi.ContentTemplateSelector = dts; 
    }