Arka plan kodunda tanımlanan bağlama nesneleri


87

Kodun arkasında örneklenen bir nesnem var, örneğin, XAML window.xaml olarak adlandırılıyor ve window.xaml.cs içinde

protected Dictionary<string, myClass> myDictionary;

Bu nesneyi örneğin bir liste görünümüne yalnızca XAML işaretlerini kullanarak nasıl bağlayabilirim?

Güncelleme:

(Bu tam olarak test kodumda var):

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

Ve kodun arkasında

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

    public Window1()
    {
        InitializeComponent();
    }
}

Başlığın "ABCDEFG" olması gerektiğini varsayalım, değil mi? ama hiçbir şey göstermiyor.


1
Garip bir şekilde, pencerenin özellik atamasının sırasını değiştirirsem çalışmıyor. "Başlık" Özelliğini ve ardından "DataContext" Özelliğini ayarlarsam, bağlama gerçekleşmez. Bunu kimse açıklayabilir mi? <Window x: Class = "INotifyPropertyTest.MainWindow" xmlns = " schemas.microsoft.com/winfx/2006/xaml/presentation " xmlns: x = " schemas.microsoft.com/winfx/2006/xaml " xmlns: local = " clr-namespace: INotifyPropertyTest "Height =" 350 "Width =" 525 "DataContext =" {Binding RelativeSource = {RelativeSource self}} "Title =" {Binding WindowName} ">
Ramesh

Yanıtlar:


109

DataContext'i kontrolünüz, formunuz vb. İçin şu şekilde ayarlayabilirsiniz:

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

Açıklama :

Yukarıdaki değere ayarlanan veri bağlamı, arkasındaki koda "sahip" olan öğe ne olursa olsun yapılmalıdır - bu nedenle, bir Window için bunu Window bildiriminde ayarlamalısınız.

Örneğiniz bu kodla çalışıyor:

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

Bu düzeyde ayarlanan DataContext, daha sonra penceredeki herhangi bir öğe tarafından miras alınır (bunu bir alt öğe için açıkça değiştirmediğiniz sürece), bu nedenle Window için DataContext ayarlandıktan sonra , herhangi bir denetimden CodeBehind özelliklerine doğrudan bağlama yapabilmeniz gerekir. pencerede.


1
Buradaki "Öz", tüm pencere sınıfından ziyade kontrol anlamına gelir, öyle mi?
xandy

Yeterince garip, Aşağıda sahip olduğum kod var ve beklendiği gibi çalışmıyor: genel kısmi sınıf Window1: Window {public const string windowname = "ABCDEFG"; public Window1 () {InitializeComponent (); }} <Window x: Class = "QuizBee.Host.Window1" xmlns = " schemas.microsoft.com/winfx/2006/xaml/presentation " xmlns: x = " schemas.microsoft.com/winfx/2006/xaml " Başlık = "{Binding windowname}" Yükseklik = "300" Genişlik = "300" DataContext = "{Binding RelativeSource = {RelativeSource Self}}"> </Window>
xandy

10
Oh, şimdi sorun değil, pencere adını saf genel değişken yerine özellik olarak değiştirdim ve şimdi görüntülenebilir! Teşekkürler!
xandy

1
Bunun neden sadece varsayılan olarak ayarlanmadığını hayal edemiyorum.
Okonomiyaki3000

122

Bunu yapmanın çok daha kolay bir yolu var. Pencerenize veya UserControl'ünüze bir Ad atayabilir ve ardından ElementName ile bağlanabilirsiniz.

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: Name'i (derleyici hatası CS0542) değiştirmek zorunda kaldım. Ardından, ElementName'in buna göre değiştirilmesi gerekir.
Jack Miller

25

Guy'ın cevabı doğru olsa da (ve muhtemelen 10 durumdan 9'una uyuyor), bunu DataContext'i yığında daha da ayarlamış bir denetimden yapmaya çalışıyorsanız, DataContext'i ayarladığınızda bunu sıfırlayacağınızı belirtmek gerekir. kendine dönüş:

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

