खोज…


वाक्य - विन्यास

  • <TextBlock Text="{Binding Title}"/>

  • <TextBlock Text="{Binding Path=Title}"/>

  • <TextBlock> <TextBlock.Text> <Binding Path="Title"/> </TextBlock.Text> </TextBlock>

टिप्पणियों

ये सभी टैग एक ही परिणाम उत्पन्न करते हैं।

पाठ संपत्ति के लिए बाध्यकारी

रनटाइम में UI सामग्री को बदलने के लिए, आप Binding उपयोग कर सकते हैं। जब बाइंड की गई संपत्ति कोड से बदल दी जाती है, तो उसे UI पर प्रदर्शित किया जाएगा।

<TextBlock Text="{Binding Title}"/>

परिवर्तनों के बारे में UI को सूचित करने के लिए, संपत्ति को INotifyPropertyChanged इंटरफ़ेस से PropertyChanged घटना को उठाना चाहिए या आप INotifyPropertyChanged Dependency Property उपयोग कर सकते हैं।

यदि संपत्ति "शीर्षक" xaml.cs फ़ाइल में या XAML से Datacontext वर्ग में है तो बाइंडिंग काम कर रही XAML

Datacontext को XAML में सीधे सेट किया जा सकता है

<Window x:Class="Application.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Application">
<Window.DataContext>
   <local:DataContextClass/>
</Window.DataContext>

स्ट्रिंग बाइंडिंग स्वरूपण

किसी चीज को बांधते समय, उदाहरण के लिए एक तारीख जिसे आप कोड में उसके साथ खिलवाड़ किए बिना एक विशिष्ट प्रारूप में दिखाना चाहते हैं।

ऐसा करने के लिए हम StringFormat संपत्ति का उपयोग कर सकते हैं।

यहाँ कुछ उदाहरण हैं:

Text="{Binding Path=ReleaseDate, StringFormat=dddd dd MMMM yyyy}"

यह मेरी तारीख को निम्न स्वरूपित करता है:

16 अगस्त 2016 को मंगलवार है


यहाँ तापमान के लिए एक और उदाहरण है।

Text="{Binding Path=Temp, StringFormat={}{0}°C}"

यह प्रारूप:

25 डिग्री सेल्सियस

INotifyPropertyChanged की मूल बातें

यदि आप केवल स्थैतिक वस्तुओं को प्रदर्शित करने की इच्छा नहीं रखते हैं, लेकिन आपके यूआई का संबंध सहसंबंधी वस्तुओं में परिवर्तन के लिए है, तो आपको INotifyPropertyChanged इंटरफ़ेस की मूल बातें समझने की आवश्यकता है।

यह मानते हुए कि हमारे पास अपना MainWindow परिभाषित है

<Window x:Class="Application.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:vm="clr-namespace:Application.ViewModels>
    <Window.DataContext>
       <vm:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <TextBlock Text={Binding Path=ApplicationStateText}" />
    </Grid>
</Window>

हमारे Viewmodel- क्लास MainWindowViewModel रूप में परिभाषित किया गया है

namespace Application.ViewModels
{
    public class MainWindowViewModel
    {
        private string _applicationStateText;

        public string ApplicationStateText
        {
            get { return _applicationStateText; }
            set { _applicationStateText = value; }
        }
        public MainWindowViewModel() 
        { 
            ApplicationStateText = "Hello World!";
        }

    }
}

हमारे एप्लिकेशन का टेक्स्टब्लॉक अपने बाइंडिंग के कारण टेक्स्ट हैलो वर्ल्ड प्रदर्शित करेगा। यदि रनटाइम के दौरान हमारे ApplicationStateText में बदलाव होता है, तो हमारे UI को इस तरह के बदलाव के बारे में सूचित नहीं किया जाएगा।
इसे लागू करने के लिए, हमारे INotifyPropertyChanged स्रोत, इस मामले में हमारे MainWindowViewModel , को इंटरफ़ेस INotifyPropertyChanged को लागू करने की आवश्यकता है। यह हमारी Bindings का कारण PropertyChangedEvent सदस्यता लेने में सक्षम होगा।
जब भी हम अपनी ApplicationStateText संपत्ति को बदलते हैं, तो हमें PropertyChangedEventHandler को आमंत्रित करना होगा:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Application.ViewModels
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged( [CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private string _applicationStateText;

        public string ApplicationStateText
        {
            get { return _applicationStateText; }
            set
            {
                if (_applicationStateText != value)
                {
                    _applicationStateText = value;
                    NotifyPropertyChanged();
                }
            }
        }
        public MainWindowViewModel()
        {
            ApplicationStateText = "Hello World!";
        }
    }
}

और सुनिश्चित करें, कि TextBlock.Text की हमारी Binding वास्तव में एक PropertyChangedEvent को सुनता है:

<Window x:Class="Application.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:vm="clr-namespace:Application.ViewModels">
    <Window.DataContext>
       <vm:MainWindowViewModel/>
    </Window.DataContext>
    <Grid>
        <TextBlock Text={Binding Path=ApplicationStateText, UpdateSourceTrigger=PropertyChanged }" />
    </Grid>
</Window>

INotifyPropertyChanged और INotifyCollectionChanged के साथ ऑब्जेक्ट्स के एक संग्रह को बाइंड करना

मान लेते हैं कि आपके पास एक ListView जो Users प्रॉपर्टी ऑफ़ ViewModel तहत सूचीबद्ध प्रत्येक User ऑब्जेक्ट को प्रदर्शित करने वाला है, जहाँ उपयोगकर्ता ऑब्जेक्ट के गुण प्रोग्रामेटिक रूप से अपडेट किए जा सकते हैं।

