2010-08-04 53 views
2

我有一个WPF应用程序,我想通过用删除线TextDecoration显示它们来装饰逻辑删除的项目(在TreeView中保存)。在TreeViewItem样式触发器中TextDecorations不应用于TextBlock

我可以在触发时成功应用前景色,但是当我尝试设置TextDecorations时,它没有任何效果。

下面是一些示例代码,可以重现问题。首先,XAML:


<Style TargetType="TreeViewItem"> 
    <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}" /> 
    <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" /> 
    <EventSetter Event="TreeViewItem.MouseRightButtonDown" Handler="tvw_MouseRightButtonUp"/> 
    <Style.Triggers> 
    <DataTrigger Binding="{Binding IsDeleted}" Value="True"> 
    <!--<Setter Property="TextBlock.Foreground" Value="red" />--> 
    <Setter Property="TextBlock.TextDecorations" Value="Underline" /> 
    </DataTrigger> 
    </Style.Triggers> 
</Style> 
</TreeView.Resources> 

这里是C#

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.ComponentModel; 
using System.Collections.ObjectModel; 
using System.Globalization; 

namespace StrikethroughTest { 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window { 
     public MainWindow() { 
      InitializeComponent(); 
      ObservableCollection<ViewModel> model = BuildModel(); 
      tvw.ItemsSource = model; 
     } 

     private ObservableCollection<ViewModel> BuildModel() { 
      ObservableCollection<ViewModel> toplevel = new ObservableCollection<ViewModel>(); 
      ViewModel root = new ViewModel("Root"); 
      toplevel.Add(root); 
      for (int i = 1; i < 5; ++i) { 
       ViewModel child = new ViewModel("Child " + i); 
       root.AddChild(child); 
       for (int j = 1; j < 5; ++j) { 
        ViewModel leaf = new ViewModel("Leaf " + i + "," + j); 
        child.AddChild(leaf); 
       } 
      } 
      return toplevel; 
     } 

     private void tvw_MouseRightButtonUp(object sender, MouseButtonEventArgs e) { 
      ViewModel item = tvw.SelectedItem as ViewModel; 
      if (item != null) { 
       ShowMenu(item, tvw); 
      } 

     } 

     private void ShowMenu(ViewModel item, FrameworkElement source) { 
      ContextMenu menu = new ContextMenu(); 
      MenuItem mnuDelete = new MenuItem(); 
      mnuDelete.Header = "Delete"; 
      mnuDelete.Click += new RoutedEventHandler((src, e) => { item.IsDeleted = true; }); 
      menu.Items.Add(mnuDelete); 
      source.ContextMenu = menu; 
     } 

    } 

    public class ViewModel : ViewModelBase { 

     private bool _expanded; 
     private bool _selected; 
     private bool _deleted; 
     private ObservableCollection<ViewModel> _children;   

     public ViewModel(string caption) { 
      this.Caption = caption; 
      _children = new ObservableCollection<ViewModel>(); 
     } 

     public void AddChild(ViewModel child) { 
      _children.Add(child); 
     } 

     public bool IsExpanded { 
      get { return _expanded; } 
      set { SetProperty("IsExpanded", ref _expanded, value); } 
     } 

     public bool IsSelected { 
      get { return _selected; } 
      set { SetProperty("IsSelected", ref _selected, value); } 
     } 

     public bool IsDeleted { 
      get { return _deleted; } 
      set { SetProperty("IsDeleted", ref _deleted, value); } 
     } 

     public ObservableCollection<ViewModel> Children { 
      get { return _children; } 
     } 


     public String Caption { get; set; } 

    } 

    public abstract class ViewModelBase : INotifyPropertyChanged { 
     protected bool SetProperty<T>(string propertyName, ref T backingField, T value) { 
      var changed = !EqualityComparer<T>.Default.Equals(backingField, value); 
      if (changed) { 
       backingField = value; 
       RaisePropertyChanged(propertyName); 
      } 
      return changed; 
     } 

     protected void RaisePropertyChanged(string propertyName) { 
      if (PropertyChanged != null) { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 


     public event PropertyChangedEventHandler PropertyChanged; 

    } 
} 

当某人选择树节点时,右键单击并选择删除,我希望标题被删除。在我的真实应用程序中,每个TreeViewItem都有一个图标,为简洁起见我省略了它们,尽管它看起来没有什么区别。

有没有人有任何想法,为什么这不工作?

回答

4

您正在设置TreeViewItem的属性。设置TextBlock.Foreground的工作原理是因为该属性是可继承的(请参阅Property Value Inheritance),所以TextBlock将从其父TreeViewItem中获取值。 TextBlock.TextDecorations不可继承,因此您需要将其设置在TextBlock本身而不是TreeViewItem上。

这样做可能是通过做这样的事情把触发器在DataTemplate中最简单的方法:

<TreeView.Resources> 
    <Style TargetType="TreeViewItem"> 
     <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay}" /> 
     <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" /> 
     <EventSetter Event="TreeViewItem.MouseRightButtonDown" Handler="tvw_MouseRightButtonUp"/> 
    </Style> 
    <HierarchicalDataTemplate DataType="{x:Type vm:ViewModel}" ItemsSource="{Binding Children}"> 
     <TextBlock Name="TextBlock" Text="{Binding Caption}"/> 
     <HierarchicalDataTemplate.Triggers> 
      <DataTrigger Binding="{Binding IsDeleted}" Value="True"> 
       <Setter TargetName="TextBlock" Property="TextDecorations" Value="Underline" /> 
      </DataTrigger> 
     </HierarchicalDataTemplate.Triggers> 
    </HierarchicalDataTemplate> 
</TreeView.Resources> 
+0

谢谢,完美的作品!我想我认为这是因为我用'TextBlock'为我的setter属性添加了前缀,它会以某种方式将它神奇地应用于与该类型匹配的TreeViewItem的所有后代子节点。我想我仍然有办法理解继承模型。感谢您的链接,我会去看看。 – David 2010-08-05 02:24:26

相关问题