92 votes

OneWayToSource liant à partir de la propriété readonly dans Xaml

Je suis en train d'essayer de se lier à une propriété En lecture seule avec OneWayToSource comme mode, mais il semble que ce ne peut pas être fait dans le code XAML:

<controls:FlagThingy IsModified="{Binding FlagIsModified, 
                                          ElementName=container, 
                                          Mode=OneWayToSource}" />

J'obtiens:

La propriété 'FlagThingy.IsModified' ne peut pas être ensemble parce qu'il n'a pas un accessible accesseur set.

IsModified est un readonly DependencyProperty sur FlagThingy. Je veux lier cette valeur à l' FlagIsModified de la propriété sur le conteneur.

Pour être clair:

FlagThingy.IsModified --> container.FlagIsModified
------ READONLY -----     ----- READWRITE --------

Est-ce possible en utilisant seulement XAML?


Mise à jour: eh Bien, je fixe ce cas, en mettant la liaison sur le conteneur et non sur l' FlagThingy. Mais je voudrais encore savoir si cela est possible.

49voto

alex2k8 Points 12225

Certains résultats de la recherche pour OneWayToSource...

Option # 1.

// Control definition
public partial class FlagThingy : UserControl
{
    public static readonly DependencyProperty IsModifiedProperty = 
            DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
}
<controls:FlagThingy x:Name="_flagThingy" />
// Binding Code
Binding binding = new Binding();
binding.Path = new PropertyPath("FlagIsModified");
binding.ElementName = "container";
binding.Mode = BindingMode.OneWayToSource;
_flagThingy.SetBinding(FlagThingy.IsModifiedProperty, binding);

Option # 2

// Control definition
public partial class FlagThingy : UserControl
{
    public static readonly DependencyProperty IsModifiedProperty = 
            DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());

    public bool IsModified
    {
        get { return (bool)GetValue(IsModifiedProperty); }
        set { throw new Exception("An attempt ot modify Read-Only property"); }
    }
}
<controls:FlagThingy IsModified="{Binding Path=FlagIsModified, 
    ElementName=container, Mode=OneWayToSource}" />

Option # 3 (Vrai en lecture seule propriété de dépendance)

Système.ArgumentException: 'Modifiés' propriété ne peut pas être lié aux données.

// Control definition
public partial class FlagThingy : UserControl
{
    private static readonly DependencyPropertyKey IsModifiedKey =
        DependencyProperty.RegisterReadOnly("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());

    public static readonly DependencyProperty IsModifiedProperty = 
        IsModifiedKey.DependencyProperty;
}
<controls:FlagThingy x:Name="_flagThingy" />
// Binding Code
Same binding code...

Réflecteur donne la réponse:

internal static BindingExpression CreateBindingExpression(DependencyObject d, DependencyProperty dp, Binding binding, BindingExpressionBase parent)
{
    FrameworkPropertyMetadata fwMetaData = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata;
    if (((fwMetaData != null) && !fwMetaData.IsDataBindingAllowed) || dp.ReadOnly)
    {
        throw new ArgumentException(System.Windows.SR.Get(System.Windows.SRID.PropertyNotBindable, new object[] { dp.Name }), "dp");
    }
 ....

26voto

Fredrik Hedblad Points 42772

C'est une limitation de WPF et c'est par la conception. Il est rapporté sur Connectez-vous ici:
OneWayToSource de liaison à partir d'une lecture-seule propriété de dépendance

J'ai fait une solution dynamiquement être en mesure de pousser en lecture seule des propriétés de dépendance à la source appelée PushBinding qui j'ai blogué sur ici. L'exemple ci-dessous n' OneWayToSource des Fixations de la lecture seule du DP ActualWidth et ActualHeight de la Largeur et de la Hauteur de l' DataContext

<TextBlock Name="myTextBlock">
    <pb:PushBindingManager.PushBindings>
        <pb:PushBinding TargetProperty="ActualHeight" Path="Height"/>
        <pb:PushBinding TargetProperty="ActualWidth" Path="Width"/>
    </pb:PushBindingManager.PushBindings>
</TextBlock>

PushBinding fonctionne en utilisant deux Propriétés de Dépendance, de l'Écouteur et d'un Miroir. L'auditeur est tenu OneWay de la TargetProperty et dans l' PropertyChangedCallback il met à jour la propriété Miroir qui est lié à la OneWayToSource de ce qui a été spécifié dans la Liaison.

Projet de démonstration peut être Téléchargée Ici.
Il contient le code source et à court d'exemples d'utilisation, ou visitez mon WPF blog si vous êtes intéressé par les détails de mise en œuvre.

0voto

alex2k8 Points 12225

WPF n'utilisera pas l'outil de définition de propriété CLR, mais semble effectuer une validation bizarre sur cette base.

Peut être dans votre situation cela peut être ok:

     public bool IsModified
    {
        get { return (bool)GetValue(IsModifiedProperty); }
        set { throw new Exception("An attempt ot modify Read-Only property"); }
    }
 

0voto

Mario Points 100

Hmmm... je ne suis pas sûr que je suis d'accord avec l'une de ces solutions. Comment sur la spécification d'une contrainte de rappel dans votre enregistrement de la propriété, qui ignore changement externe? Par exemple, j'avais besoin de mettre en œuvre une Position en lecture seule dépendance de la propriété pour obtenir la position d'un élément multimédia de contrôle à l'intérieur d'un contrôle de l'utilisateur. Voici comment j'ai fait:

    public static readonly DependencyProperty PositionProperty = DependencyProperty.Register("Position", typeof(double), typeof(MediaViewer),
        new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal, OnPositionChanged, OnPositionCoerce));

    private static void OnPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctrl = d as MediaViewer;
    }

    private static object OnPositionCoerce(DependencyObject d, object value)
    {
        var ctrl = d as MediaViewer;
        var position = ctrl.MediaRenderer.Position.TotalSeconds;

        if (ctrl.MediaRenderer.NaturalDuration.HasTimeSpan == false)
            return 0d;
        else
            return Math.Min(position, ctrl.Duration);
    }

    public double Position
    {
        get { return (double)GetValue(PositionProperty); }
        set { SetValue(PositionProperty, value); }
    }

En d'autres termes, tout simplement ignorer le changement et retourner la valeur soutenu par un autre membre qui n'a pas un public de modificateur. - Dans l'exemple ci-dessus, MediaRenderer est en fait privé de contrôle MediaElement.

-2voto

JaredPar Points 333733

Vous êtes en train de faire la liaison dans la mauvaise direction à droite maintenant. OneWayToSource allons essayer de mettre à jour FlagIsModified sur le conteneur à chaque fois que IsModified changements sur le contrôle de la création. Vous voulez le contraire, ce qui est d'avoir IsModified lier à conteneur.FlagIsModified. Pour cela vous devez utiliser le mode de liaison Unidirectionnelle

<controls:FlagThingy IsModified="{Binding FlagIsModified, 
                                          ElementName=container, 
                                          Mode=OneWay}" />

Liste complète des membres de l'énumération: http://msdn.microsoft.com/en-us/library/system.windows.data.bindingmode.aspx

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X