2015-12-19 3 views
1

Кто-нибудь знает, как я могу синхронизировать свои свойства, которые находятся в ViewModel, с моими свойствами зависимостей, которые находятся в представлении?Синхронизация свойств зависимостей (просмотр) с помощью свойств (ViewModel)

Я пытаюсь создать UserControl, который затем будет размещен в WPF-Window (MainWindow.xaml). Пользователь UserControl имеет собственную ViewModel, которая содержит ICommands и свойства.

Проблема заключается в том, что мне также необходимо вернуть определенные свойства в MainWindow (.xaml), а также установить их.

В настоящее время мои классы ищут так:

MainWindow.xaml

<TextBox Name="tbInput" VerticalAlignment="Top" HorizontalAlignment="Stretch" Grid.Row="0"></TextBox> 
    <local:View x:Name="appEntryView" Pfad="{Binding ElementName=tbInput, Path=Text}" Grid.Row="1" Margin="10"/> 

View.xaml

<UserControl x:Class="DependencyProperties.Test" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:local="clr-namespace:DependencyProperties_Intro" 
     x:Name="obj" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 

<Grid> 
    <TextBlock Text="{Binding ElementName=obj, Path=Pfad}"/> 
</Grid> 

View.xaml.cs

public partial class View: UserControl, INotifyPropertyChanged 
{ 

    public String Pfad 
    { 
     get { return (String)GetValue(PfadProperty); } 
     set { SetValue(PfadProperty, value); OnNotifyPropertyChanged("Pfad"); } 
    } 

    // Using a DependencyProperty as the backing store for Path. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty PfadProperty = 
     DependencyProperty.Register("Pfad", typeof(String), typeof(GraphSharpTest), new PropertyMetadata(default(string))); 

    public View() 
    { 
     InitializeComponent(); 
     this.DataContext = new ViewModel(); 
     var name = "Pfad"; 
     var binding = new Binding(name) { Mode = BindingMode.TwoWay }; 
     this.SetBinding(PfadProperty, binding); 
    } 
} 

ViewModel.cs

public class ViewModel: INotifyPropertyChanged 
{ 
    private String m_Pfad; 

    public String Pfad 
    { 
     get { return m_Pfad; } 
     set { m_Pfad = value; OnNotifyPropertyChanged("Pfad"); } 
    } 


    public void OnNotifyPropertyChanged(String info) 
    { 
     if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(info)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

Свойство зависимостей отлично работает, но метод сеттер "Pfad" в ViewModel никогда не вызывается вообще.

Заранее благодарен!

+3

Связывание, которое вы создаете в конструкторе View, позже заменяется привязкой, которую вы определяете в MainWindow.xaml. Это не может работать так. Кроме того, вам не нужно поднимать событие PropertyChanged в установщике свойства зависимостей. Он уже предоставляет механизм уведомления об изменениях из коробки. Поэтому вам также не нужно реализовывать INotifyPropertyChanged в представлении класса. – Clemens

+3

В противном случае было бы лучше, если MainWindow и View синхронизировать значения свойств с помощью общей модели представления. – Clemens

+0

Несмотря на то, что я удалил привязку TextBox, метод setter не будет вызываться. Я никогда не слышал об общем взгляде. Я проверю это. У меня эта проблема уже около 3 часов, и все, у кого такая же проблема, исправили это. Я действительно не знаю, чего не хватает. Спасибо, что сообщили мне, что измененная собственность не нужна. –

ответ

1

Подъем PropertyChanged в свойствах CLR свойств зависимостей является распространенной ошибкой. Вы должны не размещать любой код там, так как он не используется связями вообще. Они существуют только для установки свойства один раз в коде или XAML, таким образом, вы также будете не ударить по любым точкам останова, которые вы там установили.


var name = "Pfad"; 
var binding = new Binding(name) { Mode = BindingMode.TwoWay }; 
this.SetBinding(PfadProperty, binding); 

Я понимаю, что вы хотите передать значение на ваш взгляд-модели. Это не будет работать, так как вы можете привязать свойство только один раз. Прямо сейчас вы также связать свойство здесь:

<local:View x:Name="appEntryView" Pfad="{Binding ElementName=tbInput, Path=Text}" Grid.Row="1" Margin="10"/> 

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

Дело в том, что модель вида является частной для View, и в этом случае нет необходимости в синхронизации, если никто не имеет доступа к данным. Вероятно, вы хотите, чтобы свойство было либо установлено снаружи, обрабатывая UserControl больше как элемент управления, отбрасывая модель представления, или вы хотите, чтобы модель представления передавалась извне как DataContext, и представление привязывается непосредственно к ней.


Вы должны быть осторожны с явно устанавливая DataContext из UserControls в их определении, как и it can obfuscate what is happening and lead to bindings unexpectedly breaking.Если вы хотите установить свойства в экземпляре UserControl, я бы рекомендовал его избегать.

+0

Спасибо! Я хочу рассматривать UserControl как элемент управления. Я хочу иметь возможность настраивать UserControl извне, но я также хочу иметь возможность добавлять «пользовательские рабочие процессы» в UserControl. Например, у меня есть кнопка в моем представлении, и команда может быть привязана снаружи к кнопке. Я знаю, это звучит странно, но контроль должен быть очень настраиваемым. Может быть, я не должен использовать MVVM здесь. Также должен быть корневой объект, который постоянно изменяется и должен быть известен из управления хостом (MainWindow.xaml), поэтому мне нужно сделать привязку в любом случае. –

+1

Тогда я бы избавился от модели вида для 'UserControl'; вы можете привязать свойства модели просмотра к экземплярам «снаружи». –

+0

Вы имели в виду, что я не могу связать свойства снаружи? Если да, есть ли какая-либо другая архитектура, которую я могу использовать, или я должен просто поместить все в Code-Behind? Может быть, это будет выглядеть еще лучше, я не знаю. –