代码之家  ›  专栏  ›  技术社区  ›  HAdes

如何在属性更改时更改控件的外观?

  •  1
  • HAdes  · 技术社区  · 14 年前

    我想向用户突出显示任何修改过的内容,以便他们知道他们更改了什么,或者在幕后对他们进行了哪些编程更改。

    我想用样式将这个逻辑应用到我所有的控件中,但我不确定如何应用。我知道我需要创建一个触发器,但不知道确切触发什么,也不知道如何获取绑定属性的任何更改,以便知道它是否已更改。

    3 回复  |  直到 14 年前
        1
  •  2
  •   Robert Rossney    14 年前

    可能最好的方法是为实现的值编写一个包装类 INotifyPropertyChanged 并显示读/写 Value 类型属性 object ValueHasChanged 财产。然后,您可以很容易地在 价值

    if (!value.Equals(_Value))
    {
       _Value = value;
       ValueHasChanged=true;
       OnPropertyChanged("Value");
    }
    

    而不是你的视图模型类公开 string DateTime 属性,它应该暴露 ValueWrapper

    private string SomeStringField;
    
    private ValueWrapper _SomeStringProperty;
    
    public ValueWrapper SomeStringProperty
    {
       get 
       { 
          return (_SomeStringProperty == null) 
             ? _SomeStringProperty = new ValueWrapper(SomeStringField) 
             : _SomeStringProperty; 
       }
    }
    

    然后您可以构建一个样式,如:

    <Style x:Key="ShowChangedValue">
       <Setter Property="Background" Value="White"/>
       <Style.Triggers>
          <DataTrigger Binding="{Binding ValueHasChanged}" Value="True">
             <Setter Property="Background" Value="AliceBlue"/>
          </DataTrigger>
        </Style.Triggers>
    </Style>
    

    使用方式如下:

    <TextBox DataContext="{Binding SomeStringProperty}" 
             Text="{Binding Value, Mode=TwoWay}"
             Style="{StaticResource ShowChangedValue}"/>
    

    这其中有一些恼人的事情,比如要在主视图模型类中更改属性的值,现在必须使用 SomeStringProperty.Value = "foo" SomeStringProperty = "foo"

        2
  •  2
  •   Chris Taylor    14 年前

    创建 ValueTracker 类,该类将提供以下3个附加的依赖项属性

    -这将是应跟踪的控件的属性

    默认值 -这是一个被认为是默认值的值,否则就会触发样式触发器。

    -这将指示如果当前值与默认值匹配,则此属性将在触发器测试中使用。

    这是一个快速的测试,它不是完美的,但我相信一点点软性将使事情进展顺利,当然,有更多WPF经验的人可以改进这个想法。

    using System;
    using System.Windows;
    using System.ComponentModel;
    
    namespace WpfApplication1
    {
      public static class ValueTracker
      {
        // Attached dependency property for DefaultValue 
        public static object GetDefaultValue(DependencyObject obj)
        {
          return (object)obj.GetValue(DefaultValueProperty);
        }
    
        public static void SetDefaultValue(DependencyObject obj, object value)
        {
          obj.SetValue(DefaultValueProperty, value);
        }
    
        public static readonly DependencyProperty DefaultValueProperty =
            DependencyProperty.RegisterAttached("DefaultValue", 
            typeof(object), typeof(ValueTracker), new UIPropertyMetadata(0));
    
        // Attached dependency property for IsDefaultValue 
        public static bool GetIsDefaultValue(DependencyObject obj)
        {      
          return (bool)obj.GetValue(IsDefaultValueProperty);
        }
    
        private static void SetIsDefaultValue(DependencyObject obj, bool value)
        {
          obj.SetValue(IsDefaultValueProperty, value);
        }
    
        public static readonly DependencyProperty IsDefaultValueProperty =
            DependencyProperty.RegisterAttached("IsDefaultValue", 
            typeof(bool), typeof(ValueTracker), new UIPropertyMetadata(false));
    
        // Attached dependency property for TrackedProperty 
        public static DependencyProperty GetTrackProperty(DependencyObject obj)
        {
          return (DependencyProperty)obj.GetValue(TrackPropertyProperty);
        }
    
        public static void SetTrackProperty(DependencyObject obj, DependencyProperty value)
        {      
          obj.SetValue(TrackPropertyProperty, value);
        }
    
        public static readonly DependencyProperty TrackPropertyProperty =
            DependencyProperty.RegisterAttached("TrackProperty", 
            typeof(DependencyProperty), typeof(ValueTracker), 
            new UIPropertyMetadata(TrackPropertyChanged));
    
    
        public static void TrackPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {   
          DependencyProperty oldProperty = e.OldValue as DependencyProperty;
          if (oldProperty != null)
          {
            DependencyPropertyDescriptor dpd = 
              DependencyPropertyDescriptor.FromProperty(oldProperty, typeof(UIElement));
    
            if (dpd != null)
            {
              dpd.RemoveValueChanged(d, TrackedPropertyValueChanged);
            }
          }
    
          DependencyProperty newProperty = e.NewValue as DependencyProperty;
          if (newProperty != null)
          {        
            DependencyPropertyDescriptor dpd = 
              DependencyPropertyDescriptor.FromProperty(newProperty, typeof(UIElement));
    
            if (dpd != null)
            {
              dpd.AddValueChanged(d, TrackedPropertyValueChanged);
            }        
          }
        }
    
        private static void TrackedPropertyValueChanged(object sender, EventArgs e)
        {
          DependencyObject o = sender as DependencyObject;
          if (o != null)
          {         
            object defaultValue = Convert.ChangeType(GetDefaultValue(o), GetTrackProperty(o).PropertyType);
            SetIsDefaultValue(o, Object.Equals(o.GetValue(GetTrackProperty(o)), defaultValue));        
          }
        }
      }
    }
    

    以上可按如下方式使用。

    2-对于要跟踪的每个控件,附加样式并设置ValueTracker.DefaultValue并设置应使用ValueTracker.TrackProperty.

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:r="clr-namespace:WpfApplication1"
            mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow"         
            d:DesignHeight="221" d:DesignWidth="287"
            Width="250" Height="250">
      <StackPanel Loaded="StackPanel_Loaded" >
        <StackPanel.Resources>
          <Style TargetType="{x:Type Control}" x:Key="trackChanges">
            <Style.Triggers>
              <Trigger Property="local:ValueTracker.IsDefaultValue" Value="false">
                <Setter Property="FontWeight" Value="Bold" />
              </Trigger>
            </Style.Triggers>
          </Style>
        </StackPanel.Resources>
    
        <TextBox Name="textbox1" Width="100" Height="23" 
                 local:ValueTracker.DefaultValue="Help" 
                 local:ValueTracker.TrackProperty="TextBox.Text" 
                 Style="{StaticResource ResourceKey=trackChanges}" />
    
        <ComboBox Name="combobox1" 
                  SelectedIndex="2" 
                  local:ValueTracker.DefaultValue="2" 
                  local:ValueTracker.TrackProperty="ComboBox.SelectedIndex" 
                  Style="{StaticResource ResourceKey=trackChanges}">
          <ComboBox.Items>
            <ComboBoxItem>Item 1</ComboBoxItem>
            <ComboBoxItem>Item 2</ComboBoxItem>
            <ComboBoxItem>Item 3</ComboBoxItem>
            <ComboBoxItem>Item 4</ComboBoxItem>
          </ComboBox.Items>
        </ComboBox>
      </StackPanel>
    </Window>
    
        3
  •  -1
  •   yoav.str    14 年前

    我会重新编写关于INotifyPropertyChanged的设计模式的阅读

    dispatcher on msdn

    假设你想打印新的电路板你应该这样做

      printDelgate paintControlDelgate = () => paintControl();
      m_CurrentDispatcher.Invoke(paintControlDelgate);
    

    <ControlTemplate x:Key="StarTemplate" TargetType="{x:Type Button}">
        <Grid>
            <ed:RegularPolygon Visibility="Collapsed" Name="star1" Fill="{Binding Path=ButtonColor}" 
                                   InnerRadius="0.47211" Margin="20.5,16,15.5,8" PointCount="5"  Stroke="Black"
                                   StrokeThickness="2"  Height="40" Width="40"/>
            <ed:RegularPolygon Name="star2" Fill="Black" Visibility="Visible"  InnerRadius="0.47211" Margin="20.5,16,15.5,8"
                                   PointCount="5"  Stroke="Black" StrokeThickness="6"  Height="40" Width="40"/>
        </Grid>
    
        <ControlTemplate.Triggers>
    
            <Trigger Property="IsPressed"  Value="True">
                <Setter TargetName="star1" Property="Visibility" Value="Visible"/>
                <Setter TargetName="star2" Property="Visibility" Value="Collapsed"/>
            </Trigger>
    

    所以当按钮被按下时,它的内容可见性就会改变。