【问题标题】:WPF Data Binding Architecture QuestionWPF 数据绑定架构问题
【发布时间】:2011-08-15 19:20:10
【问题描述】:

我正在尝试学习如何使用 WPF 绑定和 MVVM 架构。我在依赖属性方面遇到了一些麻烦。我试图通过将项目绑定到 DataContext 中的 DependencyProperty 来控制视图上项目的可见性,但它不起作用。无论我在下面视图模型的构造函数中将GridVisible 值设置为什么,在我运行代码时它始终显示为可见。

谁能看出我哪里出错了?

C# 代码(视图模型):

public class MyViewModel : DependencyObject
{
    public MyViewModel ()
    {
        GridVisible = false;
    }

    public static readonly DependencyProperty GridVisibleProperty =
    DependencyProperty.Register(
        "GridVisible",
        typeof(bool),
        typeof(MyViewModel),
        new PropertyMetadata(false,
                new PropertyChangedCallback(GridVisibleChangedCallback)));

    public bool GridVisible
    {
        get { return (bool)GetValue(GridVisibleProperty); }
        set { SetValue(GridVisibleProperty, value); }
    }

    protected static void GridVisibleChangedCallback(
        DependencyObject source,
        DependencyPropertyChangedEventArgs e)
    {
        // Do other stuff in response to the data change.
    }
}

XAML 代码(查看):

<UserControl ... >

    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
    </UserControl.Resources>

    <UserControl.DataContext>
        <local:MyViewModel x:Name="myViewModel" />
    </UserControl.DataContext>

    <Grid x:Name="_myGrid"
        Visibility="{Binding Path=GridVisible,
            ElementName=myViewModel,
            Converter={StaticResource BoolToVisConverter}}">

        <!-- Other elements in here -->

    </Grid>

</UserControl>

我查看了一些在线教程,似乎我正确地遵循了我在那里找到的内容。有任何想法吗?谢谢!

【问题讨论】:

    标签: c# wpf xaml dependency-properties datacontext


    【解决方案1】:

    从绑定中删除 ElementName,这似乎不正确。 将其更改为:

    <Grid x:Name="_myGrid"
            Visibility="{Binding Path=GridVisible,
                Converter={StaticResource BoolToVisConverter}}">
    

    【讨论】:

    • 实际上,我将您的代码复制了出来,发现它适用于包含和不包含 ElementName 的绑定。您在什么上使用用户控件(即窗口或其他用户控件)?也许那里有问题(您未包含的代码)。
    • 我删除了 ElementName 但它仍然不起作用。看起来你是对的——它可能与我的代码的另一部分有关,而不是上面发布的净化版本。不幸的是,我无法发布实际代码,因为它是为了工作。
    • 在这种情况下,当您运行应用程序并打开包含此用户控件的窗口时,请在 VisualStudio 中的“输出”窗口中查找任何带有类似于此“BindingExpression 路径错误:”文本的错误在“对象......”上找不到 GridVisible 属性,该消息的内容可能会帮助您进一步调试它。对不起,我不能帮助你更多。祝你好运。
    • 你是对的,这是一个错字!我在调试模式下运行时检查了输出窗口,发现我拼错了我的一个数据绑定。它现在完美运行。谢谢!
    【解决方案2】:

    将 ViewModel 设置为 DataContext 的目的是启用简单的相对绑定,您仅指定 Path 的所有绑定都将 DataContext 作为源,它在整个 UserControl 中继承(除非另有设置,例如在ItemsControl 的模板项)

    因此,一旦在 UserControl 上设置了 DataContext,您通常在绑定到 VM 时不会指定任何源。 (来源为ElementNameRelativeSourceSource

    此外,我个人不会让 ViewModels 从 DependencyObject 继承,因为这引入了线程关联性,而且 DependencyProperties 的重点是通过不在所有数据结构中创建不必要的字段来提高稀疏数据结构的效率(ViewModels 通常正好相反的稀疏)。

    【讨论】:

    • INotifyPropertyChangedDependencyObject 的替代品 - 大多数视图模型使用它而不是依赖属性。
    【解决方案3】:

    让您的 ViewModel 实现 INotifyPropertyChanged,而不是从 DependencyObject 继承。 实现接口并从您的属性设置器中引发 PropertyChanged。

        private bool gridVisible;
    
        public bool GridVisible
        {
            get { return gridVisible; }
            set 
            { 
                gridVisible = value; 
                OnPropertyChanged("GridVisible"); 
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    【讨论】:

    • 您无需在 XAML 中使用 ElementName 引用您的 VM,也无需命名您的 VM。当您将其分配给 usercontrol.DataContext 时,它将成为用户控件的所有子项的默认绑定源。
    猜你喜欢
    • 2011-10-18
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多