2010-08-04 40 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