Вопрос по wpf, c#, user-controls, data-binding, xaml – Привязка данных в пользовательских элементах управления WPF

28

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

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

Это пользовательский элемент управления 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>

И это код-за:

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 в произвольное значение, это отражается в пользовательском элементе управления.

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

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; }
}

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

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

в окне вывода вы увидите ошибку привязки, что-то вроде объекта MainOptionsPanel не имеет номера свойства - и это правда. просто измените свой usercontrol xaml на это в моем ответе. blindmeis

Ваш Ответ

3   ответа
6

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

= & GT; Делатьnot установитьDataContext вUserControl декларации, использованиеRelativeSource или жеElementName привязки вместо.

На самом деле, наследование DataContext (пока) не то, что я хочу. CustomControls - это другая история. Но для UserControls я расскажу о его хорошей практике.
@mizipzor: плохая практика - задавать DataContext таким, чтобы он был невидимым "извне". и нецелесообразно, поскольку наследование DataContext обычно является тем, чего вы хотите и ожидаете.
@kelmer: да. Это тот же объект, все, что вы делаете в определении, применимо к вашим экземплярам, что в случае установки DataContext, как вы только что показали, является плохой идеей, поскольку перезаписывает унаследованный DataContext.
Почему бы не установить DataContext? Я знаю, что есть способы, которыми он распространяется на дочерние элементы управления (я думаю), но мы до сих пор не сталкивались с какими-либо проблемами в нашем приложении.
Итак, что вы хотите сказать, чтобы удалить строку DataContext из определения Usercontrol? Потому что там я также определил его как RelativeSource. Gabriel Sanmartin
2

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

    public Window1()
    {
        Number= 15;
        DataContext = this;
        InitializeComponent();
    }
Если честно, такой подход плох, потому что вы можете изменить контекст данных извне.
39

Проблема, с которой вы столкнулись, заключается в следующем: в вашем пользовательском контроле вы будете привязывать метку к DP ProtocolNumber вашего пользовательского контроля, а не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>

РЕДАКТИРОВАТЬ: чтобы прояснить некоторые вещи, ваш пользовательский контроль также работает, если вы измените привязку в вашем MainWindow. но вы должны привязать к DataContext MainWindow с помощью RelativeSource.

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

Похожие вопросы