【问题标题】:Binding to an element of the DataTemplate on Windows Phone在 Windows Phone 上绑定到 DataTemplate 的元素
【发布时间】:2023-03-08 01:56:01
【问题描述】:

简单明了:我需要将ContextMenu 项目的一些属性绑定到DataTemplate 中其父项的属性。

我找不到访问它的方法,因为ElementName 不起作用,而RelativeSource 允许我只使用SelfTemplatedParent

这是我的代码:

<telerikPrimitives:RadDataBoundListBox Grid.Row="2"
                                       Grid.Column="0"
                                       Grid.ColumnSpan="3"
                                       ItemsSource="{Binding Transfers.Keys, Source={StaticResource TransfersManager}, Mode=OneWay}">
                <telerikPrimitives:RadDataBoundListBox.ItemTemplate>
                    <DataTemplate>
                        <toolkit:TransferControl x:Name="TransferControl"
                            Header="{Binding Converter={StaticResource TransferMonitorToDocumentTitleConverter}}"
                            IsContextMenuEnabled="False"
                            Icon="{Binding Converter={StaticResource TransferMonitorToDocumentIconUriConverter}}"
                            AutoHide="False"
                            Monitor="{Binding}"
                            Language="it-IT"
                            StatusTextBrush="Black"
                            Foreground="Black">
                            <toolkit:TransferControl.HeaderTemplate>
                                <DataTemplate>
                                    <StackPanel>
                                        <toolkit:ContextMenuService.ContextMenu>
                                            <toolkit:ContextMenu>
                                                <toolkit:MenuItem Header="item1"
                                                                  IsEnabled="{Binding Monitor Property in the TransferControl object}"
                                                                  />
                                                <toolkit:MenuItem Header="item2"/>
                                            </toolkit:ContextMenu>
                                        </toolkit:ContextMenuService.ContextMenu>
                                        <Rectangle Fill="Transparent" Height="30"/>
                                        <ContentControl Content="{Binding}"
                                                        HorizontalAlignment="Left"
                                                        VerticalAlignment="Center"
                                                        Foreground="Black" />                                        
                     </StackPanel>
                 </DataTemplate>
             </toolkit:TransferControl.HeaderTemplate>
         </toolkit:TransferControl>
     </DataTemplate>
</telerikPrimitives:RadDataBoundListBox.ItemTemplate>

我要绑定的是:

<toolkit:MenuItem Header="item1" 
                  IsEnabled="{Binding Monitor Property in the TransferControl object}"
                  />

我想将它绑定到&lt;toolkit:TransferControl x:Name="TransferControl" ... /&gt; 对象的Monitor 属性。

【问题讨论】:

  • 你试过IsEnabled="{Binding DataContext.Monitor, ElementName=TransferControl}"。当元素位于另一个项目的 DataTemplate 中时,我没有对其进行测试,但我在绑定到 ListBox 或其他 ItemsControl 时使用了这种方法,例如this post
  • 我现在不能尝试,但如果我没记错的话它会抛出一个异常,说没有 TransferControl 元素,因为它是在 DataTemplate 中定义的

标签: c# xaml windows-phone-8 data-binding


【解决方案1】:

我能够解决这个问题,只需创建一个新的 UserControl 来保存您的 ListBox 的内容。我使用了 LongListSelector。这是一个可行的解决方案。

首先是页面的 XAML:

<phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Items}">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <local:WindowsPhoneControl/>
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>

然后是用户控件。这没什么特别的,只是一个包装。

    <UserControl x:Class="PivotApp1.WindowsPhoneControl"
    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:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">

    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
        <phone:LongListSelector x:Name="TransferControl" Margin="0,0,-12,0"
                                ItemsSource="{Binding Items}"
                                toolkit:TiltEffect.IsTiltEnabled="True">
            <phone:LongListSelector.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <toolkit:ContextMenuService.ContextMenu>
                            <toolkit:ContextMenu>
                                <toolkit:MenuItem Header="item1"
                                                  IsEnabled="{Binding DataContext.Monitor, ElementName=TransferControl}"/>
                                <toolkit:MenuItem Header="item2"/>
                            </toolkit:ContextMenu>
                        </toolkit:ContextMenuService.ContextMenu>
                        <StackPanel Margin="0,0,0,17">
                            <TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                            <TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </phone:LongListSelector.ItemTemplate>
        </phone:LongListSelector>
    </Grid>
</UserControl>

使用此解决方案,在呈现列表时会触发 Monitor 属性。打开菜单时不会被击中。当然,如果您为监视器触发 propertyChanged,它会再次获取该值。

【讨论】:

  • 虽然我也喜欢@yasen 的解决方案,但我决定给你赏金,因为你的似乎是一种可以在各种情况下使用的解决方案。
  • Shawn,请问您对我的解决方案有何看法(如果您有时间看一下 - 只有 Update 之后的部分)?我只是好奇。谢谢。 :)
