कोड-पीछे में परिभाषित वस्तुओं को बांधना


88

मेरे पास कुछ ऑब्जेक्ट है जो कोड में तुरंत दिया गया है, उदाहरण के लिए, XAML को window.xaml और window.xaml.cs के भीतर कहा जाता है

protected Dictionary<string, myClass> myDictionary;

उदाहरण के लिए, केवल XAML मार्कअप का उपयोग करके मैं इस ऑब्जेक्ट को कैसे बांध सकता हूं?

अपडेट करें:

(यह वास्तव में मेरे परीक्षण कोड में है):

<Window x:Class="QuizBee.Host.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding windowname}" Height="300" Width="300"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
    </Grid>
</Window>

और कोडबाइंड में

public partial class Window1 : Window
{
    public const string windowname = "ABCDEFG";

    public Window1()
    {
        InitializeComponent();
    }
}

मान लीजिए कि शीर्षक "ABCDEFG" सही होना चाहिए? लेकिन यह कुछ भी नहीं दिखा समाप्त होता है।


1
अजीब तरह से पर्याप्त है, अगर मैं खिड़की के संपत्ति असाइनमेंट के क्रम को बदल देता हूं, तो यह काम नहीं करता है। अगर मैं "DataContext" संपत्ति के बाद "शीर्षक" संपत्ति सेट करता हूं, तो बाध्यकारी नहीं होता है। क्या कोई इसे समझा सकता है? <Window x: Class = " INotifyPropertyTest.MainWindow " xmlns = " schemas.microsoft.com/winfx/2006/xaml/pretation " xmlns: x = " schemas.microsoft.com/winfx/2006/xaml " xmlns: local = " clr-namespace: INotifyPropertyTest "Height =" 350 "Width =" 525 "DataContext =" {B बंधन RelativeSource = {RelativeSource self}} "शीर्षक =" "{बंधन विंडोनाम">>
रमेश

जवाबों:


109

आप अपने नियंत्रण, प्रपत्र आदि के लिए DataContext सेट कर सकते हैं जैसे:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

स्पष्टीकरण :

ऊपर दिए गए मान पर सेट किया जा रहा डेटा संदर्भ जो भी तत्व "पीछे" कोड का मालिक होना चाहिए - तो एक विंडो के लिए, आपको इसे विंडो घोषणा में सेट करना चाहिए।

मेरे पास इस कोड के साथ काम करने का आपका उदाहरण है:

<Window x:Class="MyClass"
  Title="{Binding windowname}"
  DataContext="{Binding RelativeSource={RelativeSource Self}}"
  Height="470" Width="626">

इस स्तर पर सेट किया गया DataContext विंडो में किसी भी तत्व द्वारा विरासत में मिला है (जब तक कि आप स्पष्ट रूप से इसे किसी चाइल्ड एलिमेंट के लिए नहीं बदलते हैं), इसलिए विंडो के लिए DataContext सेट करने के बाद आपको किसी भी नियंत्रण से गुण कोड करने के लिए सीधे बाइंड करने में सक्षम होना चाहिए खिड़की पर।


1
यहां "सेल्फ" का मतलब है, पूरे विंडो क्लास के बजाय कंट्रोल?
xandy

पर्याप्त अजीब है, निम्नलिखित कोड मेरे पास है और यह अपेक्षा के अनुरूप काम नहीं करता है: सार्वजनिक आंशिक वर्ग Window1: विंडो {सार्वजनिक कॉन्स्टेंस स्ट्रिंग विंडाउन = "ABCDEFG"; सार्वजनिक Window1 () {InitializeComponent (); }} <विंडो x: क्लास = "QuizBee.Host.Window1" xmlns = " schemas.microsoft.com/winfx/2006/xaml/pretation " xmlns: x = " schemas.microsoft.com/winfx/2006/xaml " शीर्षक = "{बाइंडिंग विंडोबैम}" हाइट = "300" चौड़ाई = "300" डाटा कॉन्टेक्स्ट = "{बाइंडिंग रिलेटिवसोर्स = {रिलेटिवसोर्स सेल्फ}}"> </ Window>
xandy

9
ओह, यह अब ठीक है, मैंने शुद्ध सार्वजनिक चर के बजाय संपत्ति होने के लिए विंडबना को बदल दिया और यह अब प्रदर्शित हो सकता है! धन्यवाद!
xandy

1
मैं कल्पना नहीं कर सकता कि यह केवल डिफ़ॉल्ट रूप से सेट क्यों नहीं है।
ओकोनोमियाकी 3000

122

ऐसा करने का एक बहुत आसान तरीका है। आप अपनी विंडो या UserControl को नाम निर्दिष्ट कर सकते हैं, और उसके बाद ElementName द्वारा बाइंड कर सकते हैं।

Window1.xaml

<Window x:Class="QuizBee.Host.Window1"
        x:Name="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ListView ItemsSource="{Binding ElementName=Window1, Path=myDictionary}" />
</Window>

Window1.xaml.cs

public partial class Window1:Window
{
    // the property must be public, and it must have a getter & setter
    public Dictionary<string, myClass> myDictionary { get; set; }

    public Window1()
    {
        // define the dictionary items in the constructor
        // do the defining BEFORE the InitializeComponent();

        myDictionary = new Dictionary<string, myClass>()
        {
            {"item 1", new myClass(1)},
            {"item 2", new myClass(2)},
            {"item 3", new myClass(3)},
            {"item 4", new myClass(4)},
            {"item 5", new myClass(5)},
        }; 

        InitializeComponent();
    }
}

3
मुझे x बदलना पड़ा: नाम (संकलक त्रुटि CS0542)। फिर उसके अनुसार ElementName को बदलने की आवश्यकता है।
जैक मिलर

25

जबकि गाइ का उत्तर सही है (और संभवत: 10 में से 9 मामलों में फिट बैठता है), यह ध्यान देने योग्य है कि यदि आप ऐसा नियंत्रण से करने का प्रयास कर रहे हैं जो पहले से ही अपने DataContext को स्टैक के आगे सेट करता है, तो जब आप Dataonontext सेट करते हैं तो आप इसे रीसेट कर देंगे। वापस अपने आप में:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

यह निश्चित रूप से आपके मौजूदा बाइंडिंग को तोड़ देगा।

यदि यह मामला है, तो आपको अपने माता-पिता के बजाय, जिस नियंत्रण को बांधने की कोशिश कर रहे हैं, उस पर RelativeSource सेट करना चाहिए।

UserControl के गुणों के लिए बाध्य करने के लिए अर्थात:

Binding Path=PropertyName, 
        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}

