Предоставление нескольких источников привязки данных

Я чувствую, что мне не хватает довольно фундаментальной концепции WPF, когда дело доходит до привязки данных, но я не могу найти правильную комбинацию ключевых слов Google, чтобы найти то, что мне нужно, поэтому, возможно, сообщество SO может помочь. :)

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

Моя предыдущая попытка выглядит примерно так:

<UserControl.Resources>
    <src:Person x:Key="personSource" />
    <src:Job x:Key="jobSource" />
</UserControl.Resources>
<TextBox Text="{Binding Source={StaticResource personSource}, Path=Name" />
<TextBox Text="{Binding Source={StaticResource jobSource}, Path=Address" />

Это будет привязано к любым значениям по умолчанию. Я даю классы просто отлично, но если я попытаюсь динамически установить объекты в коде (как показано ниже), я не вижу никаких изменений.

Person personSource = FindResource("personSource") as Person;
personSource = externalPerson;
Job jobSource= FindResource("jobSource") as Job;
jobSource = externalJob;

Что мне не хватает?


person Toji    schedule 04.11.2008    source источник


Ответы (2)


Я бы, вероятно, использовал CustomControl с двумя DependencyProperties. Затем внешний сайт, использующий ваш настраиваемый элемент управления, может связать данные, которые им нужны, с этим элементом управления, также с помощью настраиваемого элемента управления вы можете создать шаблон того, как элемент управления выглядит в различных ситуациях.

Пользовательский код управления будет выглядеть примерно так:

public class CustomControl : Control
{
    public static readonly DependencyProperty PersonProperty =
        DependencyProperty.Register("Person", typeof(Person), typeof(CustomControl), new UIPropertyMetadata(null));
    public Person Person
    {
        get { return (Person) GetValue(PersonProperty); }
        set { SetValue(PersonProperty, value); }
    }


    public static readonly DependencyProperty JobProperty =
        DependencyProperty.Register("Job", typeof(Job), typeof(CustomControl), new UIPropertyMetadata(null));
    public Job Job
    {
        get { return (Job) GetValue(JobProperty); }
        set { SetValue(JobProperty, value); }
    }

    static CustomControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
    }
}

Generic.xaml — это файл, который должен быть создан для вас и может иметь стиль, который выглядит примерно так:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication3">


    <Style TargetType="{x:Type local:CustomControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomControl}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <StackPanel>
                            <TextBox Text="{TemplateBinding Person.Name}" />
                            <TextBox Text="{TemplateBinding Job.Address}" />
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Наконец, когда вы собираетесь использовать свой элемент управления, вы должны сделать что-то вроде этого.

<src:CustomControl Person="{Binding Person}" Job="{Binding Job}" />
person Todd White    schedule 04.11.2008
comment
Кажется, это сработает, но теперь у меня другая проблема. Я действительно не хочу использовать стили для привязки этих элементов, но всякий раз, когда я пытаюсь сослаться на новое свойство зависимостей, оно пытается найти его в контексте данных, а не в моем локальном объекте. Как явно указать локальное свойство? - person Toji; 04.11.2008
comment
Можете ли вы дать немного больше контекста того, как вы сейчас пытаетесь это сделать? Возможно, создайте новый вопрос, если этот больше не актуален. - person Todd White; 04.11.2008
comment
Хорошо, я решил это. И этот ответ, и ответ Яна Оукса в сочетании - это то, что решило это для меня, но, поскольку у этого есть более явный код, ответ идет к Тодду. - person Toji; 05.11.2008

Причина, по которой ваши текстовые поля не обновляются, заключается в том, что вы привязываете их к StaticResource. Как следует из названия, эти ресурсы являются статическими и не публикуют уведомления об изменениях. И поскольку Binding является MarkupExtension и не является производным от DependencyObject, вы не можете использовать DynamicResource.

Попробуйте создать свойства зависимостей в вашем элементе управления, чтобы ссылаться на объекты Person и Job.

Затем установите DataContext UserControl для ссылки на самого себя.

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Затем вы можете использовать точечную нотацию для ссылки на необходимые свойства.

<TextBox Text="{Binding Path=Person.Name" />
<TextBox Text="{Binding Path=Job.Address" />

Или используйте исходный параметр

<TextBox Text="{Binding Source=Person, Path=Name" />
<TextBox Text="{Binding Source=Job, Path=Address" />
person Ian Oakes    schedule 04.11.2008