【问题标题】:C# - Adding XAML elements to UWP app via x:BindC# - 通过 x:Bind 将 XAML 元素添加到 UWP 应用程序
【发布时间】:2018-08-05 22:01:14
【问题描述】:

上下文:我正在编写一个 UWP Twitter 客户端。

Twitter 通过其 API 返回的有用数据位之一是可以在推文中直接链接的内容对象 - #hashtags、@usernames、$symbols 和 URL。这使得从包含推文全文的字符串中提取这些对象变得容易,以便将它们转换为链接。

我了解 XAML 如何使用 <run><hyperlink> 标记来查找此内容,并且我已经弄清楚如何为每个推文对象动态创建 XAML。

我不知道如何将生成的 XAML 注入我的应用程序的 DataTemplate。因为需要在应用程序的多个页面上显示推文内容,所以我使用 ResourceDictionary 来保存我的所有 XAML 样式,包括我的 DataTemplate。所以,我完全不确定如何将我生成的 XAML 连接到我的应用程序的 UI。

例如,如果一条推文如下所示:

“嘿@twitter,你在浪费时间!#FridayFeeling”

我生成的 XAML 对象如下所示:

<Run>Hey </Run>
<Hyperlink link="http://twitter.com/twitter/">@twitter</Hyperlink>
<Run>, you're a time waster! </Run>
<Hyperlink link="http://twitter.com/search?hashtag=FridayFeeling">#FridayFeeling</Hyperlink>

如果推文的文本中没有可链接的内容,那么我可以按原样使用Tweet.Text,因此我尝试将其绑定到TextBox。如何处理动态插入此 XAML?

我是否坚持完全放弃数据绑定并循环通过我的集合以编程方式添加我的所有 XAML?

这是我的数据模板:

<DataTemplate x:Key="TweetTemplate" x:DataType="tweeter:Tweet2">
    <Grid Style="{StaticResource ListItemStyle}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" x:Name="RetweetedBy" x:Load="{x:Bind IsRetweet}" Height="28">
            <StackPanel Orientation="Horizontal" Padding="4 8 4 0">
                <StackPanel.Resources>
                    <Style TargetType="TextBlock">
                        <Setter Property="FontSize" Value="12"/>
                        <Setter Property="Foreground" Value="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
                    </Style>
                </StackPanel.Resources>
                <Border Height="28">
                    <TextBlock Height="24" FontFamily="{StaticResource FontAwesome}" xml:space="preserve"><Run Text="&#xf079;&#160;"/></TextBlock>
                </Border>
                <TextBlock Text="{x:Bind Path=User.Name}" />
                <TextBlock Text=" retweeted"/>
            </StackPanel>
        </Grid>
        <Grid Grid.Row="1">
            <StackPanel Orientation="Horizontal" Padding="5">
                <TextBlock Text="{x:Bind Path=Tweet.User.Name}" Margin="0 0 8 0"  FontWeight="Bold" />
                <TextBlock Text="{x:Bind Path=Tweet.User.ScreenName, Converter={StaticResource GetHandle}}" Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
                <TextBlock Text="&#x2981;" Margin="8 0" />
                <TextBlock Text="{x:Bind Path=Tweet.CreationDate, Converter={StaticResource FormatDate}}" />
            </StackPanel>
        </Grid>
        <Grid Grid.Row="2">
            <TextBlock Text="***this is where I'm having problems***" Padding="5" TextWrapping="WrapWholeWords"/>
        </Grid>
        <Grid Grid.Row="3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="2.5*" MaxWidth="100"/>
                <ColumnDefinition Width="2.5*"/>
                <ColumnDefinition Width="2.5*"/>
                <ColumnDefinition Width="2.5*"/>
            </Grid.ColumnDefinitions>
            <Grid Grid.Column="0">
                <Button x:Name="cmdComment" Content="&#xf075;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="1">
                <Button x:Name="cmdRetweet" Content="&#xf079;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="2">
                <Button x:Name="cmdLike" Content="&#xf004;" Style="{StaticResource MetaButtons}" />
            </Grid>
            <Grid Grid.Column="3">
                <Button x:Name="cmdMessage" Content="&#xf0e0;" Style="{StaticResource MetaButtons}" />
            </Grid>
        </Grid>
    </Grid>
</DataTemplate>

【问题讨论】:

  • 您可以生成所有内容(运行和超链接)并通过转换器的附加属性将它们添加为文本块的内联集合;或创建一个自定义控件,以便您可以使用您的模板并公开一些您需要访问的依赖项属性
  • 我应该一次添加一个内容数组,还是在创建每个内容项时添加它?我对 Attachedproperty 不熟悉 - 你能稍微扩展一下吗?
  • 这取决于你的实现。如果您拥有所有内容,您将立即添加它们。 attachproperty 解决方案是帮助您访问和控制文本块的 InlineCollection。您可以根据需要添加/删除内容。这也将允许您使用数据绑定

标签: c# uwp datatemplate uwp-xaml xbind


【解决方案1】:

如果你想使用附加属性,下面是一个例子:

public static class Twitter
{
    public static readonly DependencyProperty InlinesProperty = DependencyProperty.RegisterAttached(
        "Inlines", typeof(ICollection<Inline>), typeof(Twitter), new PropertyMetadata(default(ICollection<Inline>), PropertyChangedCallback));

    private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is TextBlock tb)) return;

        tb.Inlines.Clear();

        if (!(e.NewValue is ICollection<Inline> inlines)) return;

        foreach (var inline in inlines)
        {
            tb.Inlines.Add(inline);
        }
    }

    public static void SetInlines(DependencyObject element, ICollection<Inline> value)
    {
        element.SetValue(InlinesProperty, value);
    }

    public static ICollection<Inline> GetInlines(DependencyObject element)
    {
        return (ICollection<Inline>) element.GetValue(InlinesProperty);
    }
}

在 xaml 中:

        <TextBlock local:Twitter.Inlines ="{x:Bind TwitterData}"></TextBlock>

其中 TwitterData 是 List&lt;Inline&gt;

【讨论】:

  • 好吧,我说得太早了——如果我尝试在我的 XAML 中再次加载相同的推文对象(我正在使用BladeView 控件,因此单击推文会在新的刀片),我收到此错误:WinRT information: Element is already the child of another element.
  • 我可以理解您在多个地方重用了一些生成的内容(内联)。在这种情况下,要么使用计算属性,要么使用表示推文对象的数据结构,并使用转换器动态生成内容。另一种选择是使用自定义控件
  • 我想通了——我使用MemberwiseClone() 克隆了选定的推文,然后加载到第二个刀片中没有任何问题。再次感谢!!
  • 好!仅供参考:如果您使用 {Binding} 而不是 x:Bind,则使用计算属性也可以。计算属性必须每次评估并创建内容。但它只适用于 {Binding} 而不是 {x:Bind}
猜你喜欢
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 2019-01-08
  • 1970-01-01
  • 2020-08-11
  • 1970-01-01
  • 2018-04-03
  • 1970-01-01
相关资源
最近更新 更多