none
WPF的DataGrid,比對彼此欄位來改變顏色,但是顯示有問題 RRS feed

  • 問題

  • 我要的效果是有ABCDE五個欄位

    只要BCDE的欄位比A欄大,就變紅色,比A欄位小就變綠色

    我的方式是自訂一個DataColumn

    MainWindow.xaml:

    <Window x:Class="WpfDataGrid.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfDataGrid"
            Title="MainWindow" Height="534.211" Width="709.211">
        <Grid Loaded="Grid_Loaded">
            <DataGrid AutoGenerateColumns="False" Name="dataGriScore" IsReadOnly="True">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="ID" Binding="{Binding Path=ID}" Width="80"/>
                    <local:CustomDataColumn Header="A" Binding="{Binding Path=A}" Width="65"/>
                    <local:CustomDataColumn Header="B" Binding="{Binding Path=B}" Width="65"/>
                    <local:CustomDataColumn Header="C" Binding="{Binding Path=C}" Width="65"/>
                    <local:CustomDataColumn Header="D" Binding="{Binding Path=D}" Width="65"/>
                    <local:CustomDataColumn Header="E" Binding="{Binding Path=E}" Width="65"/>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>

    MainWindow.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfDataGrid
    {
        /// <summary>
        /// MainWindow.xaml 的互動邏輯
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Grid_Loaded(object sender, RoutedEventArgs e)
            {
                DataTable iv_DataTable = new DataTable();
                DataColumn[] dc = new DataColumn[6];
                dc[0] = new DataColumn("ID", Type.GetType("System.String"));
                dc[1] = new DataColumn("A", Type.GetType("System.Decimal"));
                dc[2] = new DataColumn("B", Type.GetType("System.Decimal"));
                dc[3] = new DataColumn("C", Type.GetType("System.Decimal"));
                dc[4] = new DataColumn("D", Type.GetType("System.Decimal"));
                dc[5] = new DataColumn("E", Type.GetType("System.Decimal"));
                iv_DataTable.Columns.AddRange(dc);
    
                StringReader sr = new StringReader(Properties.Resources.Data);
    
                while (sr.Peek() > 0)
                {
                    string[] values = sr.ReadLine().Split('	');
    
                    DataRow row = iv_DataTable.NewRow();
    
                    for (int i = 0; i < values.Length; i++)
                    {
                        if (values[i].Equals(string.Empty))
                        { continue; }
                        row[i] = values[i];
                    }
    
                    iv_DataTable.Rows.Add(row);
                }
    
                sr.Close();
                sr.Dispose();
    
                this.dataGriScore.ItemsSource = iv_DataTable.DefaultView;
            }
        }
    
        #region CustomDataColumn
        public class CustomDataColumn : DataGridTextColumn
        {
            protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
            {
    
                TextBlock tb = base.GenerateElement(cell, dataItem) as TextBlock;
                DataRow iv_data = (dataItem as DataRowView).Row;
    
                if (!iv_data.IsNull("A"))
                {
                    if (cell.Column.Header.Equals("B"))
                    {
                        if (!iv_data.IsNull("B"))
                        {
                            if (iv_data.Field<decimal>("B") > iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Red;
                            }
                            else if (iv_data.Field<decimal>("B") < iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Green;
                            }
                        }
                    }
                    else if (cell.Column.Header.Equals("C"))
                    {
                        if (!iv_data.IsNull("C"))
                        {
                            if (iv_data.Field<decimal>("C") > iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Red;
                            }
                            else if (iv_data.Field<decimal>("C") < iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Green;
                            }
                        }
                    }
                    else if (cell.Column.Header.Equals("D"))
                    {
                        if (!iv_data.IsNull("D"))
                        {
                            if (iv_data.Field<decimal>("D") > iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Red;
                            }
                            else if (iv_data.Field<decimal>("D") < iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Green;
                            }
                        }
                    }
                    else if (cell.Column.Header.Equals("E"))
                    {
                        if (!iv_data.IsNull("E"))
                        {
                            if (iv_data.Field<decimal>("E") > iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Red;
                            }
                            else if (iv_data.Field<decimal>("E") < iv_data.Field<decimal>("A"))
                            {
                                tb.Foreground = Brushes.Green;
                            }
                        }
                    }
                }
    
                return tb;
            }
        }
        #endregion
    }

    結果呈現有的會正常,有的不正常,如果不正常,應該全部都不正常,但卻是這樣奇怪的現象,還是用複寫的方式不好嗎?

    原始碼:
    https://www.dropbox.com/sh/pcvxzynwhqhlg28/E2c1x81TBg


    • 已編輯 Wesley Hsu 2013年10月22日 下午 03:50
    2013年10月22日 下午 03:50

解答

  • (1) 加資料欄位 (用來判斷 A 是否大於 B 之類)

    (2) 設計 data trigger

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    
    namespace WpfApplication1
    {
        public  class TestData : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged(string propertyname)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
                }
            }
    
            private string _id;
            public string ID
            {
                get { return _id; }
                set
                {
                    if (_id != value)
                    {
                        _id = value;
                        OnPropertyChanged("ID");
                    }
                }
            }
    
            private int _a;
            public int A
            {
                
                get { return _a; }
                set
                {
                    if (_a != value)
                    {
                        
                        _a = value;
                        OnPropertyChanged("A");
                        AGreaterthanB = (A >= B);
                    }
                }
            }
    
            private int _b;
            public int B
            {
                get { return _b; }
                set
                {
                    if (_b != value)
                    {                    
                        _b = value;
                        OnPropertyChanged("B");
                        AGreaterthanB = (A >= B);
                    }
                }
            }
    
            private bool _aGreaterthanb = true;
            public bool AGreaterthanB
            {
                get { return _aGreaterthanb; }
                private set
                {
                    if (_aGreaterthanb != value)
                    {
                        _aGreaterthanb = value;
                        OnPropertyChanged("AGreaterthanB");
                    }
                }
            }
        }
    
        public class TestDataCollection
        {
            private ObservableCollection<TestData> _items = new ObservableCollection<TestData>();
            public ObservableCollection<TestData> Items
            {
                get { return _items; }
                set { _items = value; }
            }
        }
    }

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="600" Width="800">
        <Window.Resources >
            <Style x:Key="cellStyle" TargetType="DataGridCell">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding AGreaterthanB}"
                                 Value="True">
    
                        <Setter Property="Foreground" Value="Green"></Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding AGreaterthanB}"
                         Value="False">
                        <Setter Property="Foreground" Value="Red"></Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Window.Resources>
        <Grid>
            <DataGrid AutoGenerateColumns="False" x:Name="datagrid" FontSize="30" >
                <DataGrid.Columns>
                    <DataGridTextColumn Header="ID" Binding="{Binding Path=ID}" Width="100" />
                    <DataGridTextColumn Header="A" Binding="{Binding Path=A}" Width="100"/>
                    <DataGridTextColumn Header="B" Binding="{Binding Path=B}" Width="100" CellStyle="{StaticResource cellStyle}"/>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// MainWindow.xaml 的互動邏輯
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                TestDataCollection data = new TestDataCollection();
                data.Items.Add(new TestData() { ID = "1", A = 8, B = 9 });
                data.Items.Add(new TestData() { ID = "2", A = 7, B = 4 });
                data.Items.Add(new TestData() { ID = "3", A = 6, B = 9 });
                datagrid.ItemsSource = data.Items;
            }
        }
    }


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 <br/> <a target="_blank" href="http://www.bplan.com.tw/chunfeng/front/bin/ptlist.phtml?Category=103591"><img border="0" src="http://files.dotblogs.com.tw/billchung/1007/20107414497912.gif" width="200" height="67"></a>


    2013年10月23日 下午 03:41
    版主

