2014-01-06 32 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

当我有类似的问题,我使用。

希望它能帮助!