2014-01-06 70 views
2

我有一個MainWindow.xaml,MainwindowViewModel.cs,HaemogramReport.xaml和HaemogramReport.xaml.cs。我的項目中也有其他文件,但問題在於上述四個文件。 我在這裏發佈最小代碼,以便其他人可以發現問題。在WPF綁定不按預期工作

現在HaemogramReport.xaml我宣佈一些控件像GridTextBoxTextBlockRectangleBorderContentControl

例如HaemogramReport.xaml樣子:

<Page.DataContext> 
    <vm:MainWindowViewModel /> 
</Page.DataContext> 

<Grid DataContext="{Binding Source={StaticResource Settings}}" PreviewMouseDown="Object_Selection" x:Name="Root"> 

    <Border Style="{StaticResource BorderStyle}" x:Name="HaemogramTestBorder" 
      Grid.Row="{Binding Default.HaemogramTestGridRow}" Grid.Column="{Binding Default.HaemogramTestGridColumn}" 
      Grid.RowSpan="{Binding Default.HaemogramTestGridRowSpan}" Grid.ColumnSpan="{Binding Default.HaemogramTestGridColumnSpan}"> 
     <Grid> 
      <Rectangle Fill="Transparent" x:Name="HaemogramTestRectangle"/> 
      <TextBlock x:Name="HaemogramTestTextBlock" 
         Text="{Binding Default.HaemogramTestText}" Visibility="{Binding Default.HaemogramTestVisibility}" 
         Background="{Binding Default.HaemogramTestBackground, Converter={StaticResource colorToSolidColorBrushConverter}}" 
         Foreground="{Binding Default.HaemogramTestForeground, Converter={StaticResource colorToSolidColorBrushConverter}}" 
         FontFamily="{Binding Default.HaemogramTestFontFamily, Converter={StaticResource stringToFontFamilyConverter}}" 
         FontSize="{Binding Default.HaemogramTestFontSize}" 
         FontWeight="{Binding Default.HaemogramTestFontWeight}" FontStyle="{Binding Default.HaemogramTestFontStyle}" 
         HorizontalAlignment="{Binding Default.HaemogramTestHorizontalAlignment}" 
         VerticalAlignment="{Binding Default.HaemogramTestVerticalAlignment}" 
         Margin="{Binding Default.HaemogramTestMargin}" /> 
     </Grid> 
    </Border> 

</Grid> 

當我點擊任何的上述聲明元素中的元素將引發名爲Root的網格的mousedown事件。

該事件處理程序在HaemogramReport.xmal.cs中。那就是:

private void Object_Selection(object sender, MouseButtonEventArgs e) 
{ 
    var mouseWasDownOn = e.Source as FrameworkElement; 

    if (mouseWasDownOn != null) 
    { 

     foreach (Border border in FindVisualChildren<Border>(Root)) 
     { 
      border.BorderBrush = Brushes.Transparent; 
     } 

     if (!(mouseWasDownOn is Border)) 
     { 
      FindParent<Border>(mouseWasDownOn).BorderBrush = Brushes.Orange; 
     } 

     MainWindowViewModel mwvm = new MainWindowViewModel(); 
     mwvm.SelectedObj = mouseWasDownOn; 

    } 
} 

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject 
{ 
    if (depObj != null) 
    { 
     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
      if (child != null && child is T) 
      { 
       yield return (T)child; 
      } 

      foreach (T childOfChild in FindVisualChildren<T>(child)) 
      { 
       yield return childOfChild; 
      } 
     } 
    } 
} 

public static T FindParent<T>(DependencyObject child) where T : DependencyObject 
{ 
    //get parent item 
    DependencyObject parentObject = VisualTreeHelper.GetParent(child); 

    //we've reached the end of the tree 
    if (parentObject == null) return null; 

    //check if the parent matches the type we're looking for 
    T parent = parentObject as T; 
    if (parent != null) 
     return parent; 
    else 
     return FindParent<T>(parentObject); 
} 

在鼠標按下電網的處理器命名Root,我說mwvm.SelectedObj = mouseWasDownOn;

SelectedObj是在MainwindowViewModel.cs聲明類型FrameworkElement的的屬性如下:

private FrameworkElement selectedObj; 
public FrameworkElement SelectedObj 
{ 
    get 
    { 
     return selectedObj; 
    } 
    set 
    { 
     selectedObj = value; 
     OnPropertyChanged("SelectedObj"); 
    } 
} 

現在我的主窗口我有例如一個網格和一個文本框在裏面。有問題的綁定在這裏聲明。 XAML的樣子:

<Window.DataContext> 
    <vm:MainWindowViewModel /> 
</Window.DataContext> 

<Grid DataContext="{Binding SelectedObj, UpdateSourceTrigger=PropertyChanged}"> 
    <TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged, TargetNullValue='null', FallbackValue='Error'}"/> 
</Grid> 

當使用上面的代碼,我總是在上面的文本框中的文本Error

當時我認爲這可能是綁定錯誤的第一次機會,讓我改變了我的MainWindowViewModel.cs如下:

public class MainWindowViewModel : INotifyPropertyChanged 
{ 
    public MainWindowViewModel() 
    { 
     SelectedObj = txt; 
    } 

    TextBlock txt = new TextBlock() 
    { 
     Text = "123" 
    }; 

    private FrameworkElement selectedObj; 
    public FrameworkElement SelectedObj 
    { 
     get 
     { 
      return selectedObj; 
     } 
     set 
     { 
      selectedObj = value; 
      OnPropertyChanged("SelectedObj"); 
     } 
    } 
} 

