Как да настроите контекст на данни и персонализирано свързване на потребителски контрол

Не разбирам защо обвързването работи за текстово поле, но не работи за потребителски контрол. На изображението по-долу виждате как трябва да работи. Услугата може да се свърже с жълтия потребителски контрол и този потребителски контрол съдържа свойство от моя собствен клас. В моя случай това свойство се нарича Имейл. Проблемът е, че този имейл никога не се свързва с жълтия потребителски контрол. Ако заменя потребителския контрол с обикновен контрол "TextBox", той работи правилно.

Моля, можете ли да ме посъветвате как да си намеря подвързваща работа?

Описание на потребителския контрол на обвързването

Кодова основа на главната страница на Silvelright

#Region "UserProfile"

    ''' <summary>
    ''' UserProfile Dependency Property
    ''' </summary>
    Public Shared ReadOnly UserProfileProperty As DependencyProperty = _
        DependencyProperty.Register("UserProfile", GetType(ServiceReference1.UserProfile), GetType(MainPage), _
            New Windows.PropertyMetadata(Nothing, _
                AddressOf OnUserProfileChanged))

    ''' <summary>
    ''' Gets or sets the UserProfile property.  This dependency property 
    ''' indicates ....
    ''' </summary>
    Public Property UserProfile() As ServiceReference1.UserProfile
        Get
            Return CType(GetValue(UserProfileProperty), ServiceReference1.UserProfile)
        End Get
        Set(ByVal value As ServiceReference1.UserProfile)
            SetValue(UserProfileProperty, value)
        End Set
    End Property

    ''' <summary>
    ''' Handles changes to the UserProfile property.
    ''' </summary>
    Private Overloads Shared Sub OnUserProfileChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim target As MainPage = CType(d, MainPage)
        Dim oldUserProfile As ServiceReference1.UserProfile = CType(e.OldValue, ServiceReference1.UserProfile)
        Dim newUserProfile As ServiceReference1.UserProfile = target.UserProfile
        target.OnUserProfileChanged(oldUserProfile, newUserProfile)
    End Sub

    ''' <summary>
    ''' Provides derived classes an opportunity to handle changes to the UserProfile property.
    ''' </summary>
    Protected Overridable Overloads Sub OnUserProfileChanged(ByVal oldUserProfile As ServiceReference1.UserProfile, ByVal newUserProfile As ServiceReference1.UserProfile)
        Me.DataContext = newUserProfile

    End Sub

#End Region

при проследяване на свойството, елементът "newUserProfile" беше зададен успешно в codebehind.

XAML

<UserControl x:Class="CH_App.ucUserEditor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                          xmlns:my="clr-namespace:CH_App"

    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox Text="{Binding Path=Email}"/>
        <my:ucDbRow Title="Email" Value="{Binding Path=Email, Mode=TwoWay}" />
    </Grid>
</UserControl>

Texbox с обвързване на имейл работи както трябва и показва имейл адреса. Потребителският контрол не показва имейл адреса. Потребителският контрол показва заглавието правилно.

Потребителски контрол

<UserControl x:Class="CH_App.ucDbRow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:my="clr-namespace:CH_App"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
            DataContext="{Binding RelativeSource={RelativeSource Self}}"
    d:DesignHeight="300" d:DesignWidth="400">

    <StackPanel>
        <TextBlock x:Name="txtTitle" Text="{Binding Path=Title}" />
        <TextBox x:Name="txtValue" Text="{Binding Path=Value, Mode=TwoWay}"/>
    </StackPanel>
</UserControl>

Кодът на потребителския контрол

#Region "Title"

    ''' <summary>
    ''' Title Dependency Property
    ''' </summary>
    Public Shared ReadOnly TitleProperty As DependencyProperty = _
        DependencyProperty.Register("Title", GetType(String), GetType(ucDbRow), _
            New Windows.PropertyMetadata(""))

    ''' <summary>
    ''' Gets or sets the Title property.  This dependency property 
    ''' indicates ....
    ''' </summary>
    Public Property Title() As String
        Get
            Return CType(GetValue(TitleProperty), String)
        End Get
        Set(ByVal value As String)
            SetValue(TitleProperty, value)
        End Set
    End Property

#End Region