所有回覆

  • (1) 加資料欄位 (用來判斷 A 是否大於 B 之類)

    (2) 設計 data trigger

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    
    namespace WpfApplication1
    {
        public  class TestData : INotifyPropertyChanged
        {
            public event PropertyChangedEventHandler PropertyChanged;
            protected void OnPropertyChanged(string propertyname)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
                }
            }
    
            private string _id;
            public string ID
            {
                get { return _id; }
                set
                {
                    if (_id != value)
                    {
                        _id = value;
                        OnPropertyChanged("ID");
                    }
                }
            }
    
            private int _a;
            public int A
            {
                
                get { return _a; }
                set
                {
                    if (_a != value)
                    {
                        
                        _a = value;
                        OnPropertyChanged("A");
                        AGreaterthanB = (A >= B);
                    }
                }
            }
    
            private int _b;
            public int B
            {
                get { return _b; }
                set
                {
                    if (_b != value)
                    {                    
                        _b = value;
                        OnPropertyChanged("B");
                        AGreaterthanB = (A >= B);
                    }
                }
            }
    
            private bool _aGreaterthanb = true;
            public bool AGreaterthanB
            {
                get { return _aGreaterthanb; }
                private set
                {
                    if (_aGreaterthanb != value)
                    {
                        _aGreaterthanb = value;
                        OnPropertyChanged("AGreaterthanB");
                    }
                }
            }
        }
    
        public class TestDataCollection
        {
            private ObservableCollection<TestData> _items = new ObservableCollection<TestData>();
            public ObservableCollection<TestData> Items
            {
                get { return _items; }
                set { _items = value; }
            }
        }
    }

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="600" Width="800">
        <Window.Resources >
            <Style x:Key="cellStyle" TargetType="DataGridCell">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding AGreaterthanB}"
                                 Value="True">
    
                        <Setter Property="Foreground" Value="Green"></Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding AGreaterthanB}"
                         Value="False">
                        <Setter Property="Foreground" Value="Red"></Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Window.Resources>
        <Grid>
            <DataGrid AutoGenerateColumns="False" x:Name="datagrid" FontSize="30" >
                <DataGrid.Columns>
                    <DataGridTextColumn Header="ID" Binding="{Binding Path=ID}" Width="100" />
                    <DataGridTextColumn Header="A" Binding="{Binding Path=A}" Width="100"/>
                    <DataGridTextColumn Header="B" Binding="{Binding Path=B}" Width="100" CellStyle="{StaticResource cellStyle}"/>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace WpfApplication1
    {
        /// <summary>
        /// MainWindow.xaml 的互動邏輯
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                TestDataCollection data = new TestDataCollection();
                data.Items.Add(new TestData() { ID = "1", A = 8, B = 9 });
                data.Items.Add(new TestData() { ID = "2", A = 7, B = 4 });
                data.Items.Add(new TestData() { ID = "3", A = 6, B = 9 });
                datagrid.ItemsSource = data.Items;
            }
        }
    }


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。 <br/> <a target="_blank" href="http://www.bplan.com.tw/chunfeng/front/bin/ptlist.phtml?Category=103591"><img border="0" src="http://files.dotblogs.com.tw/billchung/1007/20107414497912.gif" width="200" height="67"></a>


    2013年10月23日 下午 03:41
    版主
  • 感謝Bill Chung高手的回答

    不過我的來源是DataTable

    難道要自訂一個Data Class,再把DataTable轉進去嗎??

    不知道會不會有脫褲子放屁的狀況~

    2013年10月25日 上午 10:02
  • 建議你集合用 ObservableCollection<T> , 而且你的資料類別中的屬性應該要實作 INotifyPropertyChanged

    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2013年10月25日 下午 01:25
    版主
  • 感謝!!

    使用您的方法,自訂類別實作INotifyPropertyChanged

    中間就寫個自動轉換程式,確實可以正常顯示了

    才剛學習WPF不久,WPF的跟以前的WinFrom差太多了

    以前DataGridView本身就是個陣列集合,直接程式碼硬敲愛怎麼變色就怎麼變,到WPF就行不太通了


    我之前的笨方法是找到這個文章:

    http://blog.darkthread.net/post-2010-08-06-silverlight-datagrid-cond-cell-color.aspx 

    也是胡亂拼湊出來的


    • 已編輯 Wesley Hsu 2013年10月25日 下午 04:01
    2013年10月25日 下午 04:01
  • 其實 XAML Based 的東西要做起變化來比 Windows Forms 要容易地多.

    只是要善用它們的優點, 像是資料繫結, 值轉換器, 故事板動畫 .

    每個人習慣不同, 我的習慣則是對於 UI 的處理儘量不使用 C# Code 去硬搞 (雖然 XAML 最後也會變成 IL Code和 C#  一樣)

    你貼的那篇黑大的文章,開頭就有個 dg1 的解法和我的解法就很類似, 其實那篇文是在闡述多種解法的說明.

    重點是, 黑大非常熟悉這些技巧, 所以他可以輕易地玩弄那些程式碼. 但這樣的程式碼只要一點點腦袋不清楚或是有所疏漏就很容易不正確.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2013年10月26日 上午 02:21
    版主