简体   繁体   中英

How to Create a Custom DataGrid

All, in this answer https://stackoverflow.com/a/18136371/626442 to a previous question, the answer provided a solution to the problem of my animation not firing. The code was

<DataTemplate x:Key="readOnlyCellUpdatedStyle">
    <TextBlock Text="{Binding KeyIndex, Mode=TwoWay,NotifyOnTargetUpdated=True}">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Setter Property="Background" Value="White"/>
                <Style.Triggers>
                    <EventTrigger RoutedEvent="Binding.TargetUpdated">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetProperty="Background.Color" 
                                    Duration="0:0:0.3"
                                    From="White" 
                                    To="Red" 
                                    RepeatBehavior="3x" 
                                    AutoReverse="True"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</DataTemplate>

This fires the animation when I update the KeyIndex column via the ViewModel. However, I only want the animation of the cells of the DataGridTextColumn to animate when the values are updated but they also fire when the DataGrid is scrolled. I was suggested

It may be a better option to create a derived DataGridTextColumn with the features you need built in, as using TargetUpdated will be pretty much impossible if you are using Virtualization. But if you made a custom DataGridTextColumn you should be able to get it working.

How do I create a custom/derived `DataGridTextColumn (I have access to blend too)?

I have no idea how to do this and the documentation on this particular concept is sparse.

Thanks for your time.

It turned out to be quite difficult to get this working with Virtualization when using VirtualizationMode="Recycling"

I found a way to get it working by deriving TextBlock and attaching to the PropertyChanged event of the bound object.

When the value changes the animation is played, but if you scroll the recycled item does not continue to play the animation.

This is a pretty rough example but I am sure you can clean up and modify to your needs.

TextBlock:

public class VirtualizingNotifyTextBlock : TextBlock
{
    private INotifyPropertyChanged _dataItem;
    private string _propertyName;

    public VirtualizingNotifyTextBlock()
        : base()
    {
        this.TargetUpdated += NotifyTextBlock_TargetUpdated;
    }

    public static readonly RoutedEvent PropertyChangedEvent = EventManager.RegisterRoutedEvent("PropertyChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(VirtualizingNotifyTextBlock));
    public static readonly DependencyProperty NotifyDurationProperty = DependencyProperty.Register("NotifyDuration", typeof(int), typeof(VirtualizingNotifyTextBlock), new PropertyMetadata(300));
    public static readonly DependencyProperty NotifyRepeatProperty = DependencyProperty.Register("NotifyRepeat", typeof(int), typeof(VirtualizingNotifyTextBlock), new PropertyMetadata(3));
    public static readonly DependencyProperty NotifyColorProperty = DependencyProperty.Register("NotifyColor", typeof(Color), typeof(VirtualizingNotifyTextBlock), new PropertyMetadata(Colors.Red));

    public Color NotifyColor
    {
        get { return (Color)GetValue(NotifyColorProperty); }
        set { SetValue(NotifyColorProperty, value); }
    }

    public int NotifyDuration
    {
        get { return (int)GetValue(NotifyDurationProperty); }
        set { SetValue(NotifyDurationProperty, value); }
    }

    public int NotifyRepeat
    {
        get { return (int)GetValue(NotifyRepeatProperty); }
        set { SetValue(NotifyRepeatProperty, value); }
    }

    public INotifyPropertyChanged DataItem
    {
        get { return _dataItem; }
        set
        {
            if (_dataItem != null)
            {
                Background = new SolidColorBrush(Colors.Transparent);
                _dataItem.PropertyChanged -= DataItem_PropertyChanged;
            }
            _dataItem = value;
            if (_dataItem != null)
            {
                _dataItem.PropertyChanged += DataItem_PropertyChanged;
            }
        }
    }

    private void NotifyTextBlock_TargetUpdated(object sender, DataTransferEventArgs e)
    {
        var binding = this.GetBindingExpression(VirtualizingNotifyTextBlock.TextProperty);
        if (binding != null)
        {
            _propertyName = binding.ResolvedSourcePropertyName;
            DataItem = binding.DataItem as INotifyPropertyChanged;
        }
    }

    private void DataItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == _propertyName)
        {
           var animation = new ColorAnimation(NotifyColor, new Duration(TimeSpan.FromMilliseconds(NotifyDuration)));
           animation.RepeatBehavior = new RepeatBehavior(NotifyRepeat);
           animation.AutoReverse = true;
           Background = new SolidColorBrush(Colors.Transparent);
           Background.BeginAnimation(SolidColorBrush.ColorProperty, animation);
        }
    }

}

Xaml:

<DataTemplate x:Key="readOnlyCellUpdatedStyle">
    <local:VirtualizingNotifyTextBlock Text="{Binding KeyIndex, NotifyOnTargetUpdated=True}" NotifyColor="Blue" NotifyDuration="250" NotifyRepeat="4" />
</DataTemplate>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM