स्थिर संपत्ति से बांधना


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>

सब कुछ संकलित है, लेकिन रन टाइम पर, मुझे निम्नलिखित अपवाद मिलते हैं:

प्रकार 'System.Windows.Markup.StaticExtension' के ऑब्जेक्ट के लिए विशेषता 'स्रोत' में मान को परिवर्तित नहीं कर सकता। ऑब्जेक्ट 'System.Windows.Data.Binding' पर मार्कअप फ़ाइल 'BurnDisk; घटक / selectversionpagefunction.xaml' लाइन 57 स्थिति 29 में त्रुटि।

किसी भी विचार मैं गलत क्या कर रहा हूँ?

जवाबों:


168

यदि बंधन को दो-तरफ़ा होने की आवश्यकता है, तो आपको एक पथ की आपूर्ति करनी होगी। स्थैतिक संपत्ति पर दो-तरफ़ा बाइंडिंग करने की एक चाल है, बशर्ते वर्ग स्थिर न हो: संसाधनों में वर्ग का एक डमी उदाहरण घोषित करें, और इसे बाइंडिंग के स्रोत के रूप में उपयोग करें।

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

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

यह उत्तर मेरे मामले के लिए अधिक उपयुक्त है क्योंकि मैं अपने स्रोत वर्ग के लिए DependencyObject का परिचय नहीं देना चाहता। पारितोषिक के लिए धन्यवाद!
एंथनी ब्रीन

6
ध्यान दें कि आपके टेक्स्ट बॉक्स को स्टैटिक प्रॉपर्टी में वैल्यू को वापस पुश करने में सक्षम करेगा, लेकिन सोर्स वैल्यू में बदलाव होने पर टेक्स्ट बॉक्स को अपडेट नहीं करेगा।
एडम

1
यह ठीक है, मुझे बस इस मामले में टेक्स्टबॉक्स से सोर्स तक बाइंडिंग की आवश्यकता थी। यदि मैं अन्य तरीके से काम करने के लिए बाध्यकारी चाहता हूं, तो मुझे इनमें से किसी एक विधि की आवश्यकता के बारे में पता है: INotifyPropertyChanged, <PropertyName> परिवर्तित घटना या निर्भरता गुण।
एंथनी ब्रायन

1
ध्यान दें: यह समाधान MVVM स्थिति में काम नहीं करेगा, क्योंकि आपके पास आमतौर पर उन वस्तुओं के प्रकार तक पहुंच नहीं होती है जिन्हें आप बांध रहे हैं।
एंटनी वुड्स

@thomas मुझे मेरे लिए काम करना अच्छा लगेगा लेकिन मैं ऐसा नहीं कर सकती। मैंने अपनी दुविधा को यहां एक और प्रश्न के रूप में पोस्ट किया: stackoverflow.com/questions/34656670/…
एंड्रयू सिम्पसन

107

आप इस तरह किसी स्थैतिक को नहीं बांध सकते। बाइंडिंग इन्फ्रास्ट्रक्चर के लिए अपडेट का नोटिफिकेशन प्राप्त करने का कोई तरीका नहीं है क्योंकि इसमें कोई DependencyObject(या ऑब्जेक्ट इंस्टेंस जो लागू हो INotifyPropertyChanged) शामिल नहीं है।

यदि वह मान नहीं बदलता है, तो बस बाइंडिंग को खोदें और x:Staticसीधे Textसंपत्ति के अंदर उपयोग करें । appवर्जनमैन क्लास के नाम स्थान (और असेंबली) के स्थान को नीचे परिभाषित करें ।

<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 पाठ = {बाइंडिंग सोर्स = {x: स्टेटिक sys: Int32.MaxValue}, मोड = OneWide} "/> है कि काम कर रहा है क्योंकि यह एक तरीका है?
एंथनी ब्रून

2
हाँ, किसी भी दो तरह से बाइंडिंग के लिए बाइंडिंग पर एक पथ गुण मान की आवश्यकता होती है। स्रोत को एक ऑब्जेक्ट होना चाहिए जिसमें पथ द्वारा निर्दिष्ट संपत्ति शामिल है। OneWay को निर्दिष्ट करने से उस प्रतिबंध को हटा दिया जाता है।
एडम

इसके अलावा, देर से अपडेट के लिए खेद है, लेकिन मैंने उपरोक्त उत्तर को एक नमूने के साथ अपडेट किया है।
एडम

क्या स्टैटिक स्ट्रिंग को बांधने का कोई तरीका है। मेरे पास एक म्यूटिंडिंग है और एक इनपुट एक निश्चित स्ट्रिंग है।
नितिन चौधरी

39

.NET 4.5 में, स्थैतिक गुणों से बंधना संभव है, अधिक पढ़ें

आप डेटा बाइंडिंग के स्रोत के रूप में स्थैतिक गुणों का उपयोग कर सकते हैं। डेटा बाइंडिंग इंजन पहचानता है कि जब स्थैतिक घटना को उठाया जाता है तो संपत्ति का मूल्य बदल जाता है। उदाहरण के लिए, यदि कोई वर्ग MyClperty नामक स्थैतिक गुण को परिभाषित करता है, तो SomeClass एक स्थैतिक घटना को परिभाषित कर सकता है जिसे MyProperty के मान में परिवर्तन किया जाता है। स्थैतिक घटना निम्नलिखित हस्ताक्षर में से किसी एक का उपयोग कर सकती है:

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

ध्यान दें कि पहले मामले में, क्लास PropertyNameChanged नामक एक स्थैतिक घटना को उजागर करता है जो EventArgs को इवेंट हैंडलर के पास देता है। दूसरे मामले में, क्लास StaticPropertyChanged नामक एक स्थैतिक घटना को उजागर करता है जो प्रॉपर्टीचैन्डएवेंटएवार्स को इवेंट हैंडलर को देता है। एक वर्ग जो स्थैतिक संपत्ति को लागू करता है, वह किसी भी विधि का उपयोग करके संपत्ति-परिवर्तन की सूचनाएं चुन सकता है।


यहाँ लिंक के मामले में किसी को और अधिक पढ़ना चाहता है। Microsoft ने इसे नीचे ले लिया, लेकिन यह यहाँ वेब संग्रह पर है। 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

11

किसी staticसंपत्ति को बांधने के दो तरीके / वाक्यविन्यास हो सकते हैं। यदि pstatic वर्ग में एक गुण है MainWindow, तो निम्न के bindingलिए 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 + के लिए राइट वेरिएंट

सी # कोड

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 को ठीक से कॉल करने के लिए अपने कोड में थोड़ा बदलाव करें।
मार्क ए। डोनोहे

कई अलग-अलग समाधानों की कोशिश की और यह काम किया। PropertyChangedEventHandler मेरे लिए क्या काम करता है। चीयर्स।
ममगेरेज

2

मेरी परियोजना CalcBinding को देखें , जो आपको स्थैतिक संपत्ति, जटिल गुण, गणित और अन्य सहित पथ संपत्ति मूल्य में जटिल अभिव्यक्ति लिखने के लिए प्रदान करता है। तो, आप इसे लिख सकते हैं:

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

सौभाग्य!


0

ये उत्तर सभी अच्छे हैं यदि आप अच्छे सम्मेलनों का पालन करना चाहते हैं, लेकिन ओपी कुछ सरल चाहता था , जो कि मैं चाहता हूं कि जीयूआई डिजाइन पैटर्न से निपटने के बजाय मैं भी चाहता हूं। यदि आप सभी करना चाहते हैं, तो आपके पास एक बुनियादी जीयूआई ऐप में एक स्ट्रिंग है जिसे आप बिना किसी फैंसी के तदर्थ अपडेट कर सकते हैं, तो आप इसे सीधे अपने सी # स्रोत में एक्सेस कर सकते हैं।

मान लीजिए कि आपको वास्तव में मूल 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.Textकी get/ 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----";
        }
    }
}

फिर जब आप बटन, वॉयला पर क्लिक करके उस घटना को ट्रिगर करते हैं! Kilroy प्रकट होता है :)

यहां छवि विवरण दर्ज करें


0

एक अन्य समाधान एक सामान्य वर्ग बनाना है जो प्रॉपर्टीचेंजर को इस तरह लागू करता है

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

और यदि आवश्यक हो तो यहां प्रॉपर्टीचेंजर कार्यान्वयन है

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

कोष्ठक की उपेक्षा न करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.