Home > Blockchain >  Send objects to UserControl
Send objects to UserControl

Time:06-19

I am trying to send objects to an UserControl, but I cannot figure what's wrong?

Here is my UserControl :

namespace VSTEEL.UserControls
{
    /// <summary>
    /// Interaction logic for UserControlListOperations.xaml
    /// </summary>
    public partial class UserControlListOperations : UserControl,INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(string nomPropriete)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(nomPropriete));
        }
        public string MyString
        {
            get
            {
                return (string)GetValue(MyStringProperty);
            }
            set
            {
                SetValue(MyStringProperty, value); this.NotifyPropertyChanged("MyString");
            }
        }
        public static DependencyProperty MyStringProperty =
        DependencyProperty.Register(
        nameof(MyString),
        typeof(string),
        typeof(UserControlListOperations),
        new PropertyMetadata(MyStringPropertyChanged));
        private static void MyStringPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            //var userControl = (UserControlMyString)obj;

            // handle the new property value here
        }

        public static DependencyProperty ListOp1Property =
        DependencyProperty.Register(
        nameof(ListOp1),
        typeof(IList<Operation>),
        typeof(UserControlListOperations),
        new PropertyMetadata(ListOp1PropertyChanged));

        public IList<Operation> ListOp1
        {
            get
            {
                return (IList<Operation>)GetValue(ListOp1Property);
            }
            set
            {
                SetValue(ListOp1Property, value);this.NotifyPropertyChanged("ListOp1");
            }
        }
        private static void ListOp1PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var userControl = (UserControlListOperations)obj;

            // handle the new property value here
        }
        public Contract Contract
        {
            get
            {
                return (Contract)GetValue(ContractProperty);
            }
            set
            {
                SetValue(ContractProperty, value); this.NotifyPropertyChanged("Contract");
            }
        }
        public static DependencyProperty ContractProperty =
        DependencyProperty.Register("Contract", typeof(Contract), typeof(UserControlListOperations));


        private List<Operation> listOp2 { get; set; } = new List<Operation>( Global.GetListOperations());
        public List<Operation> ListOp2 { get { return this.listOp2; } set { this.listOp2 = value; } }

        public UserControlListOperations()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        static FrameworkPropertyMetadata propertyMetaData = new FrameworkPropertyMetadata
        (
            "UserControlListOperations",
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
            new PropertyChangedCallback(TextProperty_PropertyChanged)
        );

        private static void TextProperty_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            
        }

        
    }
}

And here is my main window, from which I am trying to open the UserControl :

<GridViewColumn Header="{x:Static p:Resources.Advancement}" Width="{Binding WidthColumnContractAdv, Mode=TwoWay}">
    <GridViewColumn.CellTemplate>
        <DataTemplate>
            <StackPanel Tag="{Binding}" MouseMove="mouseOverProgressionContractAss">
                <Grid>
                    <views:UserControlListOperations 
                    ListOp1 = "{Binding Path = ListOpAss}"
                    MyString="toto"/>
                    <!--SetListOp2 = "{Binding DataContext.ListOpAssTot}"/>-->
                    </Grid>
                </StackPanel>
            </DataTemplate>
        </GridViewColumn.CellTemplate>
    </GridViewColumn>
    <GridViewColumn Header="{x:Static p:Resources.Advancement}" Width="{Binding WidthColumnContractAdv, Mode=TwoWay}">
        <GridViewColumn.CellTemplate>
            <DataTemplate>
                <StackPanel Tag="{Binding}" MouseMove="mouseOverProgressionContractAss">
                    <Rectangle Name="AFF_Track"  Height="12" Stroke="black" StrokeThickness="1"  Tag="{Binding ID}">
                        <Rectangle.Fill>
                            <MultiBinding Converter="{StaticResource :listOpToLinearGradientBrush}">
                                <Binding Path="ListOpAss" />
                                <Binding RelativeSource="{RelativeSource AncestorType={x:Type Fluent:RibbonWindow}}" Path="DataContext.ListOpAssTot" />
                                <Binding Source="0"/>
                            </MultiBinding>
                        </Rectangle.Fill>
                        <Rectangle.ToolTip>
                            <ContentControl  Template="{StaticResource ToolTipOperations}"/>
                        </Rectangle.ToolTip>
                    </Rectangle>

                    <Rectangle Name="AFF_Track2"  Height="12" Stroke="black" StrokeThickness="1"  Tag="{Binding ID}">
                        <Rectangle.Fill>
                            <MultiBinding Converter="{StaticResource :listOpToLinearGradientBrush}">
                                <Binding Path="ListOpAss" />
                                <Binding RelativeSource="{RelativeSource AncestorType={x:Type Fluent:RibbonWindow}}" Path="DataContext.ListOpAssTot" />
                                <Binding Source="1"/>
                            </MultiBinding>
                        </Rectangle.Fill>
                        <Rectangle.ToolTip>
                            <ContentControl  Template="{StaticResource ToolTipOperations}"/>
                        </Rectangle.ToolTip>
                    </Rectangle>
                </StackPanel>
            </DataTemplate>
        </GridViewColumn.CellTemplate>
    </GridViewColumn>