<ListView ItemsSource="{Binding Path=Users}" >
    <ListView.ItemTemplate>
        <DataTemplate DataType="{x:Type models:User}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Margin="5,3,15,3" 
                         Text="{Binding Id, Mode=OneWay}" />
                <TextBox Width="200"
                         Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Delay=450}"/>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

User ऑब्जेक्ट के लिए INotifyPropertyChanged beeing को सही तरीके से लागू करने के बावजूद

public class User : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private int _id;
    private string _name;

    public int Id
    {
        get { return _id; }
        private set
        {
            if (_id == value) return;
            _id = value;
            NotifyPropertyChanged();
        }
    }
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value) return;
            _name = value;
            NotifyPropertyChanged();
        }
    }

    public User(int id, string name)
    {
        Id = id;
        Name = name;
    }

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

और आपके ViewModel ऑब्जेक्ट के लिए

public sealed class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private List<User> _users;
    public List<User> Users
    {
        get { return _users; }
        set
        {
            if (_users == value) return;
            _users = value;
            NotifyPropertyChanged();
        }
    }
    public MainWindowViewModel()
    {
        Users = new List<User> {new User(1, "John Doe"), new User(2, "Jane Doe"), new User(3, "Foo Bar")};
    }

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

यदि उपयोगकर्ता के लिए प्रोग्रामेटिक रूप से परिवर्तन किया जाता है, तो आपका UI अपडेट नहीं होगा।

यह केवल इसलिए है क्योंकि आपने केवल सूची के इंस्टेंस पर INotifyPropertyChanged सेट किया है। यदि आप किसी तत्व की एक प्रॉपर्टी आपके UI को अपडेट करेंगे, तो ही आप पूरी तरह से सूची को फिर से इंस्टेंट करेंगे।

// DO NOT DO THIS
User[] userCache = Users.ToArray();
Users = new List<User>(userCache);

यह हालांकि प्रदर्शन के लिए बहुत थकाऊ और अविश्वसनीय रूप से खराब है।
यदि आपके पास उपयोगकर्ता की आईडी और नाम दोनों को दर्शाने वाले 100'000 तत्वों की सूची है, तो प्रत्येक जगह 200'000 DataBindings होंगी, जिनमें से प्रत्येक को फिर से बनाना होगा। जब भी किसी चीज़ में बदलाव किया जाता है, तो उपयोगकर्ता के लिए यह उल्लेखनीय है।

इस समस्या को आंशिक रूप से हल करने के लिए, आप List<T> बजाय System.ComponentModel.ObservableCollection<T> उपयोग कर सकते हैं:

private ObservableCollection<User> _users;
public ObservableCollection<User> Users
{
    get { return _users; }
    set
    {
        if (_users == value) return;
        _users = value;
        NotifyPropertyChanged();
    }
}

ObservableCollection हमें CollectionChanged इवेंट और INotifyPropertyChanged को लागू करता है। MSDN के अनुसार घटना बढ़ेगी, "[..] जब कोई आइटम जोड़ा जाता है , हटाया जाता है , बदला जाता है , स्थानांतरित किया जाता है , या पूरी सूची ताज़ा होती है "।
हालाँकि आपको जल्दी से यह पता चल जाएगा कि .NET 4.5.2 और पूर्व के साथ, ObservableCollection एक कलेक्शन चेंज किए गए इवेंट को नहीं बढ़ाएगा अगर यहाँ पर कलेक्शन चेंजेज में किसी एलिमेंट की प्रॉपर्टी पर चर्चा की जाए।

के बाद इस समाधान हम केवल लागू कर सकते हैं हमारे अपने TrulyObservableCollection<T> बिना INotifyPropertyChanged के लिए बाधा T सब कुछ हम जरूरत होने और मौसम को उजागर T औजार INotifyPropertyChanged या नहीं:

/*
 * Original Class by Simon @StackOverflow http://stackoverflow.com/a/5256827/3766034
 * Removal of the INPC-Constraint by Jirajha @StackOverflow 
 * according to to suggestion of nikeee @StackOverflow http://stackoverflow.com/a/10718451/3766034
 */
public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
{
    private readonly bool _inpcHookup;
    public bool NotifyPropertyChangedHookup => _inpcHookup;

    public TrulyObservableCollection()
    {
        CollectionChanged += TrulyObservableCollectionChanged;
        _inpcHookup = typeof(INotifyPropertyChanged).GetTypeInfo().IsAssignableFrom(typeof(T));
    }
    public TrulyObservableCollection(IEnumerable<T> items) : this()
    {
        foreach (var item in items)
        {
            this.Add(item);
        }
    }

    private void TrulyObservableCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (NotifyPropertyChangedHookup && e.NewItems != null && e.NewItems.Count > 0)
        {
            foreach (INotifyPropertyChanged item in e.NewItems)
            {
                item.PropertyChanged += ItemPropertyChanged;
            }
        }
        if (NotifyPropertyChangedHookup && e.OldItems != null && e.OldItems.Count > 0)
        {
            foreach (INotifyPropertyChanged item in e.OldItems)
            {
                item.PropertyChanged -= ItemPropertyChanged;
            }
        }
    }
    private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
        OnCollectionChanged(args);
    }
}

और हमारे ViewModel में हमारे संपत्ति Users को TrulyObservableCollection<User> रूप में परिभाषित करते हैं

private TrulyObservableCollection<string> _users;
public TrulyObservableCollection<string> Users
{
    get { return _users; }
    set
    {
        if (_users == value) return;
        _users = value;
        NotifyPropertyChanged();
    }
}

हमारे यूआई को अब हर एक Binding को फिर से बनाने की आवश्यकता के बिना संग्रह परिवर्तन के भीतर एक तत्व की INPC- संपत्ति के बारे में एक बार सूचित किया जाएगा।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow