2017-08-28 102 views
-1

在WPF中,我一直在試圖弄清楚如何保持一個視圖依賴屬性和它的一個視圖模型的屬性同步一段時間沒有任何運氣。我對這個主題進行了大量的研究,但是沒有一個建議的解決方案適用於我,我希望有人能夠幫助我找到我失蹤的東西。WPF - 如何保持依賴項屬性和視圖模型屬性同步?

我嘗試了很多在這篇文章中建議的東西,Twoway-bind view's DependencyProperty to viewmodel's property?,因爲我看過的所有東西看起來都是最有前途的,但從來沒有能夠得到我期待的結果。

我寫了一個簡單的程序來演示我遇到的問題。其中我將MainWindowViewModel中的屬性IntValue設置爲2,然後將其綁定到在UserControl IncrementIntView中創建的依賴項屬性。然後當我在IncrementIntView中按下按鈕時,它將IntValue的值增加1。這一切工作的用戶控件IncrementIntView裏面很好,但我無法弄清楚如何更新INTVALUE送回MainWindowViewModel,它保持設定爲2

IncrementIntView.xaml.cs

public partial class IncrementIntView : UserControl 
{ 
    public int IntValue 
    { 
     get { return (int)GetValue(IntValueProperty); } 
     set { SetValue(IntValueProperty, value); } 
    } 

    public static readonly DependencyProperty IntValueProperty = 
     DependencyProperty.Register("IntValue", typeof(int), typeof(IncrementIntView), 
             new PropertyMetadata(-1, new PropertyChangedCallback(IntValueChanged))); 

    private static void IntValueChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) 
    { 
     IncrementIntView detailGroup = dependencyObject as IncrementIntView; 
     if (e.NewValue != null) 
     { 
      detailGroup.ViewModel.IntValue = (int)e.NewValue; 
     } 
    } 

    public IncrementIntView() 
    { 
     InitializeComponent(); 
    } 
} 

IncrementIntViewModel.cs

public class IncrementIntViewModel : ViewModelBase 
{ 
    private int intValue; 
    public int IntValue 
    { 
     get { return intValue; } 
     set { SetProperty(ref intValue, value); } 
    } 

    public IncrementIntViewModel() 
    { 
     incrementIntCommand = new Command(IncrementInt); 
    } 

    private Command incrementIntCommand; 
    public Command IncrementIntCommand { get { return incrementIntCommand; } } 
    public void IncrementInt() 
    { 
     IntValue++; 
    } 
} 

IncrementIntView.xaml

<UserControl.DataContext> 
    <local:IncrementIntViewModel x:Name="ViewModel" /> 
</UserControl.DataContext> 

<Grid> 
    <StackPanel Orientation="Horizontal"> 
     <Label Content="{Binding IntValue}" /> 
     <Button Content="Increment" Command="{Binding IncrementIntCommand}" Width="75" /> 
    </StackPanel> 
</Grid> 

MainWindow.xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 
} 

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase 
{ 
    private int intValue = 2; 
    public int IntValue 
    { 
     get { return intValue; } 
     set { SetProperty(ref intValue, value); } 
    } 
} 

MainWindow.xaml

<Window.DataContext> 
    <local:MainWindowViewModel x:Name="ViewModel"/> 
</Window.DataContext> 

<Grid> 
    <StackPanel Margin="10"> 
     <local:IncrementIntView IntValue="{Binding IntValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ElementName=ViewModel}" /> 
     <Label Content="{Binding IntValue}" /> 
    </StackPanel> 
</Grid> 
+0

請注意'ElementName = ViewModel'完全是多餘的。由於MainWindowViewModel實例已分配給Window的DataContext,因此不需要顯式指定Binding源。綁定應該是'IntValue =「{Binding IntValue,Mode = TwoWay}」',因爲'UpdateSourceTrigger = PropertyChanged'也是默認值。 – Clemens

回答

0

我可以看到你的代碼是從MainWindowViewModel的財產傳遞給INTVALUE IncrementIntView的依賴屬性到IncrementIntViewModel的屬性。

遞增按鈕正在更新IncrementIntViewModel的IntValue屬性。不幸的是,IncrementIntViewModel中發生的任何事情都不會反射回IncrementIntView的IntValue依賴項屬性。雙向模式不在IncrementIntView的依賴項屬性和IncrementIntViewModel的屬性之間,但它位於MainWindowViewModel的屬性和IncrementIntView的依賴項屬性之間。

簡單的解決方案:將MainWindow的標籤綁定到IncrementIntViewModel的IntValue屬性而不打擾視圖的屬性。

<local:IncrementIntView x:Name="iiv" IntValue="{Binding IntValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ElementName=ViewModel}" /> 
<Label Content="{Binding DataContext.IntValue, ElementName=iiv}" /> 
<!--You need to specify DataContext.IntValue, because you have same name for both view's dependency property and viewmodel's property--> 

在這裏你可以看到,MainWindowViewModel的INTVALUE並不重要,因爲它只是傳遞給IncrementIntViewModel一次,從來沒有更新過的值的值。

其他解決方案:您需要觸發值更改回MainViewModel的屬性。

首先,MainViewModel和IncrementIntViewModel之間沒有連接。一種解決方案是將MainViewModel設置爲單例,以便在IncrementIntViewModel內完成增量時,還需要更新MainViewModel的屬性。

在MainViewModel.cs

public static MainWindowViewModel SingletonInstance { get; set; } 
public MainWindowViewModel() 
{ 
    if (SingletonInstance == null) 
    { 
     SingletonInstance = this; 
    } 
} 

在IncrementIntViewModel.cs

public void IncrementInt() 
{ 
    IntValue++; 
    MainWindowViewModel.SingletonInstance.IntValue = IntValue; 
} 

另外其他的解決辦法:上述解決方案類似,但我們並不需要作出的Singleton實例MainWindowViewModel,因爲MainWindow是以單例開始的。

在IncrementIntViewModel.cs

public void IncrementInt() 
{ 
    IntValue++; 
    ((MainWindowViewModel)App.Current.MainWindow.DataContext).IntValue = IntValue; 
} 

如果你的意圖是從IncrementViewModel的財產IncrementView的依賴屬性更新INTVALUE,那麼你可能會問,爲什麼你需要這樣做,因爲MVVM應該到V之間的分離和VM。 V應該看虛擬機,但不是相反。

+0

您的其他解決方案和其他解決方案都可以正常工作,但正如您所說這對MVVM無效。我將退後一步並重新評估我的方法。謝謝您的幫助。 – ThatBaldGuy13