Как я могу связать внутри этого ControlTemplate?

У меня есть ListView, заполненный List<MyListItem> и мне нужно использовать ControlTemplate чтобы иметь возможность изменять эффекты при выборе элемента. Теперь у меня проблема в том, что {Binding MyProperty} не работает внутри этого ControlTemplate, Как я могу получить доступ к свойствам MyListItem внутри шаблона?

Мой XAML выглядит так (упрощенно):

<ListView
        Name="ListView"
        Grid.Column="1"
        IsSwipeEnabled="False">

        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListViewItem">
                            <Grid>
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="CommonStates">
                                        <VisualState x:Name="Normal"/>
                                    </VisualStateGroup>
                                    <VisualStateGroup x:Name="SelectionStates">
                                        <VisualState x:Name="Unselected">
                                            <Storyboard>
                                                <ColorAnimation Duration="0" Storyboard.TargetName="myColoredText" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Orange"/>
                                            </Storyboard>
                                        </VisualState>
                                        <VisualState x:Name="SelectedUnfocused">
                                            <Storyboard>
                                                <ColorAnimation Duration="0" Storyboard.TargetName="myColoredText" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Red"/>
                                            </Storyboard>
                                        </VisualState>
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>

                                <!-- Here I have my custom layout, removed for readability -->
                                <TextBlock
                                    Name="myColoredText"
                                    Foreground="Green"
                                    Text="{Binding MyProperty}"/><!-- This does not work -->

                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>

Вот класс, стоящий за этим XAML:

public sealed partial class MyPage : Page
{
    public MyPage()
    {
        InitializeComponent();
        ListView.ItemsSource = new List<MyListItem>()
        {
            new MyListItem("Title1", "SubTitle1"),
            new MyListItem("Title2", "SubTitle2")
        }
    }
}

и класс MyListItem:

class MyListItem
{
    public string MyProperty { get; set; }
    public string MyOtherProperty { get; set; }

    public MyListItem(string myProperty, string myOtherProperty)
    {
        MyProperty = myProperty;
        MyOtherProperty = myOtherProperty;
    }
}

Самый маленький проект с проблемой:

проект

4 ответа

Решение

В TextBox, используйте:

Text="{Binding Content.MyProperty, 
               RelativeSource={RelativeSource TemplatedParent}}"

Wpf поддерживает привязку только к свойствам, а не к полям. Итак, ваш MyItemClass должен быть:

public class MyListItem { 
    public string MyProperty { get; set; } 
    public string MyOtherProperty { get; set; } 

    public MyListItem(string myProperty, string myOtherProperty) {         
        MyProperty = myProperty; 
        MyOtherProperty = myOtherProperty;  
    }
}

Надеюсь, поможет

Вам нужно использовать {TemplateBinding} выражение при работе с обычаем ControlTemplates. Это связывает значения свойств с любыми соответствующими свойствами, связанными с экземпляром элемента управления.

<TextBlock Name="myColoredText"
           Foreground="Green"
           Text="{TemplateBinding MyProperty}" />

Это будет привязано непосредственно к указанному свойству экземпляра в вашем элементе управления. Так как элементы управления WPF/WinRT DependencyObjects, DependencyProperties обычно используются:

public static readonly DependencyProperty MyPropertyProperty = 
    DependencyProperty.Register(
        "MyProperty",
        typeof(Boolean),
        typeof(ListViewItem),
        null
    );

public bool MyProperty
{
    get { return (bool)GetValue(MyPropertyProperty); }
    set { SetValue(MyPropertyProperty, value); }
}

Затем при объявлении нового экземпляра нужно заполнить это свойство, как это стандартно в XAML:

<someNamespace:ListViewItem MyProperty={Binding ViewModelProperty} />

Вы можете прочитать больше о выражении разметки TemplateBinding на MSDN.

ControlTemplate обычно используется для определения того, как должен выглядеть элемент управления. Поэтому гораздо проще поместить свой XAML в DataTemplate и назначить его ListView.ItemTemplate собственность вместо Вы можете получить доступ ко всем вашим пользовательским свойствам из DataTemplate:

<ListView.ItemTemplate>
    <DataTemplate>
        <TextBlock Name="myColoredText" Foreground="Green"
            Text="{Binding MyProperty}" /><!-- This will now work -->
    </DataTemplate>
</ListView.ItemTemplate>

ОБНОВЛЕНИЕ >>>

Вы также можете использовать DataTemplate от ItemContainerStyle свойство как это:

<Style x:Key="SomeStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate DataType="{x:Type Your:DataType}">
                <TextBlock Name="myColoredText" Foreground="Green"
                    Text="{Binding MyProperty}" /><!-- This will now work -->
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>
Другие вопросы по тегам