在XAML中设置元素的DataContext?

6

你好,我正在尝试掌握绑定。

XAML 代码:

<Window x:Class="WPF_SandBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="MainWindow" Height="350" Width="525">
    <StackPanel x:Name="stackPanel">
        <TextBox x:Name="textBox_FirstName" Width="200" Margin="0,100,0,0" Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"  />
        <TextBox x:Name="textBox_LastName" Width="200" Margin="0,10,0,0" Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}" />
        <TextBlock x:Name="textBlock_FullName"  Background="LightBlue" Width="200" Margin="0,10,0,0" Text="{Binding Path=FullName, UpdateSourceTrigger=PropertyChanged}"  />
    </StackPanel>
</Window>

以下是C#代码:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Person person = new Person { FirstName = "Matt", LastName = "Smith" };
            stackPanel.DataContext = person;

        }
    }

    public class Person : INotifyPropertyChanged
    {
        string firstName;
        string lastName;

        public string FirstName
        {
            get
            { 
                return firstName;
            }
            set
            {
                firstName = value;
                OnPropertyChanged("FirstName");
                OnPropertyChanged("FullName");
            }
        }

        public string LastName
        {
            get { return lastName; }
            set
            {
                lastName = value;
                OnPropertyChanged("LastName");
                OnPropertyChanged("FullName");
            }
        }

        public string FullName
        {
            get
            {
                return String.Format("{0}, {1}",lastName,firstName);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }

当启动时,会显示一个有2个文本框和1个文本块的窗口。在窗口构造函数中,我创建了一个Person类的实例,并将stackPanel的DataContext分配给该实例。第一个文本框绑定到Person类的FirstName属性,第二个文本框绑定到LastName属性,最后的TextBlock只打印LastName属性和FirstName属性。正如我之前所说的,我在C#代码中设置了stackPanel的DataContext。如何在XAML中代替设置它?例如:

<StackPanel x:Name="stackPanel" DataContext="person">
        <TextBox x:Name="textBox_FirstName" Width="200" Margin="0,100,0,0" Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"  />
        <TextBox x:Name="textBox_LastName" Width="200" Margin="0,10,0,0" Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}" />
        <TextBlock x:Name="textBlock_FullName"  Background="LightBlue" Width="200" Margin="0,10,0,0" Text="{Binding Path=FullName, UpdateSourceTrigger=PropertyChanged}"  />
    </StackPanel>

这样做不起作用,但是你可以看到我正在尝试在XAML中设置stackPanel的DataContext,我该如何做?

谢谢!


@NETscape 嗯,我目前正在学习如何制作Windows 8商店应用程序,而WPF是其中的重要组成部分。除了MVVM之外,还有什么其他方面值得我关注吗? - Foysal94
阅读MVVM资源将教会您所需了解的内容,同时欢迎您随时加入WPF聊天室 - Kcvin
3个回答

5

这篇简短的文章解释了通过XAML或代码两种设置DataContext的方法。以下是代码:

public class HelloWorldDataContextModel
{
    public string HelloWorld { get; set; }

    public HelloWorldDataContextModel()
    {
        HelloWorld = "Hello world!";   
    }
}

以下是 XAML 代码:

<Window x:Class="HelloWorldDataContext.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:local="clr-namespace:HelloWorldDataContext"        
        Title="MainWindow" Height="350" Width="525">    

    <Window.Resources>
        <local:HelloWorldDataContextModel x:Key="HelloWorldDataContext" />   
    </Window.Resources>    

    <Grid DataContext="{StaticResource HelloWorldDataContext}">        
        <TextBox HorizontalAlignment="Left" Height="23" Margin="222,127,0,0" TextWrapping="Wrap" Text="{Binding HelloWorld}" VerticalAlignment="Top" Width="120"/>    
    </Grid>
</Window>

啊,谢谢。我已经搜索了很久,试图找到一个合适的文章或网站来解释这个问题,但就是找不到。那么,这是推荐的方式/最佳方式吗? - Foysal94
请问您能解释一下这行代码 " xmlns:local="clr-namespace:HelloWorldDataContext" " 的作用吗?另外,Text="{Binding HelloWorld}" 是绑定到 HelloWorldDataContextModel.cs 文件中的 "HelloWorld" 属性吗?什么是静态资源?我已经在谷歌上搜索过了,但是找不到例子来帮助我理解它的语法和作用... - Foysal94

1
补充Abbas的回答,当你有一个无参数构造函数时,你可能会更经常地遇到这种情况,特别是在应用MVVM模式时,你也可以以不同的方式设置控件的DataContext
<Window x:Class="HelloWorldDataContext.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:local="clr-namespace:HelloWorldDataContext"        
        Title="MainWindow" Height="350" Width="525">    

    <Window.DataContext>
        <local:HelloWorldDataContextModel />   
    </Window.DataContext>    

    <Grid>        
        <TextBox HorizontalAlignment="Left" Height="23" Margin="222,127,0,0" TextWrapping="Wrap" Text="{Binding HelloWorld}" VerticalAlignment="Top" Width="120"/>    
    </Grid>
</Window>

你可以使用我的方法或Abbas的方法得到相同的结果;然而,当构造函数需要参数时,这种方式并不值得去尝试。

请问您能解释一下这行代码 " xmlns:local="clr-namespace:HelloWorldDataContext" " 的作用吗?另外,Text="{Binding HelloWorld}" 是绑定到 HelloWorldDataContextModel.cs 文件中的 "HelloWorld" 属性吗?但是您并没有将 DataContext 应用于 Grid 面板?此外,您能否解释一下静态资源是什么,以及我应该如何使用它/语法或者直接指导我一个好的网站来解释它,因为我在谷歌上找不到。 - Foysal94
如果您不明确设置控件(Grid/StackPanel/TextBox等)的DataContext,则它将继承其父控件的DataContext。例如...设置Windows的DataContext,那么其中所有控件都将继承该DataContext。但是,有一个例外,即某些控件不属于Visual Tree,因此不会继承DataContext,例如ContextMenu。 - Lee O.
XAML代码中的"xmlns:local="clr-namespace:HelloWorldDataContext"",类似于C#代码中的"using HelloWorldDataContext",用于导入命名空间HelloWorldDataContext。详情请参考:http://msdn.microsoft.com/zh-cn/library/bb514546(v=vs.90).aspx - Lee O.

0

我不知道你为什么要设置StackPanel的DataContext,虽然你可以设置Window的DataContext并进一步使用它,但如果你仍然想这样做,请尝试下面的代码:

XAML 代码

 <StackPanel x:Name="stackPanel" DataContext="{Binding Person}">

xaml.cs

    public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        Person = new Person { FirstName = "Matt", LastName = "Smith" };
    }
    Person person;
    public Person Person
    {
        get { return person; }
        set { person = value; OnPropertyChanged("Person"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

或者,可以使用窗口的 dataContext,而不是设置 StackPanel 的 DataContext,并像 Person.FirstName 一样绑定 textblock 文本......

<TextBox x:Name="textBox_FirstName" Width="200" Margin="0,100,0,0" Text="{Binding Path=Person.FirstName, UpdateSourceTrigger=PropertyChanged}"  />
    <TextBox x:Name="textBox_LastName" Width="200" Margin="0,10,0,0" Text="{Binding Path=Person.LastName, UpdateSourceTrigger=PropertyChanged}" />
    <TextBlock x:Name="textBlock_FullName"  Background="LightBlue" Width="200" Margin="0,10,0,0" Text="{Binding Path=Person.FullName, UpdateSourceTrigger=PropertyChanged}"  />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接