web-dev-qa-db-fra.com

Liaison à la propriété statique

J'ai du mal à lier une propriété de chaîne statique simple à une zone de texte.

Voici la classe avec la propriété static:

public class VersionManager
{
    private static string filterString;

    public static string FilterString
    {
        get { return filterString; }
        set { filterString = value; }
    }
}

Dans mon xaml, je veux juste lier cette propriété statique à une zone de texte:

<TextBox>
    <TextBox.Text>
        <Binding Source="{x:Static local:VersionManager.FilterString}"/>
    </TextBox.Text>
</TextBox>

Tout est compilé, mais au moment de l'exécution, j'obtiens l'exception suivante:

Impossible de convertir la valeur de l'attribut 'Source' en objet de type 'System.Windows.Markup.StaticExtension'. Erreur dans l'objet 'System.Windows.Data.Binding' dans le fichier de balisage 'BurnDisk; composant/selectversionpagefunction.xaml' ligne 57, position 29.

Une idée de ce que je fais mal?

162
Anthony Brien

Si la liaison doit être bidirectionnelle, vous devez fournir un chemin. Il existe un truc pour faire une liaison bidirectionnelle sur une propriété statique, à condition que la classe ne soit pas statique: déclarez une instance fictive de la classe dans les ressources et utilisez-la comme source de la liaison.

<Window.Resources>
    <local:VersionManager x:Key="versionManager"/>
</Window.Resources>
...

<TextBox Text="{Binding Source={StaticResource versionManager}, Path=FilterString}"/>
160
Thomas Levesque

Vous ne pouvez pas vous lier à un statique comme ça. Il n’existe aucun moyen pour l’infrastructure de liaison d’être avertie des mises à jour car il n’ya pas de DependencyObject (ni d’instance d’objet implémentant INotifyPropertyChanged) impliquée.

Si cette valeur ne change pas, abandonnez simplement la liaison et utilisez x:Static directement dans la propriété Text. Définissez app ci-dessous comme emplacement de l'espace de noms (et de l'assembly) de la classe VersionManager.

<TextBox Text="{x:Static app:VersionManager.FilterString}" />

Si la valeur change, je suggérerais de créer un singleton pour contenir la valeur et se lier à celle-ci.

Un exemple du singleton:

public class VersionManager : DependencyObject {
    public static readonly DependencyProperty FilterStringProperty =
        DependencyProperty.Register( "FilterString", typeof( string ),
        typeof( VersionManager ), new UIPropertyMetadata( "no version!" ) );
    public string FilterString {
        get { return (string) GetValue( FilterStringProperty ); }
        set { SetValue( FilterStringProperty, value ); }
    }

    public static VersionManager Instance { get; private set; }

    static VersionManager() {
        Instance = new VersionManager();
    }
}
<TextBox Text="{Binding Source={x:Static local:VersionManager.Instance},
                        Path=FilterString}"/>
99
Adam Sills

Dans .NET 4.5, il est possible de se lier à des propriétés statiques, en savoir plus

Vous pouvez utiliser des propriétés statiques comme source d'une liaison de données. Le moteur de liaison de données reconnaît le moment où la valeur de la propriété change si un événement statique est déclenché. Par exemple, si la classe SomeClass définit une propriété statique appelée MyProperty, SomeClass peut définir un événement statique qui est déclenché lorsque la valeur de MyProperty est modifiée. L'événement statique peut utiliser l'une des signatures suivantes:

public static event EventHandler MyPropertyChanged; 
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged; 

Notez que dans le premier cas, la classe expose un événement statique nommé PropertyNameChanged qui transmet EventArgs au gestionnaire d'événements. Dans le second cas, la classe expose un événement statique nommé StaticPropertyChanged qui transmet PropertyChangedEventArgs au gestionnaire d'événements. Une classe qui implémente la propriété statique peut choisir de générer des notifications de modification de propriété à l'aide de l'une ou l'autre méthode.

38
Jowen

Depuis WPF 4.5, vous pouvez vous lier directement à des propriétés statiques et les mettre à jour automatiquement lorsque votre propriété est modifiée. Vous devez connecter manuellement un événement de modification pour déclencher les mises à jour de la liaison.

public class VersionManager
{
    private static String _filterString;        

    /// <summary>
    /// A static property which you'd like to bind to
    /// </summary>
    public static String FilterString
    {
        get
        {
            return _filterString;
        }

        set
        {
            _filterString = value;

            // Raise a change event
            OnFilterStringChanged(EventArgs.Empty);
        }
    }

    // Declare a static event representing changes to your static property
    public static event EventHandler FilterStringChanged;

    // Raise the change event through this static method
    protected static void OnFilterStringChanged(EventArgs e)
    {
        EventHandler handler = FilterStringChanged;

        if (handler != null)
        {
            handler(null, e);
        }
    }

    static VersionManager()
    {
        // Set up an empty event handler
        FilterStringChanged += (sender, e) => { return; };
    }

}

Vous pouvez maintenant lier votre propriété static comme n'importe quelle autre:

<TextBox Text="{Binding Path=(local:VersionManager.FilterString)}"/>
11
Matt

Vous pouvez utiliser ObjectDataProvider class et sa propriété MethodName. Cela peut ressembler à ceci:

<Window.Resources>
   <ObjectDataProvider x:Key="versionManager" ObjectType="{x:Type VersionManager}" MethodName="get_FilterString"></ObjectDataProvider>
</Window.Resources>

Le fournisseur de données d'objet déclaré peut être utilisé comme ceci:

<TextBox Text="{Binding Source={StaticResource versionManager}}" />
8
GPAshka

Si vous utilisez des ressources locales, vous pouvez vous y reporter comme suit:

<TextBlock Text="{Binding Source={x:Static prop:Resources.PerUnitOfMeasure}}" TextWrapping="Wrap" TextAlignment="Center"/>
7
Edmund Covington

Il pourrait y avoir deux façons/syntaxe de lier une propriété static. Si p est une propriété static de la classe MainWindow, alors binding pour textbox sera :

1.

<TextBox Text="{x:Static local:MainWindow.p}" />

2.

<TextBox Text="{Binding Source={x:Static local:MainWindow.p},Mode=OneTime}" />
6
Kylo Ren

Variante de droite pour .NET 4.5 +

Code C #

public class VersionManager
{
    private static string filterString;

    public static string FilterString
    {
        get => filterString;
        set
        {
            if (filterString == value)
                return;

            filterString = value;

            StaticPropertyChanged?.Invoke(null, FilterStringPropertyEventArgs);
        }
    }

    private static readonly PropertyChangedEventArgs FilterStringPropertyEventArgs = new PropertyChangedEventArgs (nameof(FilterString));
    public static event PropertyChangedEventHandler StaticPropertyChanged;
}

Liaison XAML (attention aux accolades qu’elles sont (), pas {})

<TextBox Text="{Binding Path=(yournamespace:VersionManager.FilterString)}" />
3
Alexei Shcherbakov

Regardez mon projet CalcBinding , qui vous permet d'écrire des expressions complexes dans la valeur de la propriété Path, y compris les propriétés statiques, les propriétés source, Math et autres. Donc, vous pouvez écrire ceci:

<TextBox Text="{c:Binding local:VersionManager.FilterString}"/>

Bonne chance!

2
Alex141

Réponse la plus légère (.net 4.5 et versions ultérieures):

    static public event EventHandler FilterStringChanged;
    static string _filterString;
    static public string FilterString
    {
        get { return _filterString; }
        set
        {
            _filterString= value;
            FilterStringChanged?.Invoke(null, EventArgs.Empty);
        }
    }

et XAML:

    <TextBox Text="{Binding Path=(local:VersionManager.FilterString)}"/>

Ne négligez pas les crochets

0
Sean

Ces réponses sont toutes bonnes si vous voulez suivre de bonnes conventions mais le PO voulait quelque chose simple , ce que je voulais aussi au lieu de traiter avec des modèles de conception d'interface graphique . Si tout ce que vous voulez, c'est insérer une chaîne dans une application graphique de base que vous pouvez mettre à jour de manière ad-hoc sans rien d'extraordinaire, vous pouvez simplement y accéder directement dans votre source C #.

Disons que vous avez une application WPF très basique MainWindow XAML comme celle-ci,

<Window x:Class="MyWPFApp.MainWindow"
            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:local="clr-namespace:MyWPFApp"
            mc:Ignorable="d"
            Title="MainWindow"
            Height="200"
            Width="400"
            Background="White" >
    <Grid>
        <TextBlock x:Name="textBlock"                   
                       Text=".."
                       HorizontalAlignment="Center"
                       VerticalAlignment="Top"
                       FontWeight="Bold"
                       FontFamily="Helvetica"
                       FontSize="16"
                       Foreground="Blue" Margin="0,10,0,0"
             />
        <Button x:Name="Find_Kilroy"
                    Content="Poke Kilroy"
                    Click="Button_Click_Poke_Kilroy"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    FontFamily="Helvetica"
                    FontWeight="Bold"
                    FontSize="14"
                    Width="280"
            />
    </Grid>
</Window>

Cela ressemblera à ceci:

enter image description here

Dans la source de votre MainWindow XAML, vous pourriez avoir quelque chose comme ceci: tout ce que nous faisons pour changer la valeur directement via textBlock.Text _ get/set fonctionnalité:

using System.Windows;

namespace MyWPFApp
{
    public partial class MainWindow : Window
    {
        public MainWindow() { InitializeComponent(); }

        private void Button_Click_Poke_Kilroy(object sender, RoutedEventArgs e)
        {
            textBlock.Text = "              \\|||/\r\n" +
                             "              (o o) \r\n" +
                             "----ooO- (_) -Ooo----";
        }
    }
}

Ensuite, lorsque vous déclenchez cet événement en cliquant sur le bouton, le tour est joué! Kilroy apparaît :)

enter image description here

0