Bu elbette mevcut bağlarınızı bozacaktır.

Bu durumda, bağlamaya çalıştığınız denetimin üst öğesi yerine RelativeSource'u ayarlamalısınız.

yani bir UserControl'ün özelliklerine bağlanmak için:

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

Şu anda veri bağlamada neler olup bittiğini görmenin ne kadar zor olabileceği düşünüldüğünde, bu ayarın RelativeSource={RelativeSource Self}şu anda çalıştığını bulsanız bile bunu aklınızda bulundurmaya değer :)


1
Silverlight 4, FindAncestor'ı desteklemez. Ancak bunu bu şekilde yapmanız gerekir, FindAncestor'ı bu sitede açıklandığı gibi uygulayabilirsiniz. http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/
ShawnFeatherly

7

Sadece biraz daha açıklama: "Al", "set" içermeyen bir mülk bağlanamaz

Tıpkı soranın davası gibi davayla yüzleşiyorum. Bağlantının düzgün çalışması için aşağıdaki şeylere sahip olmalıyım:

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

10
'Al' ve 'ayarla' olmadan bir mülke tam olarak nasıl sahip olabilirsiniz? Bu bir mülk değil tarla olmaz mıydı?
kjbartel

0

Arkadaki kodunuzda, pencerenin DataContext değerini sözlüğe ayarlayın. XAML'nizde şunları yazabilirsiniz:

<ListView ItemsSource="{Binding}" />

Bu, ListView'ı sözlüğe bağlayacaktır.

Daha karmaşık senaryolar için bu, MVVM modelinin arkasındaki tekniklerin bir alt kümesi olacaktır .


0

Bunun bir yolu, bir ObservableCollection (System.Collections.ObjectModel) oluşturmak ve sözlük verilerinizi orada bulundurmaktır. Ardından ObservableCollection'ı Liste Kutunuza bağlayabilmelisiniz.

XAML'nizde şuna benzer bir şeye sahip olmalısınız:

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

0

Bir dönüştürücü tanımlayın:

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

Bir Sözlüğün özel bir tanımına bağlanın. Atladığım birçok geçersiz kılma var, ancak önemli olan indeksleyici, çünkü değer değiştirildiğinde özellik değiştirildi olayını yayıyor. Bu, kaynağın bağlanmayı hedeflemesi için gereklidir.

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 dosyanızda bu dönüştürücüyü kullanın. İlk referans:

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

Daha sonra, örneğin, sözlüğünüzde anahtarın "Ad" olduğu bir giriş varsa, ona bağlanmak için: kullanın

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

0

Mülkünüzü "windowname" bir DependencyProperty yapın ve kalanını koruyun.


0

Ben de aynı sorunu yaşıyordum ama benimki yerel bir değişken ayarladığım için değildi ... Bir çocuk penceresindeydim ve Window XAML'e yeni eklediğim göreceli bir DataContext ayarlamam gerekiyordu.

<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

Bu, arkasındaki koda bağlanma yolum (özelliğe bakın DataTemplateSelector)

public partial class MainWindow : Window
{
  public MainWindow()
  {
    this.DataTemplateSelector = new MyDataTemplateSelector();

    InitializeComponent();

    // ... more initializations ...
  }

  public DataTemplateSelector DataTemplateSelector { get; }

  // ... more code stuff ...
}

XAML'de, RelativeSourceAncestors aracılığıyla kapsama alanına kadar başvurulacak Window, bu yüzden Windowsınıfımdayım ve özelliği Pathbildirim yoluyla kullanıyorum :

<GridViewColumn Header="Value(s)"
                CellTemplateSelector="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataTemplateSelector}"/>

Özelliğin DataTemplateSelectorçağrılmadan önce ayarlanması, InitializeComponenteksik uygulama IPropertyChangedveya uygulama kullanımına bağlıdır, DependencyPropertybu nedenle özellik değişikliği durumunda iletişim çalışmaz DataTemplateSelector.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.