#c# #wpf #xaml #dependency-properties #datacontext
#c# #wpf #xaml #зависимость-свойства #datacontext
Вопрос:
Я пытаюсь научиться использовать привязку WPF и архитектуру MVVM. У меня возникли некоторые проблемы со свойствами зависимостей. Я пытался управлять видимостью элемента в представлении, привязывая его к DependencyProperty в DataContext, но это не работает. Независимо от того, какое GridVisible
значение я задаю в конструкторе модели представления ниже, оно всегда отображается как видимое при запуске кода.
Кто-нибудь может увидеть, где я ошибаюсь?
C # code (ViewModel):
public class MyViewModel : DependencyObject
{
public MyViewModel ()
{
GridVisible = false;
}
public static readonly DependencyProperty GridVisibleProperty =
DependencyProperty.Register(
"GridVisible",
typeof(bool),
typeof(MyViewModel),
new PropertyMetadata(false,
new PropertyChangedCallback(GridVisibleChangedCallback)));
public bool GridVisible
{
get { return (bool)GetValue(GridVisibleProperty); }
set { SetValue(GridVisibleProperty, value); }
}
protected static void GridVisibleChangedCallback(
DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
// Do other stuff in response to the data change.
}
}
Код XAML (Посмотреть):
<UserControl ... >
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</UserControl.Resources>
<UserControl.DataContext>
<local:MyViewModel x:Name="myViewModel" />
</UserControl.DataContext>
<Grid x:Name="_myGrid"
Visibility="{Binding Path=GridVisible,
ElementName=myViewModel,
Converter={StaticResource BoolToVisConverter}}">
<!-- Other elements in here -->
</Grid>
</UserControl>
Я просмотрел несколько онлайн-руководств, и, похоже, я правильно следую тому, что я там нашел. Есть идеи? Спасибо!
Ответ №1:
Уберите ElementName из вашей привязки, это кажется неправильным. Измените его на:
<Grid x:Name="_myGrid"
Visibility="{Binding Path=GridVisible,
Converter={StaticResource BoolToVisConverter}}">
Комментарии:
1. На самом деле я скопировал ваш код и обнаружил, что он работает с привязкой с включенным именем элемента и без него. Для чего вы используете пользовательский элемент управления (т. Е. window или другой пользовательский элемент управления)? Возможно, там что-то не так (код, который вы не включили).
2. Я удалил ElementName, и он по-прежнему не работает. Похоже, вы правы — это, вероятно, как-то связано с другой частью моего кода, а не с исправленной версией, опубликованной выше. К сожалению, я не могу опубликовать фактический код, поскольку он предназначен для работы.
3. В этом случае, когда вы запускаете свое приложение и открываете окно, содержащее этот пользовательский элемент управления, поищите в своем окне вывода в VisualStudio любые ошибки с текстом, подобным этому «Ошибка пути привязки выражения: свойство ‘GridVisible’ не найдено в ‘object ……» содержимое этого сообщения может помочь вам в дальнейшей отладке. извините, я не могу вам больше помочь. удачи.
4. Вы были правы, это была опечатка! Я проверил окно вывода при запуске в режиме отладки и обнаружил, что я неправильно написал одну из своих привязок данных. Теперь это работает отлично. Спасибо!
Ответ №2:
Пусть ваша ViewModel реализует INotifyPropertyChanged вместо наследования от DependencyObject. Реализуйте интерфейс и вызывайте PropertyChanged из вашего установщика для свойства.
private bool gridVisible;
public bool GridVisible
{
get { return gridVisible; }
set
{
gridVisible = value;
OnPropertyChanged("GridVisible");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Комментарии:
1. Вам не нужно ссылаться на свою виртуальную машину в вашем XAML с помощью ElementName, и вам не нужно называть свою виртуальную машину. Когда вы назначаете его usercontrol. DataContext становится источником привязки по умолчанию для всех дочерних элементов пользовательского элемента управления.
Ответ №3:
Смысл установки ViewModel в качестве DataContext заключается в том, чтобы включить простые относительные привязки, все привязки, в которых вы указываете только Path
, принимают DataContext в качестве источника, который наследуется во всем UserControl (если не установлено иное, например, в шаблонных элементах ItemsControl)
Итак, как только DataContext установлен в UserControl, вы обычно не указываете какой-либо источник при привязке к виртуальной машине. (Источниками являются ElementName
, RelativeSource
и Source
)
Кроме того, я лично не стал бы наследовать ViewModels от DependencyObject
, поскольку это вводит привязку к потоку, также точка DependencyProperties делает разреженные структуры данных более эффективными, не создавая ненужных полей во всех из них (ViewModels обычно являются полной противоположностью sparse).
Комментарии:
1.
INotifyPropertyChanged
является альтернативойDependencyObject
— большинство viewmodels используют это вместо свойств зависимостей.