My first GridViewColumn is the one opening the UserControl, but in debugging, I can se that SetValue(ListOp1Property, value); is never launched, and that's what I cannot understand? (the UserControl is corrctly initialized)

I left the second column to check, that all is working fine without using UseControl (and it is working).

Here is my UserControl XAML : (I added a string MyString, and it is corrctly set, not objects.

<UserControl x:Class="VSTEEL.UserControls.UserControlListOperations"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:converters="clr-namespace:VSTEEL.Converters;assembly=MainLibrary"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:VSTEEL.UserControls"
             mc:Ignorable="d" 
             >
    <UserControl.Resources>
        <converters:ListOpToLinearGradientBrush x:Key=":listOpToLinearGradientBrush" />
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <Label Content="{Binding MyString}"/>
        <Rectangle Grid.Row="1" Name="AFF_Track"  Height="12" Stroke="black" StrokeThickness="1"  Tag="{Binding ID}">
            <Rectangle.Fill>
                <MultiBinding Converter="{StaticResource :listOpToLinearGradientBrush}">
                    <Binding Path="ListOp1" />
                    <Binding Path="Contract" />
                    <Binding Source="0"/>
                </MultiBinding>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Row="2" Name="AFF_Track2"  Height="12" Stroke="black" StrokeThickness="1"  Tag="{Binding ID}">
            <Rectangle.Fill>
                <MultiBinding Converter="{StaticResource :listOpToLinearGradientBrush}">
                    <Binding Path="ListOp1" />
                    <Binding Path="Contract" />
                    <Binding Source="0"/>
                </MultiBinding>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>
</UserControl>

CodePudding user response:

Yould have to register the PropertyChangedCallback with PropertyMetadata that you pass as a fourth argument to the Register method. You should also use a more generic type for the property.

A correct dependency property implementation would look like this:

public static readonly DependencyProperty ListOp1Property =
    DependencyProperty.Register(
        nameof(ListOp1),
        typeof(IList<Operation>), // or ICollection or IEnumerable
        typeof(UserControlListOperations),
        new PropertyMetadata(ListOp1PropertyChanged)); // here

public IList<Operation> ListOp1
{
    get { return (IList<Operation>)GetValue(ListOp1Property); }
    set { SetValue(ListOp1Property, value); }
}

private static void ListOp1PropertyChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var userControl = (UserControlListOperations)obj;

    // handle the new property value here
}

Besides that, in order to bind to its own properties, the Bindings in the UserControl's XAML must have their source object to the control instance, e.g. by RelativeSource={RelativeSource AncestorType=UserControl}.

When there ary many such Bindings, you can alternatively set the DataContext of the top level element in the control's XAML:

<Grid DataContext="{Binding
    RelativeSource={RelativeSource AncestorType=UserControl}}">
  • Related