作出上述改變後,當我跑我的項目,我可以在文本框中看到123但當我點擊任何元素時,文本框中的文本不會改變。

現在這裏的問題是,如果它的綁定錯誤,那麼爲什麼在第二個例子中,我在文本框中獲得123,而在第一個示例中,我獲得Error - 回退值。

如果它不是一個綁定錯誤,那麼上述代碼中的問題是什麼?

更新

當我調試,我發現SelectedObjget一部分不會被調用。但我不知道爲什麼?

更新 - 裏德科普塞

這是我的新類:

public class DesignMethods 
{ 

    public static void FindCurrentlyClickedElement(DependencyObject Root, MouseButtonEventArgs e, MainWindowViewModel vm) 
    { 
     var mouseWasDownOn = e.OriginalSource as FrameworkElement; 

     if (mouseWasDownOn != null) 
     { 

      foreach (Border border in FindVisualChildren<Border>(Root)) 
      { 
       border.BorderBrush = Brushes.Transparent; 
      } 

      if (!(mouseWasDownOn is Border)) 
      { 
       FindParent<Border>(mouseWasDownOn).BorderBrush = Brushes.Orange; 
      } 

      vm.SelectedObj = mouseWasDownOn; 

     } 
    } 

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj != null) 
     { 
      for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
      { 
       DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
       if (child != null && child is T) 
       { 
        yield return (T)child; 
       } 

       foreach (T childOfChild in FindVisualChildren<T>(child)) 
       { 
        yield return childOfChild; 
       } 
      } 
     } 
    } 

    public static T FindParent<T>(DependencyObject child) where T : DependencyObject 
    { 
     //get parent item 
     DependencyObject parentObject = VisualTreeHelper.GetParent(child); 

     //we've reached the end of the tree 
     if (parentObject == null) return null; 

     //check if the parent matches the type we're looking for 
     T parent = parentObject as T; 
     if (parent != null) 
      return parent; 
     else 
      return FindParent<T>(parentObject); 
    } 

} 

我用它喜歡:

private void Object_Selection(object sender, MouseButtonEventArgs e) 
{ 
    DesignMethods.FindCurrentlyClickedElement(Root, e, this.DataContext as MainWindowViewModel); 
} 

回答

2

問題是你創建ViewModel的新實例,不使用現有的實例:

// This is not the same instance you're binding to! 
// MainWindowViewModel mwvm = new MainWindowViewModel(); 

// Get the existing one instead 
var mwvm = this.DataContext as MainWindowViewModel; 
mwvm.SelectedObj = mouseWasDownOn; 

請注意,儘管這裏我可能不會使用術語「ViewModel」。你正在做的事情非常不是典型的MVVM場景,因爲你將DataContext實例緊密地耦合到你的View中,而耦合是在兩個方向上發生的,這幾乎與MVVM的正常目標相反。


編輯:

您可能還需要更新您的綁定SelectedObj。我建議用XAML組試圖:

<Grid> 
    <TextBox Text="{Binding SelectedObj.Text, UpdateSourceTrigger=PropertyChanged, TargetNullValue='null', FallbackValue='Error'}"/> 
</Grid> 
+0

2天前我問了這個問題。現在我已經在一個新類中移動了Object_Selection,這樣我就可以在很多地方使用它了。此外,我已將此方法標記爲「靜態」。我不能使用'this'。所以我想我應該通過'MainWindowViewModel'的Current Instance,並且我已經這樣做了。但是我仍然沒有對輸出做任何改變。 – Khushi

+0

有關更多詳細信息,請參閱更新後的問題。另外我在xaml中聲明瞭我的datacontext。這會影響你提到的代碼嗎? – Khushi

+0

@Khushi您確定要更改虛擬機的正確實例嗎?如果你在setter中放置一個斷點,你會看到這個變化嗎? –

0

嘗試使用OriginalSource,而不是來源:

var mouseWasDownOn = e.OriginalSource as FrameworkElement; 

因爲處理複合控件時的Source屬性可以是包含OriginalSource對象(在您的情況下是網格)的父類。

+0

不,我調試時我在那裏保留了一個斷點,我認爲mouseWasDownOn中的值始終是我點擊的元素。我的意思是我不認爲你提到的代碼是問題的原因。 – Khushi

0

我認爲你的錯誤可能是FrameworkElement的不具有Text屬性http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement(v=vs.110).aspx

enter image description here

編輯:嘗試更新上的文字你的綁定是

{Binding SelectedObj.Text} 
+0

是的,你在某種程度上是正確的,所以我用Object替換了FrameworkElement。並且對象具有文本屬性。 – Khushi

+0

當您將文本綁定到{Binding SelectedObj.Text} – DLeh

+0

時,會發生什麼?我正在檢查它。 – Khushi

0

我認爲你的錯誤可能是你使用的是「共同」的屬性,而不是DependencyProperties。

正如你可以在微軟描述見

「當你定義自己的屬性,並希望他們支持的Windows Presentation Foundation(WPF)的功能, 的許多 方面,包括樣式,數據綁定,繼承,動畫和默認值 值,您應該將它們實現爲依賴項屬性。「

這些都是正確類型的屬性,以充分利用通過WPF

提供的所有資源,在這些環節

http://msdn.microsoft.com/en-us/library/system.windows.dependencyproperty(v=vs.110).aspx

http://msdn.microsoft.com/en-us/library/ms750428(v=vs.110).aspx

或者乾脆尋找依賴看看在谷歌的財產WCF。

另一種有用的鏈接理解這些特性之間的差是

https://stackoverflow.com/a/3674727

當我有類似的問題,我使用。

希望它能幫助!