2009-02-11 9 views
2

Итак, я изучаю WPF прямо сейчас и хочу сделать простую привязку данных между значением bool и включен или нет MenuItem.WPF привязка данных IsEnabled Свойство

Я закодировал так:

<MenuItem Name="miSaveFile" Header="Save" Click="miSaveFile_Click" 
IsEnabled="{Binding}" /> 

И в .cs файл я поставил:

miSaveFile.DataContext = dataChanged; 

По какой-то причине не кажется, что правильно отражает состояние из MenuItem dataChanged.

Что мне не хватает?

ответ

4

Вам лучше привязываться к объекту, чем к примитивному типу. Этот объект часто называют «моделью» для вашего вида.

WPF использует интерфейс INotifyPropertyChanged для модели (или часто рассматриваемой модели), чтобы уведомить представление о том, что модель изменила состояния.

Итак, сначала вы должны определить класс данных как модель, которая реализует интерфейс INotifyPropertyChanged и запускает событие PropertyChanged всякий раз, когда свойство изменяется.

Когда вы устанавливаете привязку, у вас есть 5 основных элементов привязки, о которых нужно беспокоиться. Связывание имеет исходный объект, исходный путь к исходному объекту, целевой объект, целевое свойство целевого объекта и дополнительный конвертер.

Если вы не указали источник, по умолчанию используется DataContext элемента управления, на которое установлено привязку. Существуют и другие варианты настройки источника. Here - статья Microsoft об установке источника. Затем вы можете установить путь для свойства, чтобы вытащить из источника для привязки. В вашем случае источник является логическим, и нет пути, потому что привязка использует весь исходный объект.

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

Конвертер может произвольно преобразовать исходное значение в значение, совместимое с целевым свойством. Вы можете использовать любой объект для конвертера, который реализует IValueConverter или IMultiValueConverter (для MutliBindings).

В вашем случае я бы сначала создал модель, которая реализует INotifyPropertyChanged. Затем я бы присвоил DataContext меню экземпляру модели. Тогда я установил бы связывание:

IsEnabled="{Binding Path=EnableFlag}" 

(Где EnableFlag является булево свойство в модели, которую вы хотите, чтобы меню для связывания)

Если вы настроили интерфейс INotifyPropertyChanged правильно, пункт меню будет включен/отключен, когда вы измените это свойство на модели.

1

Как пользовательский интерфейс знает, когда переменная dataChanged действительно изменилась?

Я обычно привязываю свойство к объекту, и пусть этот класс реализует INotifyPropertyChanged. Пользовательский интерфейс затем автоматически обновляется всякий раз, когда вызывается событие PropertyChanged.

Так что я бы

<MenuItem Name="miSaveFile" Header="Save" Click="miSaveFile_Click" 
IsEnabled="{Binding DataChanged}"</MenuItem> 

, а затем установить miSaveFile.DataContext = myObject.DataChanged (MyObject может быть, если вы используете CodeBehind)

Edit: Я просто сделал быстрый тест , Если вы установите контекст данных непосредственно в свойство DataChanged, подписка на событие PropertyChanged объекта владельца не добавляется. Но решение, которое я предлагаю, работает.

+0

"? Как пользовательский интерфейс знать, когда переменная dataChanged фактически изменились" Хороший вопрос. Прямо сейчас я все еще на стадии Data_Binding-Is-Voodoo :) –

+0

Если вы хотите по-настоящему понять, что происходит (материал вуду), вы можете включить .NET-инфраструктуру в визуальную студию и посмотреть на код, который на самом деле выполнено :) –

2

Что касается MenuItem, не лучший ли подход к использованию модели Command, а не свойства Click и IsEnabled?

После InitialiseComponent():

this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Save, fileSaveExecuted, fileSaveCanExecute)); 

Дополнительных методы:

/* here is where you set e.CanExecute true for enabled: */ 
    private void fileSaveCanExecute(object x, CanExecuteRoutedCommandEventArgs e)) { e.CanExecute = ...; e.Handled = true; } 
/* here is where you act on the command: */ 
    private void fileSaveExecuted(object sender, ExecutedRoutedEventArgs e) { ... } 

XAML:

<MenuItem Header="_Save" Command="Save"/>