2013-04-29 2 views
2

Я использую привязку OneWayToSource, и кажется, что он всегда устанавливает для моего источника свойство значение null. Почему это так? Это вызывает у меня проблемы, потому что мне нужно значение из свойства target в моем исходном свойстве, а не null.OneWayToSource Dilemma

Вот мой код:

MyViewModel.cs:

public class MyViewModel 
{ 
    private string str; 

    public string Txt 
    { 
     get { return this.str; } 
     set { this.str = value; } 
    } 
} 

MainWindow.cs:

public MainWindow() 
{ 
    InitializeComponent(); 
    MyViewModel vm = new MyViewModel(); 
    vm.Txt = "123"; 
    this.DataContext = vm; 
} 

MainWindow.xaml:

<Window x:Class="OneWayToSourceTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525" 
     xmlns:local="clr-namespace:OneWayToSourceTest"> 
     <Grid> 
     <local:MyButton Content="{Binding Path=Txt, Mode=OneWayToSource}"/> 
     </Grid> 
</Window> 

MyButton.cs:

public class MyButton : Button 
{ 
    public MyButton() 
    { 
     this.Content = "765"; 
    } 
} 

Целевое свойство MyButton.Content. Свойством source является MyViewModel.Txt. Свойство Txt должно быть установлено в «765», но вместо этого оно равно null.

Почему я получаю null вместо 765?

EDIT:

Пожалуйста, посмотрите внутри MyButton конструктора. На самом деле, если вы будете использовать простой TwoWay, он будет работать. Я тестировал его, и он не имеет ничего общего с содержимым, которое устанавливается внутри конструктора. Его что-то с OneWayToSource привязкой.

Теперь, чтобы объяснить, как я использовал TwoWay связывание, я установить значение дп внутри конструктора, вызвав setvalue метод, но затем внутри обертки или лучше сказал геттер и сеттер я не предложил сеттер, следовательно, почему я сделал мой TwoWay вид выглядит как его OneWayToSource. Я сделал это, чтобы проверить, не виноват ли его конструктор. Я понял, что свойство внутри viewmodel имеет значение 765, так что я имел в виду с привязкой TwoWay. Я просто тестировал, был ли он конструктором управления. Его все отлично с установкой значения внутри конструктора.

Скрывая сеттер Я имею в виду этот множество {}

+0

Есть ли у вас какие-либо BindingErrors? – Jehof

+0

