2013-09-10 2 views
4

Следующий код работает, как ожидалось:Разница между установкой DataContext = this в конструкторе и привязкой к {RelativeSource Self} в WPF?

AskWindow.xaml:

<Window 
    x:Class='AskWPF.AskWindow' 
    xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' 
    xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' 
    > 

<DataGrid ItemsSource="{Binding SimpleItems}" /> 

</Window> 

AskWindow.xaml.cs:

namespace AskWPF { 

public class SimpleRow { 
    private string firstColumn; 
    private string secondColumn; 

    public SimpleRow(string first, string second) { 
     firstColumn = first; 
     secondColumn = second; 
    } 

    public string FirstColumn { 
     get { return firstColumn; } 
     set { firstColumn = value; } 
    } 

    public string SecondColumn { 
     get { return secondColumn; } 
     set { secondColumn = value; } 
    } 
} 

public partial class AskWindow : Window { 

    private ObservableCollection<SimpleRow> simpleItems; 

    public AskWindow() { 
     InitializeComponent(); 
     DataContext = this; 

     simpleItems = new ObservableCollection<SimpleRow>(); 
     simpleItems.Add(new SimpleRow("row 0, column 0", "row 0, column 1")); 
     simpleItems.Add(new SimpleRow("row 1, column 0", "row 1, column 1")); 
    } 

    public ObservableCollection<SimpleRow> SimpleItems { 
     get { return simpleItems; } 
    } 
} 

} 

Но если установить DataContext='{Binding RelativeSource={RelativeSource Self}}' в Window теги и строки комментария DataContext=this мы получаем пустое окно. Зачем?

AskWindow.xaml:

<Window .... DataContext='{Binding RelativeSource={RelativeSource Self}}'> 

    <DataGrid ItemsSource="{Binding SimpleItems}" /> 

</Window> 

AskWindow.xaml.cs:

... 
public AskWindow() { 
    InitializeComponent(); 
    // DataContext = this; 

    simpleItems = new ObservableCollection<SimpleRow>(); 
    simpleItems.Add(new SimpleRow("row 0, column 0", "row 0, column 1")); 
    simpleItems.Add(new SimpleRow("row 1, column 0", "row 1, column 1")); 
} 
... 

ответ

1

Вот моя догадка. В обоих случаях в одной точке ваша коллекция имеет значение null. Точно сразу после InitializeComponent. На этом этапе исходная привязка данных получила данные, но не датиконтекст. Теперь, установив DataContext, ваше свойство будет поднято, и каждое связанное с ним привязанность становится недействительным и обновляется. Вот моя часть догадки, причина, по которой она работает, заключается в том, что привязка к ItemsSource отложена, поэтому она работает, чтобы просто установить коллекцию в следующей строке.

Короче: установка Datacontext приведет к повторной фиксации привязки. Но в вашем примере RelativeSource ваша привязка работала с самого начала, но коллекция была нулевой, и вы никогда не говорили wpf о том, чтобы восстановить привязку. Если вы прямо инициализируете свою коллекцию, она должна работать нормально.

+0

Я удивлен этим поведением.Похоже, если DataContext имеет значение null при вызове InitializeComponent(), тогда привязка будет дефферирована; если DataContext не является нулевым, будет привязан к конкретному экземпляру объекта. –

1

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

Порекомендуйте переместить вызов InitializeComponent в конец конструктора или, по крайней мере, установить поле заранее.

Обычно я использую только для чтения поле и просто инициализировать его сразу:

private readonly ObservableCollection<Data> collection = 
    new ObservableCollection<Data>(); 
public ObservableCollection<Data> Collection { get { return collection ; } } 
0

Фактически связывание является правильным, и она работает также. Чтобы обновить экран, привязка должна получать уведомления о том, что что-то изменилось. Связывание сначала оценивает, а затем прослушивает уведомления. Во второй версии привязка сначала оценивается при запуске InitializeComponent, но в этот момент нет значений, поэтому вы ничего не видите. После этого значения создаются, но привязка не переоценивается, потому что никакие уведомления не отправляются.

Так что да, одно решение будет состоять в инициализации коллекции до InitializeComponent.

... 
private ObservableCollection<SimpleRow> simpleItems = new ObservableCollection<SimpleRow>(); 
... 

Другое решение было бы глупо и излишним, чтобы уведомить связывание, что что-то изменилось.

Просто примечание, возможно, это для учебных целей, потому что пользовательский интерфейс не следует смешивать с моделью.

 Смежные вопросы

  • Нет связанных вопросов^_^