为特定控件设置WPF datacontext

时间:2013-12-09 20:11:24

标签: wpf xaml data-binding datacontext

我正在开发一个WPF应用程序,我正在努力了解DataContext的一些细节,因为它适用于绑定。我的应用程序使用一个业务对象,其定义如下:

public class MyBusinessObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

    // enumerations for some properties
    public enum MyEnumValues
    {
        [Description("New York")]
        NewYork,
        [Description("Chicago")]
        Chicago,
        [Description("Los Angeles")]
        LosAngeles
    }

    // an example property
    private string _myPropertyName;
    public string MyPropertyName
    {
        get { return _myPropertyName; }
        set
        {
            if (_myPropertyName == value)
            {
                return;
            }

            _myPropertyName = value;
            OnPropertyChanged(new PropertyChangedEventArgs("MyPropertyName"));
        }
    }

    // another example property
    private MyEnumValues _myEnumPropertyName;
    public MyEnumValues MyEnumPropertyName
    {
        get { return _myEnumPropertyName; }
        set
        {
            if (_myEnumPropertyName== value)
            {
                return;
            }

            _myEnumPropertyName= value;
            OnPropertyChanged(new PropertyChangedEventArgs("MyEnumPropertyName"));
        }
    }

    // example list property of type Widget
    public List<Widget> MyWidgets { get; set; }

    // constructor
    public MyBusinessObject()
    {
        // initialize list of widgets
        MyWidgets = new List<Widget>();

        // add 10 widgets to the list
        for (int i = 1; i <= 10; i++)
        {
           MyWidgets.Add(new Widget());
        }

        // set default settings
        this.MyPropertyName = string.empty;
    }
}

如您所见,我有一些在此类中声明的属性,其中一个是Widgets列表。 Widget类本身也实现了INotifyPropertyChanged并公开了大约30个属性。

我的UI有一个组合框,它绑定到我的Widgets列表,如下所示:

MyBusinessObject myBusinessObject = new MyBusinessObject();

public MainWindow()
{
    InitializeComponent();

    this.DataContext = myBusinessObject;

    selectedWidgetComboBox.ItemsSource = myBusinessObject.MyWidgets;
    selectedWidgetComboBox.DisplayMemberPath = "WidgetName";
    selectedWidgetComboBox.SelectedValuePath = "WidgetName";
}

我的UI上的大多数控件都用于显示Widget的属性。当我的用户从组合框中选择一个Widget时,我希望这些控件显示所选Widget的属性。我目前通过在我的组合框的SelectionChanged事件处理程序中更新我的窗口的DataContext来实现此行为,如下所示:

private void selectedWidgetComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    this.DataContext = selectedWidgetComboBox.SelectedItem;
}

这允许我将我的控件绑定到适当的Widget属性,如下所示:

<TextBox Text="{Binding WidgetColor}"></TextBox>

但是,并非我的UI中的所有控件都用于显示窗口小部件属性。某些控件需要显示MyBusinessObject的属性(例如:上面定义的MyPropertyName)。在这种情况下,我不能简单地说:

<TextBox Text="{Binding MyPropertyName}"></TextBox>

...因为窗口的DataContext指向选定的Widget而不是MyBusinessObject。谁能告诉我如何为特定控件(在XAML中)设置DataContext以引用MyPropertyName属于MyBusinessObject的属性?谢谢!

2 个答案:

答案 0 :(得分:3)

您应该向MyBusinessObject类添加一个属性,而不是更改窗口的DataContext:

private Widget _selectedWidget;
public Widget SelectedWidget
{
    get { return _selectedWidget; }
    set
    {
        if (_selectedWidget == value)
        {
            return;
        }

        _selectedWidget = value;
        OnPropertyChanged(new PropertyChangedEventArgs("SelectedWidget"));
    }
}

然后将SelectedWidget绑定到组合框的SelectedItem属性。您需要使用小部件属性的任何地方,您可以这样做:

<TextBox Text="{Binding Path=SelectedWidget.WidgetColor}"></TextBox>

答案 1 :(得分:1)

尝试

<TextBox Text="{Binding MyBusinessObject.MyPropertyName}"></TextBox>

如果MyBusinessObject是文本框的datacontext而MyPropertyName是MyBusinessObject的属性

,则此方法有效

此外,Here is a good article to clarify binding

希望这会有所帮助

编辑1:

使用这样的相对绑定:

text="{Binding DataContext.MyPropertyName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TypeOfControl}}}"

因此,relatve绑定允许您将可视树查找到另一个UI元素并使用其datacontext。我会考虑将窗口的内容包装在网格中。并将windows datacontext润湿到businessobject,将网格datacontext润湿到小部件。这样,您始终可以通过实际源绑定使用父窗口的datacontext。

如果您的窗口的datacontext是您的业务对象,请使用以下内容

text="{Binding DataContext.MyPropertyName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"