首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以编程方式更改ColumnDefinition样式

以编程方式更改ColumnDefinition样式
EN

Stack Overflow用户
提问于 2019-12-05 01:03:27
回答 2查看 126关注 0票数 0

下面的方法是在自定义控件中实现的。它以DataTable table作为参数,并使用表中的值填充网格grdMain。此表的每一列都应在鼠标悬停时更改其颜色。但是,当我试图将样式附加到ColumnDefinition时,它会抛出一个异常:

System.ArgumentException:'Style对象不允许影响其应用对象的样式属性。

代码语言:javascript
复制
private void DrawGrid(DataTable table)
    {
        // Prepare style to apply
        var gridColumnStyle = GetColumnStyles();
        foreach (var column in table.Columns)
        {
            var columnDefinition = new ColumnDefinition();
            columnDefinition.OverridesDefaultStyle = true;

            // System.ArgumentException: 'Style object is not allowed to affect the Style property of the object to which it applies.'
            columnDefinition.Style = gridColumnStyle;
            grdMain.ColumnDefinitions.Add(columnDefinition);
        }
        int rowNumber = 0;
        foreach (DataRow row in table.Rows)
        {
            grdMain.RowDefinitions.Add(new RowDefinition());
            for (int columnNumber = 0; columnNumber < table.Columns.Count; columnNumber++)
            {
                var cellText = new TextBlock()
                {
                    Text = row[columnNumber].ToString(),
                };
                grdMain.Children.Add(cellText);
                cellText.SetValue(Grid.RowProperty, rowNumber);
                cellText.SetValue(Grid.ColumnProperty, columnNumber);
            }
            rowNumber++;
        }
    }

如何以编程方式将样式应用于列定义?

UPD:这里是GetColumnStyles()的实现

代码语言:javascript
复制
private Style GetColumnStyles()
    {
        var columnStyle = new DataVisualizer.Desktop.Views.Styles.ColumnSelectionTableStyle();
        var columnHoverBrush = columnStyle["ColumnHoverBrush"];
        var columnBrush = columnStyle["ColumnBrush"];

        DataTrigger columnMouseHoverTrigger = new DataTrigger()
        {
            Binding = new Binding("IsMouseOver"),
            Value = true
        };
        columnMouseHoverTrigger.Setters.Add(new Setter()
        {
            Property = StyleProperty,
            Value = columnHoverBrush
        });
        var gridColumnStyle = new Style();
        gridColumnStyle.Triggers.Add(columnMouseHoverTrigger);
        return gridColumnStyle;
    }

ColumnSelectionTableStyle在单独的文件中定义:

代码语言:javascript
复制
 <ResourceDictionary
    x:Class="DataVisualizer.Desktop.Views.Styles.ColumnSelectionTableStyle"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <SolidColorBrush x:Key="StandardSolidColorBrush" Color="Blue" />
    <LinearGradientBrush x:Key="StandardLinearGradientBrush" StartPoint="0.0,0.0" EndPoint="1.0,1.0">
        <LinearGradientBrush.GradientStops>
            <GradientStop Color="White" Offset="0" />
            <GradientStop Color="Black" Offset="1" />
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
    <SolidColorBrush x:Key="ColumnHoverBrush" Color="BlueViolet" Opacity=".5"/>
    <SolidColorBrush x:Key="ColumnBrush" Color="White" Opacity="1"/>
</ResourceDictionary>
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-06 15:12:21

事实证明,这是一个比我预期的更复杂的问题。我们开始吧。

如果我正确理解了这一点,您将把各种Brushes存储在ColumnSelectionTableStyle类中,该类继承自ResourceDictionary。然后,您需要使用这些Brushes为Grid的列创建一个Style

例外(不太重要)

代码中直接导致异常的部分是GetColumnStyles中的行GetColumnStyles。正如例外说的那样,您不能使用Style来更改正在使用的Style (这会产生一些奇怪的悖论)。这并不是很重要的原因,因为这并不是你想要做的。

ColumnDefinition的问题

如果我理解的话,Trigger只需要设置列的背景,而不需要更改它的整个Style。通常,我建议您将Trigger目标设为Background属性,但这正是您遇到真正问题的地方。ColumnDefinition没有“背景”属性。