यह देखते हुए कि वर्तमान में डेटा बाइंडिंग के साथ क्या हो रहा है, यह देखना मुश्किल है, यह ध्यान में रखने योग्य है, भले ही आपको वह सेटिंग मिल जाए RelativeSource={RelativeSource Self} वर्तमान में काम करती है :)


1
सिल्वरलाइट 4 फाइंडनएस्टर का समर्थन नहीं करता है। हालाँकि, आपको इसे इस तरह से करने की आवश्यकता है कि आप इस साइट पर वर्णित फाइंडनॉसर को लागू कर सकें। http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/
ShawnFeatherly

7

बस थोड़ा और स्पष्टीकरण: 'गेट' के बिना एक संपत्ति, 'सेट' बाध्य नहीं हो पाएगी

मैं मामले का सामना करने वाले के मामले की तरह ही कर रहा हूं। और बाइंड को ठीक से काम करने के लिए मेरे पास निम्न चीजें होनी चाहिए:

//(1) Declare a property with 'get','set' in code behind
public partial class my_class:Window {
  public String My_Property { get; set; }
  ...

//(2) Initialise the property in constructor of code behind
public partial class my_class:Window {
  ...
  public my_class() {
     My_Property = "my-string-value";
     InitializeComponent();
  }

//(3) Set data context in window xaml and specify a binding
<Window ...
DataContext="{Binding RelativeSource={RelativeSource Self}}">
  <TextBlock Text="{Binding My_Property}"/>
</Window>

9
आपके पास 'गेट' और 'सेट' के बिना कितनी संपत्ति हो सकती है? यह एक क्षेत्र नहीं होगा और एक संपत्ति नहीं होगी?
kjbartel

1

एक कनवर्टर परिभाषित करें:

public class RowIndexConverter : IValueConverter
{
    public object Convert( object value, Type targetType,
                           object parameter, CultureInfo culture )
    {
        var row = (IDictionary<string, object>) value;
        var key = (string) parameter;
        return row.Keys.Contains( key ) ? row[ key ] : null;
    }

