在代码中即时访问生成的UIElements

时间:2017-05-09 14:47:02

标签: c# wpf xaml

如果有更好的方法,请纠正我:)

我必须动态地将UIElement(在我的情况下为StackPanel)添加到我的xaml。

我的代码:

foreach (Dienstleistung dienstleistung in dienstleistungenList)
{
    var xaml = System.Windows.Markup.XamlWriter.Save(StackPanelTemplate);
    var deepCopy = System.Windows.Markup.XamlReader.Parse(xaml) as StackPanel;
    foreach (UIElement child in deepCopy.Children)
    {
        if (child is TextBlock)
        {
            var y = child as TextBlock;
            switch (y.Text)
            {
                case "Titel":
                    y.Text = dienstleistung.Title;
                    break;
                case "Beschreibung":
                    y.Text = dienstleistung.Summary;
                    break;
            }
        }
    }
    MainContainer.Children.Add(deepCopy);
}

的Xaml:

<WrapPanel Name="MainContainer" HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel Name="StackPanelTemplate" Margin="5px" Width="200px" MouseLeftButtonUp="StackPanelOnClick">
            <StackPanel.Style>
                <Style>
                    <Setter Property="Border.Background" Value="LightCyan"/>
                    <Style.Triggers>
                        <Trigger Property="Border.IsMouseOver" Value="True">
                            <Setter Property="Border.Background" Value="LightGreen" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </StackPanel.Style>
            <Image Margin="5px" Width="190px" Height="190px"></Image>
            <TextBlock TextAlignment="Center" TextWrapping="WrapWithOverflow" Margin="5px" FontSize="16">Titel</TextBlock>
            <TextBlock TextAlignment="Center" TextWrapping="WrapWithOverflow" Margin="5px">Beschreibung</TextBlock>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                <TextBox x:Name="txtNum" x:FieldModifier="private" Margin="5,5,0,5" Width="50" Text="0" TextChanged="txtNum_TextChanged" />
                <Button x:Name="cmdUp" x:FieldModifier="private" Margin="5,5,0,5" Content="˄" Width="20" Click="cmdUp_Click" />
                <Button x:Name="cmdDown" x:FieldModifier="private" Margin="0,5,0,5"  Content="˅" Width="20" Click="cmdDown_Click" />
            </StackPanel>
        </StackPanel>
    </WrapPanel>

简而言之,我有一个模板,我将其复制。

现在我的模板中有一个TextBox,我有TextChanged个事件。现在我的问题是,为什么这个事件不会发生?有没有办法访问这些生成的元素?

1 个答案:

答案 0 :(得分:0)

根据Microsoft的Serialization Limits of XamlWriter.Save序列化期间未保留事件处理。如果你考虑一下,原因应该是显而易见的。即使它以某种方式能够识别附加到所述事件的对象是一个控件,它可以序列化并进一步识别它何时已经序列化一个组件以避免无限循环,在反序列化时会发生什么?您当然不会将TextChanged事件挂钩到已经存在的完全相同的对象...它必须创建另一个控件实例,后面的代码实现并附加到该控件上,因为它无法知道已经记忆中的那个。

幸运的是,有一种更好的方法来实现你想要做的事情。在WPF中,如果要在某种列表上重复控件的次数可变,您需要查看使用ItemsControl或其中一个派生。如果将项目列表绑定到ItemsSource依赖项属性,然后将所需的控件放在ItemTemplate中的每个项目上,框架将为每个项目创建一个新的ItemTemplate实例列表中的项目,将其设置为ItemsControl的子项,并将新创建的控件的DataContext设置为它为其创建的列表中的项目。稍微移动你的XAML,它最终会看起来像这样:

<ItemsControl ItemsSource="{Binding DienstleistungenList}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel HorizontalAlignment="Center" VerticalAlignment="Center" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Name="StackPanelTemplate"
                        Width="200px"
                        Margin="5px"
                        MouseLeftButtonUp="StackPanelOnClick">
                <StackPanel.Style>
                    <Style>
                        <Setter Property="Border.Background" Value="LightCyan" />
                        <Style.Triggers>
                            <Trigger Property="Border.IsMouseOver" Value="True">
                                <Setter Property="Border.Background" Value="LightGreen" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </StackPanel.Style>
                <Image Width="190px"
                       Height="190px"
                       Margin="5px" />
                <TextBlock Margin="5px"
                           FontSize="16"
                           Text="{Binding Title}"
                           TextAlignment="Center"
                           TextWrapping="WrapWithOverflow" />
                <TextBlock Margin="5px"
                           Text="{Binding Summary}"
                           TextAlignment="Center"
                           TextWrapping="WrapWithOverflow" />
                <StackPanel HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            Orientation="Horizontal">
                    <TextBox x:Name="txtNum"
                             Width="50"
                             Margin="5,5,0,5"
                             x:FieldModifier="private"
                             Text="0"
                             TextChanged="txtNum_TextChanged" />
                    <Button x:Name="cmdUp"
                            Width="20"
                            Margin="5,5,0,5"
                            x:FieldModifier="private"
                            Click="cmdUp_Click"
                            Content="˄" />
                    <Button x:Name="cmdDown"
                            Width="20"
                            Margin="0,5,0,5"
                            x:FieldModifier="private"
                            Click="cmdDown_Click"
                            Content="˅" />
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

正如评论中所建议的,我建议阅读Data Templating Overview,但也会添加Data Binding Overview,因为这两者对于理解如何编写基于XAML的应用程序至关重要。