Настройка контекста данных WPF для определенного элемента управления

Я разрабатываю приложение 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;
    }
}

Как видите, у меня есть некоторые свойства, которые объявлены в этом классе, одним из которых является список виджетов. Сам класс Widget также реализует INotifyPropertyChanged и предоставляет около 30 свойств.

Мой пользовательский интерфейс имеет поле со списком, который связан с моим списком виджетов, как это:

MyBusinessObject myBusinessObject = new MyBusinessObject();

public MainWindow()
{
    InitializeComponent();

    this.DataContext = myBusinessObject;

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

Большинство элементов управления в моем пользовательском интерфейсе используются для отображения свойств виджета. Когда мой пользователь выбирает виджет из выпадающего списка, я хочу, чтобы эти элементы управления отображали свойства выбранного виджета. В настоящее время я достигаю этого поведения, обновляя DataContext моего окна в обработчике событий SelectionChanged моего комбинированного списка следующим образом:

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

Это позволяет мне привязать мои элементы управления к соответствующему свойству Widget, например так:

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

Однако не все элементы управления в моем пользовательском интерфейсе используются для отображения свойств виджета. Некоторые элементы управления должны отображать свойства из MyBusinessObject (например, определенное выше MyPropertyName). В этом сценарии я не могу просто сказать:

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

... потому что DataContext окна указывает на выбранный виджет вместо MyBusinessObject. Может кто-нибудь сказать мне, как я устанавливаю DataContext для определенного элемента управления (в XAML), чтобы ссылаться на тот факт, что MyPropertyName является свойством MyBusinessObject? Спасибо!

2 ответа

Решение

Вместо того, чтобы изменять DataContext вашего окна, вы должны добавить свойство в ваш класс MyBusinessObject, например:

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>

Пытаться

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

это работает, если MyBusinessObject является текстовым полем текстового поля, а MyPropertyName является свойством MyBusinessObject.

Также, вот хорошая статья для уточнения связывания

надеюсь это поможет

РЕДАКТИРОВАТЬ 1:

используйте относительную привязку как это:

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

Таким образом, привязка relatve позволяет вам искать визуальное дерево в другом элементе пользовательского интерфейса и использовать его текст данных. Я хотел бы рассмотреть оборачивать содержимое вашего окна в сетку. и смочите данные Windows-контекста для бизнес-объекта и сетки данных-контекста для виджета. Таким образом, вы всегда можете использовать текст данных родительского окна через реальную привязку источника.

поэтому используйте следующее, если datacontext вашего окна является вашим бизнес-объектом

text="{Binding DataContext.MyPropertyName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
Другие вопросы по тегам