Вопрос по dependency-properties, wpf, user-controls – wpf проблема с использованием свойств зависимости в UserControl

8

Я сделал UserControl, который должен обновляться каждые несколько секунд данными из последовательного порта. Этот UserControl должен быть очень простым, состоящим из метки для имени поля и другой метки, содержащей значение поля. Я говорю что этоshould быть простым, но это не работает. Он вообще не обновляется и даже не отображает имя поля.

Ниже приведен код:

public partial class LabeledField : UserControl {

    public LabeledField() {
        InitializeComponent();
    }

    public string fieldName { 
        get { return fieldNameLabel.Content.ToString(); } 
        set { fieldNameLabel.Content = value; } 
    }

    public string fieldValue { 
        get { return (string)GetValue(fieldValueProperty); } 
        set { SetValue(fieldValueProperty, value); }
    }

    public static readonly DependencyProperty fieldValueProperty =
        DependencyProperty.Register(
            "fieldValue", 
            typeof(string), 
            typeof(LabeledField),
            new FrameworkPropertyMetadata(
                "No Data"
            )
        )
    ;
}

Вот XAML:

<UserControl x:Class="DAS1.LabeledField" Name="LF"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Orientation="Horizontal">
    <Label Width="100" Height="30" Background="Gray" Name="fieldNameLabel" />
    <Label Width="100" Height="30" Background="Silver" Name="fieldValueLabel" Content="{Binding fieldValue}" />
</StackPanel>

А вот XAML для окна, которое ссылается на UserControl. Сначала заголовок:

<Window x:Class="DAS1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:me="clr-namespace:DAS1"
Title="Window1" Height="580" Width="780">

Затем сам UserControl:

<me:LabeledField fieldName="Test" Width="200" Height="30" fieldValue="{Binding businessObjectField}"/>

Если бы я знал о более конкретном вопросе, который я хотел бы задать, я бы - но кто-нибудь может сказать мне, почему это не работает?

Ваш Ответ

3   ответа
5

вы должны указать это в привязке. Привязки оцениваются относительноDataContext если их источник не указан явно, значит, ваша привязка связана не с вашим элементом управления, а с унаследованным контекстом (в котором, вероятно, отсутствует свойство, к которому вы привязываете). Что вам нужно это:

<Label Width="100" Height="30" Name="fieldValueLabel"
       Content="{Binding Path=fieldValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DAS1.LabeledField}}}" />
9

что в XAML для пользовательского элемента управления привязка была указана неправильно.

Изначально это было:

<Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding fieldValue}" />

Но я не указал элемент, которому принадлежит fieldValue. Так и должно быть (при условии, что мой пользовательский элемент управления называется «LF»:

<Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding ElementName=LF, Path=fieldValue}" />
Спасибо! Простое исправление было именно то, что мне было нужно.
В заключение! Потратил 5 часов на то, чтобы разобраться. TNX!
4

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

Вы должны определить свой UserControl следующим образом (без кода):

<UserControl x:Class="DAS1.LabeledField"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel Orientation="Horizontal">
        <Label Width="100" Height="30" Name="fieldNameLabel" Content="{Binding fieldName}" />
        <Label Width="100" Height="30" Name="fieldValueLabel" Content="{Binding field}" />
</StackPanel>

Затем убедитесь, что ваш бизнес-объект реализует INotifyPropertyChanged, потому что вы не можете эффективно обновить свой бизнес-объект, не изменив его хотя бы так сильно.fieldName Это всего лишь пример того, как можно автоматически привязать отображаемое имя на метке к свойству вашего бизнес-объекта.

Затем просто убедитесь, что DataContext вашего UserControl является вашим бизнес-объектом.

Как это будет работать? Свойство Label.Content является DependencyProperty и будет поддерживать само связывание. Ваш бизнес-объект реализует INotifyPropertyChanged и, таким образом, поддерживает обновления для привязки -without it, the binding system does not get notified when your field's value changes, regardless if you bound it to a DependencyProperty on one end.

А если вы хотите повторно использовать этот пользовательский элемент управления в другом месте, просто поместите нужный экземпляр вашего бизнес-объекта в DataContext требуемого элемента управления LabeledField. Привязка будет подключена из DataContext.

Как вы связываете со свойствами пользовательского элемента управления без свойств зависимости? Я цитирую полученную ошибку:System.Windows.Markup.XamlParseException: 'A 'Binding' cannot be set on the 'BranchId' property of type 'BranchFilter'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.'
Мне действительно нравится это решение, но это решение не очень подходит для пользовательских элементов управления, которые предназначены для многократного использования / использования в одном и том же U.I. Каждый экземпляр будет использовать одни и те же привязки. Что если разработчик захочет вставить разные строковые данные в каждый экземпляр данного пользовательского элемента управления? Это решение в теории не должно работать.
Мне нравится ваше решение, потому что оно простое. Однако я попытался реализовать это, но безуспешно. XAML для LabeledField выглядит именно так, как вы предложили. Код позади теперь содержит только конструктор, который вызывает «InitializeComponents ()», который используется по умолчанию. XAML из Window1 выглядит следующим образом: & quot; & lt; me: LabeledField fieldName = & quot; Test & quot; fieldValue = & quot; {Binding point.lat} & quot; Ширина = & Quot; 200 & Quot; Высота = & Quot; 30 & Quot; / & GT; & Quot; Это дает мне ошибки, которые говорят "свойство" fieldName "/" fieldValue "; не был найден в типе «LabeledField». Есть еще предложения? Klay
У вас должен быть бизнес-объект, который предоставляет поле & quot; поле & quot; и & quot; fieldName & quot; свойства и установите этот объект как DataContext элемента управления LabeledField. Например, "открытый класс BusinessObject {публичная строка fieldName {get {return & quot; Text & quot ;;" }} public int field {get {return 30; }}} & quot; в коде, затем в xaml: & lt; DAS1: LabeledField DataContext = & quot; {Binding * / указать здесь путь к объекту * /} & quot; / & gt; & quot;

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