注意:本答案基于WPF,对于UWP可能需要进行一些更改。
基本上有两种情况需要考虑:
1. 您有一个数据驱动的方面需要绑定到项目容器。
2. 您有一个仅用于视图的属性。
让我们假设针对这两种情况都进行了自定义的列表视图:
public class MyListView : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
return new DesignerItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is DesignerItem;
}
}
public class DesignerItem : ListViewItem
{
public bool IsEditing
{
get { return (bool)GetValue(IsEditingProperty); }
set { SetValue(IsEditingProperty, value); }
}
public static readonly DependencyProperty IsEditingProperty =
DependencyProperty.Register("IsEditing", typeof(bool), typeof(DesignerItem));
}
在情况1中,您可以使用
ItemContainerStyle
将您的视图模型属性与绑定链接,然后在数据模板内绑定相同的属性。
class MyData
{
public bool IsEditing { get; set; }
}
XAML:
<local:MyListView ItemsSource="}">
<local:MyListView.ItemContainerStyle>
<Style TargetType="">
<Setter Property="IsEditing" Value=""/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</local:MyListView.ItemContainerStyle>
<local:MyListView.ItemTemplate>
<DataTemplate>
<Border Background="Red" Margin="5" Padding="5">
<CheckBox IsChecked=""/>
</Border>
</DataTemplate>
</local:MyListView.ItemTemplate>
</local:MyListView>
在情况2中,似乎您并没有真正的数据驱动属性,因此,您属性的效果应该反映在控件(
ControlTemplate
)中。
以下示例中,基于
IsEditing
属性使工具栏可见。可以使用切换按钮来控制该属性,
ItemTemplate
作为工具栏和按钮旁的内部元素使用,它不知道
IsEditing
状态:
<local:MyListView ItemsSource="}">
<local:MyListView.ItemContainerStyle>
<Style TargetType="">
<Setter Property="IsEditing" Value=""/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="">
<DockPanel>
<ToggleButton DockPanel.Dock="Right" Margin="5" VerticalAlignment="Top" IsChecked=",Mode=TwoWay}" Content="Edit"/>
<!--Toolbar is something control related, rather than data related-->
<ToolBar x:Name="MyToolBar" DockPanel.Dock="Top" Visibility="Collapsed">
<Button Content="Tool"/>
</ToolBar>
<ContentPresenter ContentSource="Content"/>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsEditing" Value="True">
<Setter TargetName="MyToolBar" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</local:MyListView.ItemContainerStyle>
<local:MyListView.ItemTemplate>
<DataTemplate>
<Border Background="Red" Margin="5" Padding="5">
<TextBlock Text="Hello World"/>
</Border>
</DataTemplate>
</local:MyListView.ItemTemplate>
</local:MyListView>
为了更好地控制模板,您可以选择使用 Blend 并从完整的
ListViewItem
模板开始创建控件模板,然后将您的更改编辑到其中。
如果您的 DesignerItem 通常具有特定的增强外观,请考虑在
Themes/Generic.xaml
中设计它,并使用适当的默认样式。
如评论所述,您可以为编辑模式提供单独的数据模板。要做到这一点,请向
MyListView
和
DesignerItem
添加属性,并使用
MyListView.PrepareContainerForItemOverride(...)
转移模板。
为了在不需要
Setter.Value
绑定的情况下应用模板,您可以基于
IsEditing
对
DesignerItem.ContentTemplate
进行值强制。
public class MyListView : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
return new DesignerItem();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is DesignerItem;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var elem = element as DesignerItem;
elem.ContentEditTemplate = ItemEditTemplate;
}
public DataTemplate ItemEditTemplate
{
get { return (DataTemplate)GetValue(ItemEditTemplateProperty); }
set { SetValue(ItemEditTemplateProperty, value); }
}
public static readonly DependencyProperty ItemEditTemplateProperty =
DependencyProperty.Register("ItemEditTemplate", typeof(DataTemplate), typeof(MyListView));
}
public class DesignerItem : ListViewItem
{
static DesignerItem()
{
ContentTemplateProperty.OverrideMetadata(typeof(DesignerItem), new FrameworkPropertyMetadata(
null, new CoerceValueCallback(CoerceContentTemplate)));
}
private static object CoerceContentTemplate(DependencyObject d, object baseValue)
{
var self = d as DesignerItem;
if (self != null && self.IsEditing)
{
return self.ContentEditTemplate;
}
return baseValue;
}
private static void OnIsEditingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(ContentTemplateProperty);
}
public bool IsEditing
{
get { return (bool)GetValue(IsEditingProperty); }
set { SetValue(IsEditingProperty, value); }
}
public static readonly DependencyProperty IsEditingProperty =
DependencyProperty.Register("IsEditing", typeof(bool), typeof(DesignerItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsEditingChanged)));
public DataTemplate ContentEditTemplate
{
get { return (DataTemplate)GetValue(ContentEditTemplateProperty); }
set { SetValue(ContentEditTemplateProperty, value); }
}
public static readonly DependencyProperty ContentEditTemplateProperty =
DependencyProperty.Register("ContentEditTemplate", typeof(DataTemplate), typeof(DesignerItem));
}
注意,为了举例说明,我将通过使用一些触发器来激活“编辑”模式,方法是通过
ListViewItem.IsSelected
。
<local:MyListView ItemsSource="}">
<local:MyListView.ItemContainerStyle>
<Style TargetType="">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="IsEditing" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</local:MyListView.ItemContainerStyle>
<local:MyListView.ItemTemplate>
<DataTemplate>
<Border Background="Red" Margin="5" Padding="5">
<TextBlock Text="Hello World"/>
</Border>
</DataTemplate>
</local:MyListView.ItemTemplate>
<local:MyListView.ItemEditTemplate>
<DataTemplate>
<Border Background="Green" Margin="5" Padding="5">
<TextBlock Text="Hello World"/>
</Border>
</DataTemplate>
</local:MyListView.ItemEditTemplate>
</local:MyListView>
预期行为:所选项目变为可编辑状态,获取local:MyListView.ItemEditTemplate
(绿色)而不是默认模板(红色)。