【解决方案2】:

您要绑定的属性似乎已绑定到 DataContext 本身。为什么不在 HeaderTemplate 中绑定到它(DataContext)?您需要做的就是将 Header 属性绑定到 DataContext,而不是将其转换为其他内容,然后在 HeaderTemplate 中使用 Converter。像这样的:

<telerikPrimitives:RadDataBoundListBox.ItemTemplate>
    <DataTemplate>
        <toolkit:TransferControl x:Name="TransferControl"
                    Header="{Binding}"
                    IsContextMenuEnabled="False"
                    Icon="{Binding Converter={StaticResource TransferMonitorToDocumentIconUriConverter}}"
                    AutoHide="False"
                    Monitor="{Binding}"
                    Language="it-IT"
                    StatusTextBrush="Black"
                    Foreground="Black">
            <toolkit:TransferControl.HeaderTemplate>
                <DataTemplate>
                    <StackPanel>
                        <toolkit:ContextMenuService.ContextMenu>
                            <toolkit:ContextMenu>
                                <toolkit:MenuItem Header="item1"
                                                            IsEnabled="{Binding}"
                                                            />
                                <toolkit:MenuItem Header="item2"/>
                            </toolkit:ContextMenu>
                        </toolkit:ContextMenuService.ContextMenu>
                        <Rectangle Fill="Transparent" Height="30"/>
                        <ContentControl Content="{Binding Converter={StaticResource TransferMonitorToDocumentTitleConverter}}"
                                                HorizontalAlignment="Left"
                                                VerticalAlignment="Center"
                                                Foreground="Black" />
                    </StackPanel>
                </DataTemplate>
            </toolkit:TransferControl.HeaderTemplate>
        </toolkit:TransferControl>
    </DataTemplate>
</telerikPrimitives:RadDataBoundListBox.ItemTemplate>

顺便说一句,我认为您可能做了太多的绑定。绑定和转换器可能会导致性能下降,有时在没有绑定的情况下执行操作会更快、更容易。

顺便问一下,TransferMonitorToDocumentTitleConverter 是做什么的?

更新

工具包中似乎存在错误。 Header 属性的 getter 将对象转换为字符串,因此,即使该属性是 object 类型,您也只能将其设置为字符串 - 否则会在内部使用的 getter 中引发异常。

这是一个可能的解决方法:

  1. 像这样扩展 TransferControl:

    public class TransferControlFixed : TransferControl {
        public static readonly DependencyProperty HeaderFixedProperty = DependencyProperty.Register("HeaderFixed", typeof(object), typeof(TransferControlFixed), new PropertyMetadata(null));
        public object HeaderFixed {
            get {
                return GetValue(HeaderFixedProperty);
            }
            set {
                SetValue(HeaderFixedProperty, value);
            }
        }
    
        public override void OnApplyTemplate() {
            base.OnApplyTemplate();
    
            var control = (ContentControl)this.GetTemplateChild("Header");
            control.SetBinding(ContentControl.ContentProperty, new Binding() {
                Path = new PropertyPath("HeaderFixed"),
                Source = this
            });
        }
    }
    
  2. 使用 TransferControlFixed 代替 TransferControl 并绑定 HeaderFixed 而不是 Header 属性。

这似乎是一个相当简单的解决方法。

【讨论】:

  • 使用你的代码,绑定的属性获得TransferControlHeader的值,而我需要它来获得Monitor的值。转换器是旧版页面遗留下来的东西,我不再使用它了。
  • @StepTNT 我的代码不是 Monitor 和 Header 吗?它们都绑定到 DataContext 对象,我假设它是一个 TransferMonitor 对象,对吧?因此绑定的属性应该与 Monitor 属性具有相同的值。
  • 但它们不可能是一回事。 HeaderstringMonitorTransferMonitor,这就是我在 Header 上使用转换器的原因。如果Header 上没有转换器,它会抛出一个异常,指出TransferMonitor 不能转换为string。但是,使用转换器,MenuItem.IsEnabled 绑定会收到 string 而不是 TransferMonitor
  • @StepTNT 天哪.. 那个工具包... Header 属性的类型是对象,而不是字符串。但是在getter of the property 中有一个字符串转换......因为为什么不呢。我会考虑别的,但这应该是解决方案!
  • 他们现在如何引起痛苦 :D 如果您没有提出可行的解决方案,我想我会构建自己的 TransferControl 组件来删除该演员表,但我想在更改代码之前看看是否有其他方法
猜你喜欢
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-26
  • 2011-02-23
  • 1970-01-01
  • 2021-05-06
  • 1970-01-01
相关资源
最近更新 更多