Связывание объектов, определенных в коде - PullRequest
78 голосов
/ 10 ноября 2009

У меня есть некоторый объект, который создается в коде, например, 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", верно? но в итоге он ничего не показывает.

Ответы [ 10 ]

116 голосов
/ 17 мая 2011

Есть гораздо более простой способ сделать это. Вы можете назначить имя для вашего Window или 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();
    }
}
93 голосов
/ 10 ноября 2009

Вы можете установить DataContext для своего элемента управления, формы и т. Д., Например, так:

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

Разъяснение

Контекст данных, для которого установлено значение выше, должен быть сделан для любого элемента, которому «принадлежит» код позади - поэтому для Окна вы должны установить его в объявлении Окна.

У меня есть ваш пример работы с этим кодом:

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

DataContext, установленный на этом уровне, затем наследуется любым элементом в окне (если вы явно не измените его для дочернего элемента), поэтому после установки DataContext для окна вы сможете просто выполнить прямую привязку к CodeBehind свойства из любого элемента управления в окне.

23 голосов
/ 11 мая 2011

Хотя ответ Гая верен (и, вероятно, подходит для 9 из 10 случаев), стоит отметить, что если вы пытаетесь сделать это из элемента управления, для которого уже установлен DataContext, установленный дальше по стеку, вы сбросите его, когда Вы устанавливаете DataContext обратно на себя:

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

Это, конечно, тогда сломает ваши существующие привязки.

В этом случае вам следует установить RelativeSource для элемента управления, который вы пытаетесь связать, а не его родительский элемент.

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

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

Учитывая, насколько сложно в настоящее время увидеть, что происходит с привязкой данных, стоит помнить об этом, даже если вы обнаружите, что настройка RelativeSource={RelativeSource Self} в настоящее время работает:)

5 голосов
/ 30 сентября 2012

Еще немного уточнений: Свойство без '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>
1 голос
/ 10 ноября 2009

Сделайте вашу собственность "windowname" свойством DependencyProperty и оставьте то же самое.

1 голос
/ 10 ноября 2009

Определить конвертер:

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}">
0 голосов

Вы можете попробовать x: Справочный трюк

<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>
0 голосов
/ 12 октября 2011

У меня была точно такая же проблема, но у меня не было, потому что я устанавливал локальную переменную ... Я находился в дочернем окне, и мне нужно было установить относительный 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 голосов
/ 10 ноября 2009

Один из способов заключается в создании ObservableCollection (System.Collections.ObjectModel) и размещении там данных словаря. Тогда вы сможете привязать ObservableCollection к вашему ListBox.

В вашем XAML должно быть что-то вроде этого:

<ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />
0 голосов
/ 10 ноября 2009

В вашем коде установите DataContext окна в словарь. В вашем XAML вы можете написать:

<ListView ItemsSource="{Binding}" />

Это связывает ListView со словарем.

Для более сложных сценариев это будет подмножество методов, лежащих в основе шаблона MVVM .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...