The attached property is not send to the style

ComptonAlvaro 166 Reputation points
2022-02-23T12:28:48.583+00:00

I wanted to create a cell style to show errors and a text with the tooltip.

My style in the xaml dictionary file is this:

<Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCellConErrores">
    <Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
    <Setter Property="ToolTipService.InitialShowDelay" Value="5000"/>
    <Setter Property="ToolTipService.ShowDuration" Value="60000"/>

    <Setter Property="ToolTip">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource ResourceKey=dlgEnviarAlbaranCantidadParaDescontarTooltipMultivalueConverter}">
                <MultiBinding.Bindings>
                    <Binding Path="(ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip01)"/>
                    <Binding Path="(ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip02)"/>
                </MultiBinding.Bindings>
            </MultiBinding>
        </Setter.Value>
    </Setter>

    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding Path=(ap:CeldasDatagridConErroresAttachedProperty.EsDatoCorrecto)}" Value="false"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" Value="Orange"/>
        </MultiDataTrigger>
    </Style.Triggers>
</Style>

This is how I am trying to use in my column of the datagrid:

<DataGridTextColumn Header="Cantidad Para Descontar" Binding="{Binding CantidadParaDescontar, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, ValidatesOnDataErrors=True}" Width="AUTO" IsReadOnly="false"
                    ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip01="{Binding Path=DescripcionCantidadParaDescontar}"
                    ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip02="{Binding Path=MotivoCantidadParaDescontarIncorrecta}"
                    ap:CeldasDatagridConErroresAttachedProperty.EsDatoCorrecto="{Binding Path=EsCantidadParaDescontarCorrecta}"
                        CellStyle="{StaticResource DataGridCellConErrores}"/>

I can compile and run, but the text of tooltip is always empty and also it doesn't change the color of the background if the data is not correct.

How should I bind the attached properties?

Thanks.

EDIT 1: I will add a new simplified example that reproduce the same problem. This is the whole code:

The view:

<Window x:Class="TestStyleWithAttachedProperties.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:conv="clr-namespace:TestStyleWithAttachedProperties.Converters"
        xmlns:vm="clr-namespace:TestStyleWithAttachedProperties.ViewModels"
        xmlns:ap="clr-namespace:TestStyleWithAttachedProperties.AttachedProperties"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>


    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="GUIResources.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <!--<conv:CellTooltipMultiValueConverter x:Key="CellTooltipMultiValueConverter"/>-->
        </ResourceDictionary>
    </Window.Resources>


    <Grid>
        <DataGrid Name="dgdTest" Grid.Column="0" Margin="5,5,5,5"
                  ItemsSource="{Binding Items}"
                  AutoGenerateColumns="false">

            <DataGrid.Columns>
                <DataGridTextColumn Header="Price" Binding="{Binding Price}" Width="150"
                    ap:CellWithErrorsAttachedProperty.TextoTooltip01="{Binding Path=Tooltip}"
                    ap:CellWithErrorsAttachedProperty.TextoTooltip02="{Binding Path=ErrorDescription}"
                    ap:CellWithErrorsAttachedProperty.EsDatoCorrecto="{Binding Path=IsDataCorrect}"
                    CellStyle="{StaticResource DataGridCellWithErrorsStyle}">
                </DataGridTextColumn>

                <DataGridTextColumn Header="Discount" Binding="{Binding Discount}" Width="150"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

The view model:

using System.Collections.ObjectModel;

namespace TestStyleWithAttachedProperties.ViewModels
{
    public class MainWindowViewModel : BaseViewModel
    {
        public MainWindowViewModel()
        {
            Items = new ObservableCollection<Data>();

            Data miData01 = new Data()
            {
                Price = 1m,
                Discount = 0m,
                Tooltip = "Tooltip Data01",
                ErrorDescription = "No errors",
                IsDataCorrect = true,
            };

            Items.Add(miData01);


            Data miData02 = new Data()
            {
                Price = 2m,
                Discount = 10m,
                Tooltip = "Tooltip Data02",
                ErrorDescription = "No errors",
                IsDataCorrect = true,
            };

            Items.Add(miData02);


            Data miData03 = new Data()
            {
                Price = -1m,
                Discount = 0m,
                Tooltip = "Tooltip Data03",
                ErrorDescription = "Price has to be greater than 0.",
                IsDataCorrect = false,
            };

            Items.Add(miData03);
        }


        private ObservableCollection<Data> _items;

        public ObservableCollection<Data> Items
        {
            get { return _items; }
            set
            {
                _items = value;
                base.RaisePropertyChangedEvent(nameof(Items));
            }
        }
    }
}

The Data class:

using TestStyleWithAttachedProperties.ViewModels;

namespace TestStyleWithAttachedProperties
{
    public class Data : BaseViewModel
    {
        private decimal _price;

        public decimal Price
        {
            get { return _price; }
            set
            {
                _price = value;
                base.RaisePropertyChangedEvent(nameof(Price));
            }
        }

        private decimal _disocunt;

        public decimal Discount
        {
            get { return _disocunt; }
            set
            {
                _disocunt = value;
                base.RaisePropertyChangedEvent(nameof(Discount));
            }
        }


        private string _tooltip;

        public string Tooltip
        {
            get { return _tooltip; }
            set
            {
                _tooltip = value;
                base.RaisePropertyChangedEvent(nameof(Tooltip));
            }
        }



        private string _errorDescription;

        public string ErrorDescription
        {
            get { return _errorDescription; }
            set
            {
                _errorDescription = value;
                base.RaisePropertyChangedEvent(nameof(ErrorDescription));
            }
        }



