【问题标题】:WPF - Change a style in code behindWPF - 在后面的代码中更改样式
【发布时间】:2010-12-30 13:54:28
【问题描述】:

我有一个显示 TFS 查询结果的列表框。我想在后面的代码中更改 ListBoxItem 的样式,以使查询结果中包含列。

ListBoxItem 的样式在我的 Windows.Resoruces 部分中定义。我试过这个:

public T GetQueryResultsElement<T>(string name) where T : DependencyObject
{
    ListBoxItem myListBoxItem =
        (ListBoxItem)(lstQueryResults.ItemContainerGenerator.ContainerFromIndex(0));

    // Getting the ContentPresenter of myListBoxItem
    ContentPresenter myContentPresenter =
        myListBoxItem.Template.LoadContent().FindVisualChild<ContentPresenter>();

    // Finding textBlock from the DataTemplate that is set on that ContentPresenter
    DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;  <------+
    T myControl = (T)myDataTemplate.FindName(name, myContentPresenter);       |
                                                                              |    
    return (T)myControl;                                                      |
}                                                                             |
                                                                              |
        ContentTemplate is null ----------------------------------------------+

但 ContentTemplate 为空。我从here 获得了该代码,然后使用 LoadContent 调用对其进行了修改(原始代码为 ContentPresenter 提供了 null)。

无论如何。如果您知道如何更改背后代码中现有样式的方法,我很乐意看到它。


如果您需要,请具体说明:
我要在我的 ListBoxItem 样式中使用 WrapPanel。这就是我想要添加额外的 TextBlock 项的内容。

这是我的风格的一部分:

<!--Checkbox ListBox-->
<Style x:Key="CheckBoxListStyle" TargetType="ListBox">
    <Style.Resources>
        <Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
            <Setter Property="Tag" Value="{Binding Id}"/>
            <Setter Property="Background">
                <Setter.Value>
                    <Binding Path="Type" Converter="{StaticResource WorkItemTypeToColorConverter}" />
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Border BorderThickness="1" BorderBrush="#D4D4FF">
                            <Grid Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WrapPanel}}, Path=ActualWidth}" ScrollViewer.CanContentScroll="True" Margin="2">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="20" />
                                    <ColumnDefinition Width="*" />
                                    <ColumnDefinition Width="30" />
                                </Grid.ColumnDefinitions>
                                <Grid.Background>
                                    <Binding Path="Type" Converter="{StaticResource WorkItemTypeToColorConverter}" />
                                </Grid.Background>

                                <CheckBox VerticalAlignment="Center" Grid.Column="0" IsChecked="{Binding IsSelected,
                                      RelativeSource={RelativeSource TemplatedParent},
                                      Mode=TwoWay}" Name="chkIsSelected" />
                                <WrapPanel Grid.Column="1" Margin="5,0,5,0" Name="QueryColumns">
                                    <TextBlock VerticalAlignment="Center"  Text="{Binding Id}" Name="txtID" />
                                    <TextBlock VerticalAlignment="Center" Margin="5,0,5,0" Text="{Binding Title}" Name="txtTitle" />
                                </WrapPanel>

【问题讨论】:

    标签: c# wpf styles code-behind


    【解决方案1】:

    你在这里违背了规律,试图直接在代码隐藏中操纵视觉元素。有一个涉及数据绑定的非常简单的解决方案。

    我将提供通用解决方案,因为我不知道您的解决方案的细节。

    获得查询结果后,创建一个枚举,返回列名和每次迭代的字段值。

    示例:

    class NameValuePair 
    {
        public string Name { get; set; }
        public object Value { get; set; }
    }
    
    public IEnumerable<IEnumerable<NameValuePair>> EnumerateResultSet(DataTable resultSet)
    {
        foreach (DataRow row in resultSet.Rows)
            yield return EnumerateColumns(resultSet, row);
    }
    
    public IEnumerable<NameValuePair> EnumerateColumns(DataTable resultSet, DataRow row)
    {
        foreach (DataColumn column in resultSet.Columns)
            yield return new NameValuePair
                { Name = column.ColumnName, Value = row[column] };
    }
    

    在您的代码隐藏中,一旦您获得 DataTable 结果集,请执行以下操作:

    myResultsList.ItemsSource = EnumerateResultSet(myDataTable);
    

    XAML 可能如下所示:

    <Window.Resources>
        <DataTemplate x:Key="ColumnTemplate">
            <Border BorderBrush="Black" BorderThickness="1" CornerRadius="2" Padding="2">
                <WrapPanel>
                    <TextBlock Text="{Binding Name}" Margin="0,0,5,0"/>
                    <TextBlock Text="{Binding Value}" Margin="0,0,10,0"/>
                </WrapPanel>
            </Border>
        </DataTemplate>
        <DataTemplate x:Key="RowTemplate">
            <Grid>
                <ItemsControl 
                    ItemsSource="{Binding}" 
                    ItemTemplate="{StaticResource ColumnTemplate}"
                    Margin="0,5,0,5"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox Name="myResultsList" ItemTemplate="{StaticResource RowTemplate}"/>
    </Grid>
    

    示例输出:

    【讨论】:

    • 这很棒!更重要的是,这是一个很棒的答案。我已将其设置为答案,但由于 Stack Overflow 的问题,我无法对其进行投票。我已将它作为 meta 上的错误提交:meta.stackexchange.com/questions/34009/… 非常感谢您花时间帮助我解决这个问题。当你以正确的方式做它时,WPF 很棒,但当你走错了路时它是熊的。谢谢你给我指路...
    • 你对你最后的陈述非常正确 :) 不客气!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    相关资源
    最近更新 更多