静的プロパティへのバインド


168

単純な静的文字列プロパティをTextBoxにバインドするのに苦労しています。

これが静的プロパティを持つクラスです:

public class VersionManager
{
    private static string filterString;

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

私のxamlでは、この静的プロパティをTextBoxにバインドしたいだけです。

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

すべてがコンパイルされますが、実行時に次の例外が発生します。

属性「Source」の値をタイプ「System.Windows.Markup.StaticExtension」のオブジェクトに変換できません。マークアップファイル「BurnDisk; component / selectversionpagefunction.xaml」のオブジェクト「System.Windows.Data.Binding」でエラーが発生しました。行57の位置29。

私が間違っていることは何か考えていますか?

回答:


168

バインディングを双方向にする必要がある場合は、パスを指定する必要があります。クラスが静的でない場合、静的プロパティで双方向バインディングを行うトリックがあります。リソースでクラスのダミーインスタンスを宣言し、それをバインディングのソースとして使用します。

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

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

私のソースクラスにDependencyObjectを導入したくないので、この答えは私の場合により適切です。先端をありがとう!
Anthony Brien

6
テキストボックスで値を静的プロパティにプッシュできるようになりますが、ソース値が変更されてもテキストボックスは更新されません。
Adam Sills、

1
この場合、テキストボックスからソースへのバインディングが必要でした。バインディングを他の方法で機能させたい場合は、INotifyPropertyChanged、<PropertyName> Changedイベント、または依存関係プロパティのいずれかのメソッドが必要であることを知っています。
Anthony Brien

1
注:通常、バインドしているオブジェクトのタイプにアクセスできないため、このソリューションはMVVMの状況では機能しません。
Antony Woods

@thomasこれをうまく動かせるようにしたいのですが、うまくいきません。私はジレンマを別の質問としてここに投稿しました:stackoverflow.com/questions/34656670/…–
Andrew Simpson

107

そのようなstaticにバインドすることはできません。バインディングインフラストラクチャがアップデートを通知する方法はありませんDependencyObject(またはを実装するオブジェクトインスタンスINotifyPropertyChanged)が関与していないためです。

その値が変更されない場合は、バインディングを破棄してx:StaticTextプロパティ内で直接使用します。app次に、VersionManagerクラスの名前空間(およびアセンブリ)の場所を定義します。

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

値が変化する場合は、値を格納してそれにバインドするシングルトンを作成することをお勧めします。

シングルトンの例:

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}"/>

5
本当に?私のサンプルと非常に似ている静的Int32.MaxValueにバインドすることができました:<TextBox Text = {Binding Source = {x:Static sys:Int32.MaxValue}、Mode = OneWay} "/>です片道だから働く?
アンソニー・ブリエン

2
ええ、双方向のバインディングには、バインディングのPathプロパティ値が必要です。ソースは、Pathで指定されたプロパティを含むオブジェクトである必要があります。OneWayを指定すると、その制限がなくなります。
Adam Sills、

また、更新が遅くなってすみませんが、上記の回答をサンプルで更新しました。
Adam Sills、

静的文字列をバインドする方法はありますか?マルチバインディングがあり、入力の1つは固定文字列です。
Nitin Chaudhari、2010

39

.NET 4.5では、静的プロパティにバインドできます。詳細はこちら

静的プロパティをデータバインディングのソースとして使用できます。データバインディングエンジンは、静的イベントが発生した場合にプロパティの値がいつ変化するかを認識します。たとえば、クラスSomeClassがMyPropertyという静的プロパティを定義している場合、SomeClassはMyPropertyの値が変化したときに発生する静的イベントを定義できます。静的イベントは、次のシグネチャのいずれかを使用できます。

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

最初のケースでは、クラスが、EventArgsをイベントハンドラーに渡すPropertyNameChangedという名前の静的イベントを公開していることに注意してください。2番目のケースでは、クラスは、PropertyChangedEventArgsをイベントハンドラーに渡すStaticPropertyChangedという名前の静的イベントを公開します。静的プロパティを実装するクラスは、いずれかの方法を使用してプロパティ変更通知を生成することを選択できます。


