【问题标题】:TextDecorations not being applied to TextBlock during a TreeViewItem Style Trigger在 TreeViewItem 样式触发器期间未将 TextDecorations 应用于 TextBlock
【发布时间】:2010-08-04 02:24:42
【问题描述】:

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

我可以让样式触发器在触发时成功应用前景色,但是当我尝试设置 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 也有一个图标,为简洁起见,我将其省略了,尽管它似乎没有任何区别。

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

【问题讨论】:

    标签: c# wpf


    【解决方案1】:

    您正在设置 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>
    

    【讨论】:

    • 谢谢,完美运行!我想我认为因为我在我的 setter 属性前面加上了“TextBlock”,所以它会以某种方式神奇地将它应用于与该类型匹配的 TreeViewItem 的所有后代子级。我想我在理解继承模型方面还有一段路要走。谢谢你的链接,我去看看。
    猜你喜欢
    • 2010-11-24
    • 2012-04-10
    • 2019-04-25
    • 2013-01-28
    • 2010-10-29
    • 1970-01-01
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多