在Windows应用商店应用中的ItemTemplate中绑定父DataContext

时间:2015-02-20 13:50:35

标签: c# mvvm windows-store-apps winrt-xaml attached-properties

我在项目模板中绑定ItemTemplates Parent上下文时出现问题。

有很多“变通办法”只适用于WPF(即使用FindAncestorAncestorType)。这是不可能的,因为Windows Store应用程序不支持它。

其他解决方案建议使用ElementName。虽然这适用于Windows应用商店应用,但它不是一个可接受的解决方案,因为它无法重复使用DataTemplates。

我读到的一个解决方案是使用附加属性/附加行为,这听起来像是要走的路,是一种非常通用且可重复使用的方法。但到目前为止,我无法使其发挥作用。

我目前的尝试是创建一个全局附加属性并在ItemTemplate中访问它。

public class GlobalProperties : DependencyObject
{
    public static object GetParentDataContext(DependencyObject obj)
    {
        return (object)obj.GetValue(ParentDataContextProperty);
    }

    public static void SetParentDataContext(DependencyObject obj, object value)
    {
        obj.SetValue(ParentDataContextProperty, value);
    }

    // Using a DependencyProperty as the backing store for ParentDataContext.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ParentDataContextProperty =
        DependencyProperty.RegisterAttached("ParentDataContext",
            typeof(object), 
            typeof(GlobalProperties), 
            new PropertyMetadata(null, ParentDataContextChanged));

    private static void ParentDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SetParentDataContext(d, e.NewValue);
    }
}

我的XAML(通过在ListViews XAML代码中内联DataTemplate进行简化。稍后将其存储在DataTemplate.xaml文件的外部。

    <ListView 
        my:GlobalProperties.ParentDataContext="{Binding}"
        ItemsSource="{Binding Questions}"
        >
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
                <Setter Property="Margin" Value="0,-1,0,0" />
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(my:GlobalProperties.ParentDataContext).Site.Styling.TagBackgroundColor}">
                        <!-- Item Related DataBindings -->      
                    </Grid>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

my是我的GlobalProperties定义的命名空间。

当我在ParentDataContextChanged中有一个断点时,它肯定是用DataContext调用的。但我无法让XAML代码读取它。 Background Xaml属性始终为空,背景始终为白色(TagBackgroundColor属性中保存的颜色为红色)。

有人知道代码/尝试有什么问题吗?

更新 此外Background="{Binding RelativeSource={RelativeSource Self}, Path=(my:GlobalProperties.ParentDataContext).Site.Styling.TagBackgroundColor}"也不起作用,因为大多数网站都会显示此类案例的附加属性。

更新2 ViewModel的示例以便更好地说明

public class QuestionsViewModel : ViewModel 
{
    // Site.Styling.BackgroundColor to be bound to certain ItemTemplate 
    // Properties, but don't have access to it from the ItemTemplate
    // because it has the context of one item from Questions
    public Site Site { get; set; };
    // Questions bound to ListView.DataSource > becomes Item's DataContext
    public IEnumerable<Question> Questions { get; set; };
}

public class Site 
{
    public Style Styling { get; set; }
}

public class Style 
{
    public string ForegroundColor { get; set; }
    public string BackgroundColor { get; set; }
    public string LinkColor { get; set; }
}

1 个答案:

答案 0 :(得分:0)

参考上述评论,我正在提供示例代码。

Main.xaml

<Page
x:Class="TempApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converter="using:TempApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView x:Name="MyList">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
                <Setter Property="Margin" Value="0,-1,0,0" />
            </Style>
        </ListView.ItemContainerStyle>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="ListItemDataTemplateGrid"                           
                      HorizontalAlignment="Stretch">
                    <Grid.Resources>
                        <converter:ValueToBackgroundConverter x:Key="ValueToBackgroundConverter" BackgroundColor="{Binding BgColor}" />
                    </Grid.Resources>
                    <Grid Background="{Binding Converter={StaticResource ValueToBackgroundConverter}}">
                        <!--Your Content-->
                    </Grid>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

Main.xaml.cs

public sealed partial class MainPage : Page
{
    public List<TempList> ListDataSource = new List<TempList>();
    public MainPage()
    {
        this.InitializeComponent();
        FillList();           
    }

    private void FillList()
    {
        ListDataSource.Clear();
        ListDataSource.Add(new TempList { BgColor = "Red" });
        ListDataSource.Add(new TempList { BgColor = "Red" });
        MyList.ItemsSource = ListDataSource;
    }
}

public class TempList
{
    public string BgColor { get; set; }
}

ValueToBackgroundConverter.cs

class ValueToBackgroundConverter : DependencyObject, IValueConverter
    {
        public string BackgroundColor
        {
            get { return (string)GetValue(BackgroundColorProperty); }
            set { SetValue(BackgroundColorProperty, value); }
        }

        public static readonly DependencyProperty BackgroundColorProperty =
         DependencyProperty.Register("BackgroundColor",
                                     typeof(string),
                                     typeof(ValueToBackgroundConverter), null
                                     );

        public object Convert(object value, System.Type targetType, object parameter, string language)
        {
//I've used static colors but you can do manipulations to convert string to color brush
            if (BackgroundColor != null)
                return new SolidColorBrush(Color.FromArgb(0xFF, 0xA3, 0xCE, 0xDC));
            else
                return new SolidColorBrush(Color.FromArgb(0xFF, 0xE3, 0xF0, 0xF4));
        }

        public object ConvertBack(object value, System.Type targetType, object parameter, string language)
        {
            throw new System.NotImplementedException();
        }
    }