【问题标题】:How can I bind inside this ControlTemplate?如何在此 ControlTemplate 中进行绑定?
【发布时间】:2015-11-17 20:39:57
【问题描述】:

我有一个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;
    }
}

有问题的最小项目:

Project

【问题讨论】:

  • 你的代码对我来说很好。
  • 请提供MyListItem类代码
  • @VMaleev 编辑了我的问题

标签: xaml listview uwp binding


【解决方案1】:

在处理自定义ControlTemplates 时需要使用{TemplateBinding} 表达式。这会将属性值绑定到与控件实例关联的任何相应属性。

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

您可以在 MSDN 上阅读有关 TemplateBinding 标记表达式的更多信息。

【讨论】:

  • 那我应该把DependencyProperty 放在哪里呢?我不能把它放在我的自定义类中,因为它没有继承任何东西,它只存储了一些属性。此类仅用于创建要在我的ListView中使用的数据列表
  • 这是一个糟糕的解决方案,因为他必须注册他的模板的每个属性
  • 但这就是自定义控件模板的工作方式!实际上听起来您想改用DataTemplatemsdn.microsoft.com/en-us/library/…
  • @JamesWright 我可以将VisualStateManager.VisualStateGroups 代码放在DataTemplate 中吗?我似乎无法让它工作。我需要它根据ListItem 当前所处的状态来更改我的布局。
  • VisualStateManger.GoToElementState 替换您对VisualStateManger.GoToState 的调用可能会做到这一点,因为您可以定位位于另一个元素中的视觉状态。让我知道这对您有什么作用:msdn.microsoft.com/en-us/library/…
【解决方案2】:

ControlTemplate 通常用于定义控件的外观。因此,将 XAML 放入 DataTemplate 并将其分配给 ListView.ItemTemplate 属性会容易得多。您可以从DataTemplate 访问所有自定义属性:

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

更新>>>

您还可以像这样使用ItemContainerStyle 属性中的DataTemplate

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

【讨论】:

  • 是的,我已经尝试过了,但是我无法从我的ControlTemplate 设置前景色。当一个项目被选中时,我使用这个模板来改变外观。
  • 然后将该代码移至DataTemplate。或者,这可能会更好,尝试使用ItemContainerStyle property。这通常用于您想要的...样式化数据项的容器。
  • 我目前正在使用ItemContainerStyle 属性来设置这个ListViewItem 的样式。问题是我不能同时使用{Binding MyProperty}(仅适用于DataTemplate)和ItemContainerStyle 在选择或取消选择ListViewItem 时对其进行样式设置...我要么有默认样式,要么没有绑定。跨度>
【解决方案3】:

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

希望对你有帮助

【讨论】:

  • 很遗憾这是我的错字,所以没有解决方案。
  • 此代码至少适用于两个人。它看起来像测试项目,因此您可以共享问题可重现的整个项目
  • @vrwim MyListItem 是公开的吗?
  • 我正在尝试制作一个测试项目,但它会立即崩溃......当我能够创建所述项目时,我会回复您。
  • 将项目添加到我的问题中。
【解决方案4】:

TextBox 中,使用:

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

【讨论】:

  • 我收到AncestorTypeRelativeSource 上找不到的错误。我正在创建一个通用 Windows 应用程序。
  • 对不起,错过了那个标签...我会编辑答案以获得更好的方法。
  • RelativeSource 使绑定的"DataContext" 成为控件本身,即 ListViewItem。所以现在ListViewItem.Content 属性可用,并将包含您设置为项目内容的对象,因此MyProperty 可用。
  • 嘿@XAMeLi,非常感谢你的朋友!我搜索并工作了过去 3 天,无论我在网上得到什么关于我的问题的信息,每个人都用他自己的哲学解释了它,但是你在样式中的这一单行绑定对我有用......我不能给出你超过+1,否则我会给你100+。再次感谢。上帝祝福你! :)
  • @ZiaUrRahman 很高兴它有帮助。只有一点 - 这在Style 中不起作用,但仅在ControlTemplate 中起作用(也许DataTemplate,但需要检查)。
猜你喜欢
  • 2021-07-26
  • 2020-07-01
  • 1970-01-01
  • 2013-02-23
  • 2018-11-08
  • 2017-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多