javaee论坛

普通会员

225648

帖子

355

回复

369

积分

楼主
发表于 2017-07-14 15:41:00 | 查看: 184 | 回复: 2
相信从winform转到wpf的人都遇到过这样的困惑,在处理DataGrid时,我想让某一单元格根据格式校验的不同情况显示不同的颜色,以便于用户区分。

于是你去查找各种资料,wpf下DataGrid如何改变某一单元格颜色,如果运气不好,可能搜索到的结果会令你失望,运气不错的话你会搜到类似如下代码:

private void changeCell()         {            this.sj_DataGrid.Dispatcher.Invoke(            new Action(                delegate                {                    foreach (LSErr l in lse)                    {                        for (int i = 0; i < this.sj_DataGrid.Items.Count; i++)                        {                            DataRowView drv = this.sj_DataGrid.Items[i] as DataRowView;                            DataGridRow row = (DataGridRow)this.sj_DataGrid.ItemContainerGenerator.ContainerFromIndex(i);                            if (drv["StockCode"].ToString()==l.stCode)                            {                                System.Windows.Controls.Primitives.DataGridCellsPresenter presenter = GetVisualChild<System.Windows.Controls.Primitives.DataGridCellsPresenter>(row);                                if (presenter != null)                                {                                    DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(l.ci);                                    cell.Background = new SolidColorBrush(Colors.CadetBlue);                                }                                break;                            }                        }                    }                }                )                );        }//获取单元格        public static T GetVisualChild<T>(Visual parent) where T : Visual        {            T childContent = default(T);            if (parent != null)            {                int numVisuals = VisualTreeHelper.GetChildrenCount(parent);                for (int i = 0; i < numVisuals; i++)                {                    Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);                    childContent = v as T;                    if (childContent == null)                    {                        childContent = GetVisualChild<T>(v);                    }                    if (childContent != null)                    {                        break;                    }                }                //Thread.Sleep(10);            }            return childContent;        }



看起来很不错,而且运行也能成功。

不过很快你就会发现问题,那就是当你的窗口大小变化时,或者你拖动滚动条的时候奇葩的事情发生了,你选择变色的单元格变掉了,变色的可能是任何一个单元格,反正不是你想要的那一个。


于是你又再一次踏上了搜索之旅


终于让你找到了一个解决办法,就是我们标题中的VirtualizingStackPanel.IsVirtualizing="False",不错,效果很好,DataGrid应用这一属性之后我们可以准确的改变单元格颜色了。


但是,问题又来了...


当你的DataGrid加载的数据稍微多一些时,比如2000,3000,...10000...,再次运行你的程序你会发现主界面竟然卡住了好几秒,于是你设置断点查看,运行时间。你会发现由于ui虚拟化被禁用,数据加载的时间被无限拖长。用户界面卡顿,造成短时间内无响应,给用户死机的感受(PS:实际上此时程序正在玩儿命的绘制UI)


这种情况下,纵使你数据校验再好,数据校验整个过程中程序卡死的假象蒙蔽下,用户也会失去耐心,除非你的项目经理很强势,让用户耐心等待...


So,换一种实现策略吧


最终,还是暂时使用模板类中的触发器来实现吧,当不同的属性下生成不同的颜色

<Window.Resources>        <!--<c:ErrorConverter x:Key="ErrorConverter"/>-->        <c:SheetArr x:Key="SheetCols"/>        <Style TargetType="{x:Type Button}" x:Key="highlightStyle">            <Style.Triggers>                <Trigger Property="IsEnabled" Value="false">                    <Setter Property="Background" Value="#EEEEEE" />                </Trigger>                <MultiTrigger>                    <MultiTrigger.Conditions>                        <Condition Property="IsEnabled" Value="true" />                    </MultiTrigger.Conditions>                    <Setter Property="BorderBrush" Value="Red"/>                    <Setter Property="FontSize" Value="14" />                    <Setter Property="FontWeight" Value="Bold" />                    <Setter Property="Foreground" Value="Red" />                </MultiTrigger>            </Style.Triggers>        </Style>        <Style TargetType="{x:Type DataGridRow}">            <Style.Triggers>                <DataTrigger Binding="{Binding State}" Value="格式错误">                    <Setter Property="ToolTip">                        <Setter.Value>                            <ToolTip>                                <TextBlock Text="{Binding State,StringFormat='错误:{0}'}"/>                            </ToolTip>                        </Setter.Value>                    </Setter>                    <Setter Property="Foreground" Value="Red" />                </DataTrigger>            </Style.Triggers>        </Style>    </Window.Resources>



这只是一种过度方案,当发现某单元格值达到某种条件时改变背景色,不够灵活,真正的解决这一问题还得研究wpf的ui visualization实现上下手


希望已经碰到这种问题的兄弟少走点儿弯路,或者如果有大神已经解决这种问题还请指教



普通会员

0

帖子

335

回复

343

积分
沙发
发表于 2023-11-17 20:10:21

专业抢二楼!顺便笑摸狗头(3L)

普通会员

0

帖子

302

回复

312

积分
板凳
发表于 2024-04-19 06:57:15

很好

您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017