誰かがもっと読みたくなった場合のためにここにリンクがあります。マイクロソフトはそれを取り下げましたが、それはここのウェブアーカイブにあります。 web.archive.org/web/20131129053934/http://msdn.microsoft.com/...
C. Tewalt

この回答は私を正しい方向に導きましたが、例がなくても詳細を理解するにはまだ時間がかかりました。私は書いている例を元のコードに基づきます。
マット

13

WPF 4.5以降では、静的プロパティに直接バインドし、プロパティが変更されたときにバインディングを自動的に更新することができます。バインディング更新をトリガーするには、変更イベントを手動で関連付ける必要があります。

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; };
    }

}

これで、他と同じように静的プロパティをバインドできます。

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

1
VersionManagerクラスには、静的することができ、すべてがまだ動作します。パス定義の中かっこに注意してくださいPath=(local:VersionManager.FilterString)。それらが実際に必要とされる理由を誰かが知っていますか?
chviLadislav

2
プロパティは静的であるため、パス定義で中かっこが必要です。ここを
chviLadislav '26

11

staticプロパティをバインドするには、2つの方法/構文があります。pstaticclassのプロパティの場合MainWindowbindingfor textboxは次のようになります。

1。

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

2。

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

9

ObjectDataProviderクラスとそのMethodNameプロパティを使用できます。次のようになります。

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

宣言されたオブジェクトデータプロバイダーは次のように使用できます。

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

8

ローカルリソースを使用している場合は、以下のように参照できます。

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

3

.NET 4.5以降の正しいバリアント

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;
}

XAMLバインディング(中かっこは{}ではなく()であることに注意)

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

EventHandlerを適切に呼び出すようにコードを少し変更しました。
Mark A. Donohoe

多くの異なるソリューションを試してみましたが、これはうまくいきました。PropertyChangedEventHandlerは私にとってうまくいきました。乾杯。
Mgamerz

2

私のプロジェクトCalcBindingを見てください。これは、静的プロパティ、ソースプロパティ、Mathなどを含む、Pathプロパティ値での複雑な式の記述を提供します。だから、これを書くことができます:

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

幸運を!


0

これらの答えは、適切な規則に従う必要がある場合はすべて適切ですが、OPはGUIデザインパターンを処理するのではなく、私が望んでいる単純なものを望んでいました。基本的なGUIアプリに文字列を追加するだけの場合は、特別なことを行わずにアドホックに更新できます。C#ソースから直接アクセスできます。

このような非常に基本的なWPFアプリMainWindow XAMLがあるとします。

<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>

これは次のようになります。

ここに画像の説明を入力してください

MainWindow XAMLのソースでは、次のようにして、textBlock.Textget/ set機能を介して値を直接変更するために行うすべてのことを行うことができます。

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----";
        }
    }
}

次に、ボタンをクリックしてクリックイベントをトリガーすると、出来上がりです。キルロイが登場:)

ここに画像の説明を入力してください


0

別の解決策は、このようなPropertyChangerを実装する通常のクラスを作成することです

public class ViewProps : PropertyChanger
{
    private string _MyValue = string.Empty;
    public string MyValue
    {
        get { 
            return _MyValue
        }
        set
        {
            if (_MyValue == value)
            {
                return;
            }
            SetProperty(ref _MyValue, value);
        }
    }
}

次に、クラスの静的インスタンスを作成しない場所に作成します

public class MyClass
{
    private static ViewProps _ViewProps = null;
    public static ViewProps ViewProps
    {
        get
        {
            if (_ViewProps == null)
            {
                _ViewProps = new ViewProps();
            }
            return _ViewProps;
        }
    }
}

そして今、それを静的プロパティとして使用します

<TextBlock  Text="{x:Bind local:MyClass.ViewProps.MyValue, Mode=OneWay}"  />

そして必要に応じてここにPropertyChanger実装があります

public abstract class PropertyChanger : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(storage, value)) return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

-1

最も無駄のない答え(.net 4.5以降):

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

およびXAML:

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

括弧を無視しないでください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.