wpf проблема с использованием свойств зависимости в UserControl - PullRequest
8 голосов
/ 18 июля 2009

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

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

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 для Window, который ссылается на 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">

Затем пользователь сам контролирует:

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

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

Ответы [ 3 ]

9 голосов
/ 21 июля 2009

Оказывается, что в 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 голосов
/ 18 июля 2009

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

<Label Width="100" Height="30" Name="fieldValueLabel"
       Content="{Binding Path=fieldValue, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DAS1.LabeledField}}}" />
4 голосов
/ 18 июля 2009

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

Вы должны определить свой 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 и, таким образом, поддерживает обновления для привязки - без него система привязки не получает уведомление при изменении значения вашего поля, независимо от того, привязали ли вы его к DependencyProperty на одном конце .

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

...