在TreeViewItem样式触发器期间,TextDecorations未应用于TextBlock

时间:2010-08-04 02:24:42

标签: c# wpf

我有一个WPF应用程序,我希望通过使用删除线TextDecoration显示逻辑删除的项目(在TreeView中保存)。

我可以在触发时获得样式触发器以成功应用Foreground颜色,但是当我尝试设置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也有一个图标,为简洁起见,我省略了它,虽然看起来没什么区别。

有没有人知道为什么这不起作用?

1 个答案:

答案 0 :(得分: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>