WPF中的绑定不按预期工作

时间:2014-01-06 20:24:21

标签: c# wpf silverlight xaml

我有一个MainWindow.xaml,MainwindowViewModel.cs,HaemogramReport.xaml和HaemogramReport.xaml.cs。我的项目中也有其他文件,但问题出在上面提到的四个文件中。 我在这里发布最小代码,以便其他人可以解决问题。

现在在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的Grid的mouseDown处理程序中,我说mwvm.SelectedObj = mouseWasDownOn;

SelectedObj是FrameworkElement类型的属性,它在MainwindowViewModel.cs中声明如下:

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

现在在我的MainWindow中,我有一个网格和一个textBox。有问题的绑定在这里声明。 xaml看起来像:

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

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

使用上面的代码时,我总是在TextBox上面得到Text 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 - 回退值。

如果它不是绑定错误那么上面代码中的问题是什么?

更新

当我调试时,我发现永远不会调用get的{​​{1}}部分。但我不知道为什么?

更新 - Reed Copsey

这是我的新课程:

SelectedObj

我用它像:

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);
    }

}

4 个答案:

答案 0 :(得分: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>

答案 1 :(得分:0)

尝试使用OriginalSource代替来源:

var mouseWasDownOn = e.OriginalSource as FrameworkElement;

因为处理复合控件时Source属性可以是包含OriginalSource对象的父级(在您的情况下是网格)。

答案 2 :(得分:0)

我认为您的错误可能是FrameworkElement没有Text属性http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement(v=vs.110).aspx

enter image description here

编辑:尝试更新Text上的绑定

{Binding SelectedObj.Text}

答案 3 :(得分:0)

我认为您的错误可能是您使用的是“常用”属性而不是DependencyProperties。

正如您在Microsoft说明中看到的那样

  

“当您定义自己的属性并希望它们支持许多属性时   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

或者只是在google上查找Dependency Property WCF。

了解这些属性之间差异的另一个有用链接是

https://stackoverflow.com/a/3674727

我遇到类似问题时使用的。

希望它有所帮助!