ColumnDefinition实际上并不“包含”列中的元素,它不是Control,甚至不是可见的元素。Grid只使用它来管理其子级的布局。如果希望Grid的某一列具有颜色,则需要在该列中放置可见的内容。我建议使用BorderRectangle

给它一个背景

为了显示您的列有颜色,请将Rectangle/Border添加到Grid中,适当地设置Grid.ColumnGrid.RowSpan,然后设置Rectangle/BorderBackground属性。我还会设置IsHitTestVisible = false,因为您希望后台元素的作用就好像它甚至不在那里一样。然后,您将在列中添加此背景元素的顶部(而不是内部)的其他元素。

IsMouseOver触发器

ColumnDefinition在技术上确实有一个IsMouseOver属性(继承自基类),但根据我测试的结果,它实际上不起作用。

RectangleBorder都具有工作的IsMouseOver属性,但这些属性只有在鼠标直接位于元素(或其子元素)之上而没有其他属性的情况下才能工作。由于要将加法元素放在它们上面,这些“较高”元素将“窃取”IsMouseOver,因此后台元素不会作为可靠的触发器工作。

基本上,如果你想让列的背景在MouseOver上改变颜色,你就得弄脏。在我看来,你可以:

使用MouseMovePreviewMouseMove事件在Grid级别跟踪鼠标的位置,确定它在哪个列中,然后手动更改相应的背景元素的Background属性。

在每个单元格的根元素处侦听对IsMouseOver的更改,然后检查该单元格所在的列,并手动更改相应背景元素的Background属性。

TL;DR

创建自定义控件是一项很大的工作。

您不能使用样式来替换自身(但不需要)。

ColumnDefinition没有背景,但RectangleBorder都有。

票数 1
EN

Stack Overflow用户

发布于 2019-12-06 20:49:26

正如Keith所建议的,最简单(也可能是唯一的)解决方法是更改网格列,即使用Rectangle。在我的例子中,我以编程方式将它们添加到每个列的前面,并将RowSpan设置为行数:

代码语言:javascript
复制
private Rectangle GetColumnRectangle(int colNumber, int rowsNumber)
    {
        Rectangle rect = new Rectangle();
        rect.Fill = _columnNormal;
        rect.SetValue(Grid.ColumnProperty, colNumber);
        rect.SetValue(Grid.RowSpanProperty, rowsNumber);
        rect.SetValue(Grid.ZIndexProperty, 10);


        //Subscribe to events
        rect.MouseEnter += OnColumnMouseEnter;
        rect.MouseLeave += OnColumnMouseLeave;
        rect.MouseDown += OnColumnSelected;
        return rect;
    }

DrawGrid方法对新方法签名进行了更改:

代码语言:javascript
复制
private void DrawGrid(DataTable table)
    {
        foreach (var column in table.Columns)
        {
            grdMain.ColumnDefinitions.Add(new ColumnDefinition());
        }
        int rowNumber = 0;
        foreach (DataRow row in table.Rows)
        {
            grdMain.RowDefinitions.Add(new RowDefinition());
            for (int columnNumber = 0; columnNumber < table.Columns.Count; columnNumber++)
            {
                var cellText = new TextBlock()
                {
                    Text = row[columnNumber].ToString(),
                };
                grdMain.Children.Add(cellText);
                cellText.SetValue(Grid.RowProperty, rowNumber);
                cellText.SetValue(Grid.ColumnProperty, columnNumber);
            }
            rowNumber++;
        }
        for (int colNumber = 0; colNumber < grdMain.ColumnDefinitions.Count; colNumber++)
        {
            var rect = GetColumnRectangle(colNumber, rowNumber);
            grdMain.Children.Add(rect);
            //Dictionary; indicating whether the column is selected
            _rectangles.Add(rect, false);
        }
    }

将列标记为所选列的第一个想法当然是扩展Rectangle以添加Selected属性,但它是sealed,因此最简单的解决方案是字典。在我的示例中,应用于OnColumnMouseEnterOnColumnMouseLeaveOnColumnSelected中的样式具有不同的不透明度值,这使得Rectangle可以像在后台一样工作。

如果您需要在列后面有矩形的解决方案,则应该使用Keith解决方案。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59186743

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档