        private bool _isDataCorrect;

        public bool IsDataCorrect
        {
            get { return _isDataCorrect; }
            set
            {
                _isDataCorrect = value;
                base.RaisePropertyChangedEvent(nameof(IsDataCorrect));
            }
        }
    }
}

The GUI xaml resources:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:ap="clr-namespace:TestStyleWithAttachedProperties.AttachedProperties"
                    xmlns:conv="clr-namespace:TestStyleWithAttachedProperties.Converters"
                    xmlns:sys="clr-namespace:System;assembly=System.Runtime">




    <conv:CellTooltipMultiValueConverter x:Key="CellTooltipMultiValueConverter"/>



    <Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCellWithErrorsStyle">
        <Setter Property="ToolTip">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource ResourceKey=CellTooltipMultiValueConverter}">
                    <MultiBinding.Bindings>
                        <Binding Path="(ap:CellWithErrorsAttachedProperty.TextoTooltip01)" RelativeSource="{RelativeSource AncestorType=DataGridTextColumn}"/>
                        <Binding Path="(ap:CellWithErrorsAttachedProperty.TextoTooltip02)" RelativeSource="{RelativeSource AncestorType=DataGridTextColumn}"/>
                    </MultiBinding.Bindings>
                </MultiBinding>
            </Setter.Value>
        </Setter>

        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Path=(ap:CellWithErrorsAttachedProperty.EsDatoCorrecto), RelativeSource={RelativeSource AncestorType=DataGridTextColumn}}" Value="false"/>
                </MultiDataTrigger.Conditions>
                <Setter Property="Background" Value="Orange"/>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>
</ResourceDictionary>

The attached properties:

using System.Windows;




namespace TestStyleWithAttachedProperties.AttachedProperties
{
    public static class CellWithErrorsAttachedProperty
    {
        //TextoTooltip01
        //Primer texto del tooltip que se mostrará.
        public static readonly DependencyProperty TextoTooltip01Property =
            DependencyProperty.RegisterAttached(
            "TextoTooltip01",
            typeof(string),
            typeof(CellWithErrorsAttachedProperty));

        public static string GetTextoTooltip01(DependencyObject obj)
        {
            return (string)obj.GetValue(TextoTooltip01Property);
        }

        public static void SetTextoTooltip01(DependencyObject obj, string value)
        {
            obj.SetValue(TextoTooltip01Property, value);
        }



        //TextoTooltip02
        //Primer texto del tooltip que se mostrará.
        public static readonly DependencyProperty TextoTooltip02Property =
            DependencyProperty.RegisterAttached(
            "TextoTooltip02",
            typeof(string),
            typeof(CellWithErrorsAttachedProperty));

        public static string GetTextoTooltip02(DependencyObject obj)
        {
            return (string)obj.GetValue(TextoTooltip01Property);
        }

        public static void SetTextoTooltip02(DependencyObject obj, string value)
        {
            obj.SetValue(TextoTooltip01Property, value);
        }





        //ES DATO CORRECTO
        //Indica si el dato de la celda es correcto o no.
        public static readonly DependencyProperty EsDatoCorrectoProperty =
            DependencyProperty.RegisterAttached(
            "EsDatoCorrecto",
            typeof(bool),
            typeof(CellWithErrorsAttachedProperty));

        public static bool GetEsDatoCorrecto(DependencyObject obj)
        {
            return (bool)obj.GetValue(EsDatoCorrectoProperty);
        }

        public static void SetEsDatoCorrecto(DependencyObject obj, bool value)
        {
            obj.SetValue(EsDatoCorrectoProperty, value);
        }
    }
}

Then multivalue converter:

using System;
using System.Globalization;
using System.Windows.Data;



namespace TestStyleWithAttachedProperties.Converters
{
    public class CellTooltipMultiValueConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            //here values are unset values.
            //If I return a string, it is shown in the datagrid. But I can't do any logic because the values are null.
            return "Hola";
        }



        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

The base view model that implements INotifyPropertyChanged:

using System.ComponentModel;

namespace TestStyleWithAttachedProperties.ViewModels
{
    public abstract class BaseViewModel : INotifyPropertyChanging, INotifyPropertyChanged
    {
        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Administrative Properties

        /// <summary>
        /// Whether the view model should ignore property-change events.
        /// </summary>
        public virtual bool IgnorePropertyChangeEvents { get; set; }

        #endregion

        #region Public Methods
        /// <summary>
        /// Raises the PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The name of the changed property.</param>
        public virtual void RaisePropertyChangedEvent(string propertyName)
        {
            // Exit if changes ignored
            if (IgnorePropertyChangeEvents) return;

            // Exit if no subscribers
            if (PropertyChanged == null) return;

            // Raise event
            var e = new PropertyChangedEventArgs(propertyName);
            PropertyChanged(this, e);
        }

        /// <summary>
        /// Raises the PropertyChanging event.
        /// </summary>
        /// <param name="propertyName">The name of the changing property.</param>
        public virtual void RaisePropertyChangingEvent(string propertyName)
        {
            // Exit if changes ignored
            if (IgnorePropertyChangeEvents) return;

            // Exit if no subscribers
            if (PropertyChanging == null) return;

            // Raise event
            var e = new PropertyChangingEventArgs(propertyName);
            PropertyChanging(this, e);
        }

        #endregion
    }
}

This is the full code, I don't know if it is allowed to us a link to onedrive to can download the project, if it is possible, I could do it.

Thanks.

Developer technologies | Windows Presentation Foundation
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.