Прив'язка об'єктів, визначених у коді


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>

І в codebehind

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

    public Window1()
    {
        InitializeComponent();
    }
}

Припустимо, заголовок повинен стати "ABCDEFG", так? але це в кінцевому підсумку нічого не показує.


1
Як не дивно, але якщо я змінив порядок призначення властивостей вікна, це не спрацює. Якщо я встановив властивість "Title", а потім властивість "DataContext", прив'язка не відбудеться. Хто-небудь може це пояснити? <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}">
Рамеш

Відповіді:


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 для Window ви зможете просто зробити пряме прив'язування до властивостей CodeBehind з будь-якого елемента керування на вікні.


1
"Я" тут означає контроль, а не весь клас вікна, чи не так?
xandy

Як не дивно, але ось код, який я маю, і він працює не так, як очікувалося: публічний частковий клас 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 " Назва = "{Ім'я прив'язки до вікна}" Висота = "300" Ширина = "300" DataContext = "{Binding RelativeSource = {RelativeSource Self}}"> </Window>
xandy

9
О, зараз нормально, я змінив ім'я вікна на властивість, а не на загальнодоступну змінну, і воно може відображатися зараз! Дякую!
xandy

1
Я не уявляю, чому це не просто встановлено за замовчуванням.
Okonomiyaki3000,

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: Name (помилка компілятора CS0542). Тоді ElementName потрібно змінити відповідно.
Джек Міллер,

25

Хоча відповідь Гая правильна (і, мабуть, відповідає 9 з 10 випадків), варто зазначити, що якщо ви намагаєтесь зробити це з елемента керування, який вже має свій DataContext, встановлений далі в стеку, ви скинете це, коли встановите DataContext назад до себе:

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

Звичайно, це порушить ваші існуючі прив’язки.

У цьому випадку вам слід встановити RelativeSource на елементі керування, який ви намагаєтеся прив'язати, а не на його батьківському.

тобто для прив'язки до властивостей UserControl:

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

З огляду на те, наскільки важко в даний час побачити, що відбувається з прив'язкою даних, варто мати це на увазі, навіть якщо ви виявите, що налаштування на RelativeSource={RelativeSource Self}даний момент працює :)


1
Silverlight 4 не підтримує FindAncestor. Однак якщо вам потрібно зробити це таким чином, ви можете реалізувати FindAncestor, як описано на цьому сайті. http://blog.thekieners.com/2010/09/08/relativesource-binding-with-findancestor-mode-in-silverlight/
ShawnFeatherly

6

Ще трохи роз’яснень: властивість без „get”, „set” неможливо буде пов’язати

Я розглядаю справу так само, як справу аскера. І я повинен мати такі речі, щоб прив’язка працювала належним чином:

//(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
Як саме ви можете мати властивість без 'get' і 'set'? Це не було б полем, а не власністю?
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

Зробіть властивість "ім'я вікна" власністю DependencyProperty, а решту залиште незмінною.


0

У коді позаду встановіть у вікні DataContext словник. У своєму XAML ви можете написати:

<ListView ItemsSource="{Binding}" />

Це прив’яже ListView до словника.

Для більш складних сценаріїв це було б підмножиною методів, що лежать в основі шаблону MVVM .


0

Одним із способів було б створити ObservableCollection (System.Collections.ObjectModel) і мати там свої дані словника. Тоді ви зможете прив’язати ObservableCollection до вашого ListBox.

У вашому XAML у вас повинно бути щось подібне:

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

0

У мене була точно така ж проблема, але у мене не через те, що я встановлював локальну змінну ... Я знаходився у дочірньому вікні, і мені потрібно було встановити відносний DataContext, який я щойно додав до вікна XAML.

<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

Це мій спосіб прив’язати код позаду (див. Властивість DataTemplateSelector)

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

    InitializeComponent();

    // ... more initializations ...
  }

  public DataTemplateSelector DataTemplateSelector { get; }

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

У XAML буде посилатися RelativeSourceчерез Ancestors до вмісту Window, тому я перебуваю у своєму Windowкласі і використовую властивість через Pathоголошення:

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

Встановлення властивості DataTemplateSelectorперед викликом InitializeComponentзалежить від відсутності реалізації IPropertyChangedабо використання реалізації, DependencyPropertyтому зв’язок щодо зміни властивості не здійснюється DataTemplateSelector.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.