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?
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}"/>
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}"/>
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.
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)}"/>
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}}" />
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"/>
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}" />
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)}" />
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!
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
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:
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 :)