Нет. Я не хочу. : - (( –

ответ

4

MyButton получает экземпляр по InitializeComponent перед DataContext устанавливается, поэтому привязка не действует, когда его застройщик пробегов. Попробуйте установить значение одним нажатием кнопки.

+0

Я не могу заставить пользователя нажимать кнопку, чтобы установить значение. :) –

+1

Возможно, нет, но я объяснил вам, почему он не работает. Большое спасибо за downvote !! – johndsamuels

+0

Когда datacontext не установлен, значение Txt должно быть 123. Пожалуйста, взгляните на мой код еще раз. После установки DataContext связывание должно обновить значение Txt до 765. Хотя проблема в том, что после привязки обновленного значения значение но неважно, если до или после InitializeComponent, он все еще не работает с OneWayToSource.Пожалуйста, взгляните на мой вопрос еще раз.Я отредактировал его. –

1

Фактически Если вы используете простой TwoWay, он будет работать.

Я не могу воспроизвести это. Учитывая код, который вы предоставили, если вы используете режим привязки TwoWay, свойство viewmodels Txt будет равно «123», значение которого указано внутри вашего конструктора MainWindows.

Я проверил его и он не имеет ничего общего с контентом, устанавливается внутри конструктора

Как Рахиль указал, XAML Binding очищает локальное значение. Связывание происходит после запускается код конструктора ваших кнопок. Затем привязка извлекает значение по умолчанию из метаданных свойства зависимостей. Это легко установить, установив значение в более подходящее время после установления привязки, например, в событии Loaded.

Эта простая модификация даст вам желаемый результат:

public class MyButton : Button 
{ 
    public MyButton() 
    { 
     this.Loaded += MyButton_Loaded; 
    } 

    void MyButton_Loaded(object sender, RoutedEventArgs e) 
    { 
     this.Content = "765"; 
    } 
} 

Rachels ответить также обеспечивает альтернативный способ получения этой работы (переопределение метаданных свойств по умолчанию).

Почему каждый раз, когда кто-то использует привязку OneWayToSource, устанавливается значение после initalizatin? Это не имеет смысла для меня.

Я думаю, причина в том, что это не имеет смысла для вас, потому что ваш тест привязки TwoWay не работает так, как вы думаете.

Использование OneWayToSource связывания:

Использование OneWayToSource связывание происходит следующее:

  1. Вы устанавливаете MyButton.Content на "123" в это конструктор.
  2. Вы устанавливаете привязку OneWayToSource в свой XAML. Это СЧИТАЕТ значение, которое вы установили.
  3. Связывание возвращает значение свойства по умолчанию (null) из метаданных свойств и устанавливает для свойства ViewModel.Txt значение, равное этому значению.

Если вы установили свойство MyButton.Content в событие, загруженное кнопками, это происходит после того, как произошли вышеуказанные события, чтобы ваше свойство было установлено на значение, которое вы хотите.

Вы можете проверить это сами, поставив точку останова на свои MyViewModel.Txt свойства getter. значение будет установлено на «123», нуль и «756» в этом порядке.

Использование TwoWay связывания:

Теперь, если вы должны были изменить XAML использовать TwoWay связывание происходит следующее:

  1. Вы устанавливаете MyButton.Content на «123» в это конструктор.
  2. Вы устанавливаете привязку TwoWay в своем XAML. Это СЧИТАЕТ значение, которое вы установили.Значение
  3. Ваших средства управления (MyButton.Content) обновляется с использованием Источника, который в данном случае является вашим ViewModels Txt собственности в результате вашего MyButton.Content имущества равно «123».
+0

Я не поклонник просто использовать вещи, не зная почему. кажется, в этом случае я просто должен поверить вам, ребята. все еще, как я сказал, с моими настройками примера привязки twoway мне удалось доказать его не конструктор. однако давайте примем это как ответ. спасибо –

8

Content свойства может быть установлен только для одного значения, и вы заменяющего значения «756» с привязкой.

Как я указывал вам в my answer на ваш другой вопрос, WPF запускает код в следующем порядке:

  • Normal - Конструкторы работать здесь
  • DataBind
  • Рендер
  • Loaded

Итак, первое, что нужно сделать, - это ваш MainWindow Выполняется конструктор. Это создает кнопку, которая вызывает конструктор Button, и устанавливает Button.Content в «765».

Однако в XAML для Button вы указали другой объект Content - переплета. Таким образом, ваш объект кнопки создается, свойство Content получает значение «765», а затем свойство Content установлено на {Binding Path=Txt, Mode=OneWayToSource}.

Это то же самое, как сделать что-то вроде:

var b = new MyButton(); 
b.Content = "756"; 
b.Content = new Binding(...); 

Вы заменаContent собственности.

(И технически, последняя строка должна быть b.SetBinding(MyButton.ContentProperty, new Binding(...)); правильно связать значение, тем не менее, я использую более базовый синтаксис, чтобы сделать его легче понять проблему.)

Следующий шаг в цикле данные Связывание, поэтому оценивается привязка свойства Content.

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

В случае свойства зависимости Button.Content значение по умолчанию равно null, поэтому ваш исходный элемент получает значение null.

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

Если вы должны были установить значение после связывания было создано, например, в Loaded события для вашей кнопки, вы увидите, что ваше имущество источника правильно обновляются, когда вы установите кнопки Content

void MyButton_Loaded(object sender, EventArgs e) 
{ 
    ((Button)sender).Content = "756"; 
} 

И в последнюю очередь, если вы пытаетесь установить значение по умолчанию Content имущества из пользовательского элемента управления, вам необходимо перезаписать MetaData для этого свойства, например:

// Note that this is the static constructor, not the normal one 
static MyButton() 
{ 
    ContentProperty.OverrideMetadata(typeof(MyButton), 
     new FrameworkPropertyMetadata("756")); 
} 

Это сделает так, чтобы значение Content было "756" вместо null

+0

+1 Я удалил свой ответ, поскольку ваш гораздо лучше, потому что он объясняет, почему привязка работает так, как она делает. Я также не знал, что вы можете установить привязку как этот 'b.Content = new Binding (...)' и подумали, что вам нужно использовать метод SetBinding (..) '. Спасибо за совет. –

+0

@Benjamin Errmmm, который, возможно, был ошибкой :) Я думаю, что установка 'b.Content = new Binding (...)' будет устанавливать свойство Content для объекта привязки и не оценивать его (необходимо проверить конечно). Я просто использовал этот синтаксис, потому что он упрощает понимание того, что происходит :) – Rachel

+0

Да, вы правы :) Когда я тестировал это, я думал, что у меня это работает, но я ошибся (мой тест был испорчен). –