#Region "Value"

    ''' <summary>
    ''' Value Dependency Property
    ''' </summary>
    Public Shared ReadOnly ValueProperty As DependencyProperty = _
        DependencyProperty.Register("Value", GetType(String), GetType(ucDbRow), _
            New Windows.PropertyMetadata(""))

    ''' <summary>
    ''' Gets or sets the Value property.  This dependency property 
    ''' indicates ....
    ''' </summary>
    Public Property Value() As String
        Get
            Return CType(GetValue(ValueProperty), Object)
        End Get
        Set(ByVal value As String)
            SetValue(ValueProperty, value)
        End Set
    End Property

#End Region

person Nasenbaer    schedule 16.03.2012    source източник
comment
Това въпрос за WPF ли е или за Silverlight?   -  person NVM    schedule 16.03.2012
comment
Работя върху Silverlight. Но миналия месец имах подобен проблем с WPF, но там направих заобиколно решение без Binding. Сега искам да го поправя, защото съм сигурен, че просто съм пропуснал малка част от декларацията. Сега опитах няколко часа с различни ключови думи за обвързване, но никога не работи.   -  person Nasenbaer    schedule 16.03.2012
comment
Прочетох въпроса два пъти и все още не разбирам какво се опитвате да направите. Предоставете подробности за това, което искате да постигнете първо.   -  person NVM    schedule 16.03.2012
comment
Благодаря за съвета. Ще актуализирам въпроса чрез изображение.   -  person Nasenbaer    schedule 16.03.2012
comment
НП. Мисля, че знам какъв е проблемът ти, но мисля, че правиш неща, които не трябва да правиш. Мисля, че разрешаването на непосредствения ви проблем ще означава да ви позволим да се заровите в по-голяма дупка, отколкото вече сте в нея.   -  person NVM    schedule 16.03.2012
comment
Здравей NVM: Мисля, че обвързването е много ясно и прозрачно и не се чувствам в дупка. Но колкото и просто да работи, просто не прави това, което се очаква. Ако имате някакъв артикул, който не е наред или мостра, би било чудесно. Не обичам да използвам шаблони, мога също да споделя моя проект за изтегляне, ако искате да видите как работи сега.   -  person Nasenbaer    schedule 16.03.2012
comment

addColumnStyleName добавя CSS класа към <col> елемент в DOM и само шепа CSS свойства приложете там (вижте също таблица за съвместимост на браузъри)

Вместо това бихте искали да приложите CSS клас към всяка клетка в колоната, като използвате Column#setCellStyleNames()

  -  person Nasenbaer    schedule 16.03.2012
comment
Защо не харесвате шаблони, те са очевидният начин да отидете?   -  person Phil    schedule 17.03.2012


Отговори (1)


Редактиране (вмъкване):

Вие използвате Silverlight 4 и аз тествах или в Silverlight 5, или в WPF, от които вероятно и двете, но
WPF със сигурност поддържа RelativeSourceBinding по този начин, но вие сте го направили почти правилно.
Прозорецът за изход във Visual Studio ви дава следната грешка, ако не съм прав.

Грешка в System.Windows.Data: Грешка в пътя на BindingExpression:
Свойството „Имейл“ не е намерено на „VisualBasicSilverlightApplication1.ucDbRow“
„VisualBasicSilverlightApplication1.ucDbRow“ (HashCode=72766).
BindingExpression: Path='DataContext. Email'
DataItem='VisualBasicSilverlightApplication1.ucDbRow' (HashCode=72766);
целевият елемент е 'VisualBasicSilverlightApplication1.ucDbRow' (Name='');
целевото свойство е 'Value' (тип 'System. низ')..

DataContext ще премине през потребителската контрола, освен в горното ниво/инстанция на потребителската контрола.
Така че вместо да правите това:

<my:ucDbRow Title="Email" Value="{Binding Path=Email, Mode=TwoWay}" />

Единственото нещо, което ще трябва да промените в кода си, е да посочите елемента, на който сте задали DataContext, който през повечето време е LayoutRoot:
(в ucUserEditor)

<my:ucDbRow Title="Email" Value="{Binding ElementName=LayoutRoot, 
            Path=DataContext.Email, Mode=TwoWay}" />

Предишен отговор
Вие заменяте обвързания контекст на данни с този DataContext="{Binding RelativeSource={RelativeSource Self}}" в CH_App.ucDbRow. Премахнете го и стойността работи, защото сте си върнали подложката DataContext, но Title вече не работи.

Има решение:

Променете ucDbRow на това:

<UserControl x:Class="CH_App.ucDbRow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding}">
    <StackPanel>
      <TextBlock x:Name="txtTitle" Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Title}" Height="23"/>
      <TextBox x:Name="txtValue" Text="{Binding Path=Value, Mode=TwoWay}"/>
    </StackPanel>
  </Grid>
</UserControl>

Забележка: Проверете изходния си прозорец, ако обвързванията не работят, ако не успее, това е в изходния прозорец.

В допълнение:

Бих препоръчал да не се използват потребителски контроли като контроли. Според мен потребителските контроли трябва да се използват повече за представяне на индивидуален контекст, а не половината контекст на един и половината контекст на друг. Започнете да разглеждате потребителските контроли повече като страници и използвайте персонализирани контроли и шаблони за данни за подробна работа. Също така изграждането на по-добро оформление става много лесно с помощта на Grid, което е (отново по мое мнение) една от най-добрите функции в WPF и Silverlight, не може да бъде победено от подредени потребителски контроли.

person Silvermind    schedule 16.03.2012
comment
Здравей Silvermind. Благодаря за вашият отговор. С вас съм относно потребителските контроли, но би разширило въпроса, ако обясня всичко тук. Направих и stackpanel само за въпрос. Нов съм в използването на AncestorType и вече получих съобщение за ГРЕШКА при въвеждане в Silverlight XAML ucDbRow, че AncestorType не е намерен като относителен източник. Някакъв съвет? - person Nasenbaer; 18.03.2012
comment
@Nasenbaer Защото се нуждае от вашето пространство от имена. xmnls:local=clr-namespace:mynamespace и Ancestortype={ x:Type local:ucDbRow} - person Silvermind; 18.03.2012
comment
Между другото: Ако ucDbRow е UserControl (както е представено във вашия пример xaml, предполагам, че да), тогава можете също да посочите думата UserControl като AncestorType. - person Silvermind; 18.03.2012
comment
Може би мисля твърде малко. Но нищо от идеите не проработи: все още не разбирам къде да променя нещо, за да избегна съобщението за грешка на анализатора на XAML, докато се свързва правилно с контекста. Можете ли да актуализирате извадката си с още код? - person Nasenbaer; 20.03.2012
comment
Копирахте ли точно предоставения от мен XAML, защото определено трябва да работи? Освен ако ucDbRow не е UserControl в codebehind, но това трябва да доведе до повече (различни) грешки. В момента нямам време да създам пълен пример. Може би след около 6 часа. - person Silvermind; 20.03.2012
comment
@Nasenbaer Актуализирах отговора си и ако искате, ще публикувам целия код, който направих, но не би трябвало да е необходимо, тъй като този път отговорът трябва да е правилен. :) - person Silvermind; 20.03.2012