Подтвердить что ты не робот

Связывание данных в пользовательских элементах WPF

Я создаю UserControl для серии элементов управления, разделяемых несколькими окнами. Одним из элементов управления является метка, которая показывает поток какого-либо другого процесса с точки зрения "номеров протоколов".

Я пытаюсь предложить DataBinding с этой меткой, чтобы Окно автоматически отражало состояние процесса по мере изменения переменной номера протокола.

Это элемент управления пользователя XAML:

<UserControl Name="MainOptionsPanel"
    x:Class="ExperienceMainControls.MainControls"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    >
<Label Height="Auto" Name="numberLabel">Protocol:</Label>
<Label Content="{Binding Path=ProtocolNumber}" Name="protocolNumberLabel"/>
(...)
</UserControl>

И это Code-Behind:

public partial class MainControls 
{
    public MainControls()
    {
        InitializeComponent();
    }

    public int ProtocolNumber
    {
        get { return (int)GetValue(ProtocolNumberProperty); }
        set { SetValue(ProtocolNumberProperty, value); }
    }

    public static DependencyProperty ProtocolNumberProperty = 
       DependencyProperty.Register("ProtocolNumber", typeof(int), typeof(MainControls));
}

Кажется, что это работает, потому что если в конструкторе я устанавливаю ProtocolNumber на произвольное значение, он отображается в пользовательском элементе управления.

Однако при использовании этого usercontrol в конечном окне происходит срыв привязки данных.

XAML:

<Window x:Class="UserControlTesting.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:expControl="clr-namespace:ExperienceMainControls;assembly=ExperienceMainControls"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    >
    <StackPanel>
        <expControl:MainControls ProtocolNumber="{Binding Path=Number, Mode=TwoWay}" />
    </StackPanel>

</Window>

Код для окна:

public partial class Window1 : Window
{
    public Window1()
    {
        Number= 15;
        InitializeComponent();
    }

    public int Number { get; set; }
}

Это устанавливает номер протокола в ноль, игнорируя значение, установленное на Number.

Я читал пример

4b9b3361

Ответ 1

если вы посмотрите на окно вывода, вы должны увидеть исключение привязки.

У вас есть следующая проблема: в вашем пользовательском управлении вы привяжете метку к DP ProtocolNumber вашего usercontrol, а не к DataContext, поэтому вам нужно добавить, например, имя элемента к привязке.

<UserControl Name="MainOptionsPanel"
    x:Class="ExperienceMainControls.MainControls"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="uc"
    >
<Label Height="Auto" Name="numberLabel">Protocol:</Label>
<Label Content="{Binding Path=ProtocolNumber, ElementName=uc}" Name="protocolNumberLabel"/>
(...)
</UserControl>

EDIT: чтобы очистить некоторые вещи, ваш usercontrol также работает, если вы измените привязку в своем MainWindow. но вы должны привязываться к DataContext MainWindow с RelativeSource.

    <expControl:MainControls ProtocolNumber="{Binding Path=Number, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />

Ответ 2

Что вы имеете в виду:

<expControl:MainControls DataContext="{Binding RelativeSource={RelativeSource Self}}"
                         ProtocolNumber="{Binding Path=Number, Mode=TwoWay}"/>

= > Сделайте не набор объявлений DataContext в UserControl, используйте привязки RelativeSource или ElementName.

Ответ 3

Если вы не указываете RelativeSource привязки, попробуйте установить DataContext в конструкторе:

    public Window1()
    {
        Number= 15;
        DataContext = this;
        InitializeComponent();
    }