    public object ConvertBack( object value, Type targetType,
                               object parameter, CultureInfo culture )
    {
        throw new NotImplementedException( );
    }
}

एक शब्दकोश की एक कस्टम परिभाषा के लिए बाध्य करें। बहुत सारे ओवरराइड्स हैं जिन्हें मैंने छोड़ दिया है, लेकिन इंडेक्स महत्वपूर्ण है, क्योंकि यह प्रॉपर्टी बदली हुई घटना का उत्सर्जन करता है जब मूल्य बदल जाता है। बंधन को लक्षित करने के लिए स्रोत की आवश्यकता होती है।

public class BindableRow : INotifyPropertyChanged, IDictionary<string, object>
{
    private Dictionary<string, object> _data = new Dictionary<string, object>( );

    public object Dummy   // Provides a dummy property for the column to bind to
    {
        get
        {
            return this;
        }
        set
        {
            var o = value;
        }
    }


    public object this[ string index ]
    {
        get
        {
            return _data[ index ];
        }
        set
        {
            _data[ index ] = value;
            InvokePropertyChanged( new PropertyChangedEventArgs( "Dummy" ) ); // Trigger update
        }
    }


}

अपने .xaml फ़ाइल में इस कनवर्टर का उपयोग करें। पहले इसे देखें:

<UserControl.Resources>
    <ViewModelHelpers:RowIndexConverter x:Key="RowIndexConverter"/>
</UserControl.Resources>

फिर, उदाहरण के लिए, यदि आपके शब्दकोश में एक प्रविष्टि है जहां कुंजी "नाम" है, तो इसे बांधने के लिए: उपयोग करें

<TextBlock  Text="{Binding Dummy, Converter={StaticResource RowIndexConverter}, ConverterParameter=Name}">

1

अपनी संपत्ति को "डिपेंडेंसीप्रोपरि" "विंडाउन" बनाएं और शेष को समान रखें।


0

पीछे अपने कोड में, शब्दकोश में विंडो का DataContext सेट करें। अपने XAML में, आप लिख सकते हैं:

<ListView ItemsSource="{Binding}" />

यह ListView को शब्दकोश में बाँध देगा।

अधिक जटिल परिदृश्यों के लिए, यह MVVM पैटर्न के पीछे तकनीकों का सबसेट होगा ।


0

एक तरीका यह होगा कि एक ऑब्ज़र्वेबल कॉलेक्शन (System.Collections.ObjectModel) बनाया जाए और उसमें आपका डिक्शनरी डेटा हो। तब आपको अपने लिस्टबॉक्स में ऑब्जर्वेबल कॉलेक्शन को बांधने में सक्षम होना चाहिए।

आपके XAML में आपको कुछ इस तरह होना चाहिए:

<ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />

0

मुझे यह ठीक वैसी ही समस्या हो रही थी, लेकिन मेरा नहीं था क्योंकि मैं एक स्थानीय चर सेट कर रहा था ... मैं एक बच्चे की खिड़की में था, और मुझे एक रिश्तेदार डेटाकोटेक्स्ट सेट करने की आवश्यकता थी, जिसे मैंने बस विंडो एक्सएएमएल में जोड़ा था।

<Window x:Class="Log4Net_Viewer.LogItemWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Title="LogItemWindow" Height="397" Width="572">

0

आप x की कोशिश कर सकते हैं: संदर्भ चाल

<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.