2012-06-01 50 views
13

Tôi có một DataGrid có dữ liệu được làm mới bằng một quá trình nền sau mỗi 15 giây. Nếu bất kỳ dữ liệu nào thay đổi, tôi muốn chạy một hình động làm nổi bật ô có giá trị thay đổi màu vàng và sau đó mờ dần trở lại màu trắng. Tôi sắp xếp của nó có làm việc bằng cách làm như sau:Làm nổi bật các ô trong WPF DataGrid khi giá trị giới hạn thay đổi

Tôi tạo ra một phong cách với sự kiện kích hoạt trên Binding.TargetUpdated

<Style x:Key="ChangedCellStyle" TargetType="DataGridCell"> 
    <Style.Triggers> 
     <EventTrigger RoutedEvent="Binding.TargetUpdated"> 
      <BeginStoryboard> 
       <Storyboard> 
        <ColorAnimation Duration="00:00:15" 
         Storyboard.TargetProperty= 
          "(DataGridCell.Background).(SolidColorBrush.Color)" 
         From="Yellow" To="Transparent" /> 
       </Storyboard> 
      </BeginStoryboard> 
     </EventTrigger> 
    </Style.Triggers> 
</Style> 

Và sau đó áp dụng nó vào các cột tôi muốn làm nổi bật nếu một giá trị thay đổi

<DataGridTextColumn Header="Status" 
    Binding="{Binding Path=Status, NotifyOnTargetUpdated=True}" 
    CellStyle="{StaticResource ChangedCellStyle}" /> 

Nếu giá trị cho trường trạng thái trong cơ sở dữ liệu thay đổi, ô đánh dấu màu vàng giống như tôi muốn. Nhưng, có một vài vấn đề.

Trước tiên, khi lưới dữ liệu được tải ban đầu, toàn bộ cột được đánh dấu màu vàng. Điều này có ý nghĩa, bởi vì tất cả các giá trị đang được tải lần đầu tiên vì vậy bạn mong đợi TargetUpdated sẽ kích hoạt. Tôi chắc chắn có một số cách tôi có thể ngăn chặn điều này, nhưng đó là một điểm tương đối nhỏ.

Vấn đề thực sự là toàn bộ cột được đánh dấu màu vàng nếu lưới được sắp xếp hoặc lọc theo bất kỳ cách nào. Tôi đoán tôi không hiểu tại sao một loại sẽ khiến TargetUpdated kích hoạt vì dữ liệu không thay đổi, giống như cách nó được hiển thị. Vì vậy, câu hỏi của tôi là (1) làm thế nào tôi có thể ngăn chặn hành vi này trên tải ban đầu và sắp xếp/lọc, và (2) tôi đi đúng hướng và đây có phải là cách tốt để làm điều này không? Không. Tôi nên đề cập đến đây là MVVM.

+0

Để sắp xếp giải pháp thay thế cho giải pháp bạn đề xuất ... 1) bạn có mong đợi danh sách lớn không? (trong trường hợp này có nghĩa là lớn> = 100 mục); và 2) bạn có mong đợi số lượng các mục trong danh sách thay đổi thường xuyên không? –

+0

Đây thực chất là một ứng dụng hàng đợi trợ giúp liệt kê các lỗi về giao dịch và cho phép mọi người sở hữu một lỗi cụ thể và đánh dấu nó là đã giải quyết. Các giá trị không nên thay đổi thường xuyên, và tôi hy vọng họ sẽ nhận được ít hơn 100 lỗi mỗi ngày trong sản xuất. –

+0

OK tuyệt vời, tôi thấy ý tưởng hiển thị các ô khác nhau thay đổi nền của nó một cách trơn tru khi nội dung của họ thay đổi, ví dụ, khi trạng thái của nhiệm vụ thay đổi hoặc người được giao nhiệm vụ ..., nhưng tôi đã làm một số nghiên cứu về điều đó và Tôi không tìm thấy một cách mà bạn có thể làm điều này chỉ bằng cách viết Xaml. Những gì tôi sẽ làm là viết một bộ sưu tập các đối tượng miền của bạn trong bộ nhớ, và mỗi lần bạn lấy danh sách từ máy chủ, thực hiện các phương thức tiện ích thực hiện so sánh dữ liệu vừa được truy xuất với dữ liệu đã có trong DataGrid và thực hiện thay đổi kiểu. –

Trả lời

0

TargetUpdated thực sự chỉ là sự kiện dựa trên cập nhật giao diện người dùng. Việc cập nhật diễn ra không quan trọng. Trong khi phân loại tất cả các DataGridCells vẫn ở vị trí của họ chỉ có dữ liệu được thay đổi trong chúng theo kết quả phân loại do đó TargetUpdated được nâng lên. do đó chúng ta phải phụ thuộc vào lớp dữ liệu của ứng dụng WPF. Để đạt được điều này, tôi đã đặt lại Ràng buộc của DataGridCell dựa trên một biến loại theo dõi nếu cập nhật đang xảy ra ở lớp dữ liệu.

XAML:

<Window.Resources> 
    <Style x:Key="ChangedCellStyle" TargetType="DataGridCell"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="DataGridCell"> 
        <ControlTemplate.Triggers> 
         <EventTrigger RoutedEvent="Binding.TargetUpdated"> 
          <BeginStoryboard> 
           <Storyboard> 
            <ColorAnimation Duration="00:00:04" Storyboard.TargetName="myTxt" 
             Storyboard.TargetProperty="(DataGridCell.Background).(SolidColorBrush.Color)" 
             From="Red" To="Transparent" /> 
           </Storyboard> 
          </BeginStoryboard> 
         </EventTrigger>       
        </ControlTemplate.Triggers> 

        <TextBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Transparent" 
          Name="myTxt" > 
         <TextBox.Style> 
          <Style TargetType="TextBox"> 
           <Style.Triggers> 
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=DataContext.SourceUpdating}" Value="True"> 
             <Setter Property="Text" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Content.Text,NotifyOnSourceUpdated=True,NotifyOnTargetUpdated=True}" /> 
            </DataTrigger> 
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=DataContext.SourceUpdating}" Value="False"> 
             <Setter Property="Text" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=Content.Text}" />            
            </DataTrigger>          
           </Style.Triggers>          
          </Style> 
         </TextBox.Style> 
        </TextBox> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Window.Resources> 

<StackPanel Orientation="Vertical"> 
    <DataGrid ItemsSource="{Binding list}" CellStyle="{StaticResource ChangedCellStyle}" AutoGenerateColumns="False" 
       Name="myGrid" > 
     <DataGrid.Columns> 
      <DataGridTextColumn Header="Name" Binding="{Binding Name}" /> 
      <DataGridTextColumn Header="ID" Binding="{Binding Id}" /> 
     </DataGrid.Columns> 
    </DataGrid> 
    <Button Content="Change Values" Click="Button_Click" /> 
</StackPanel> 

Mã Đằng sau (DataContext đối tượng của Window):

public MainWindow() 
    { 
     list = new ObservableCollection<MyClass>(); 
     list.Add(new MyClass() { Id = 1, Name = "aa" }); 
     list.Add(new MyClass() { Id = 2, Name = "bb" }); 
     list.Add(new MyClass() { Id = 3, Name = "cc" }); 
     list.Add(new MyClass() { Id = 4, Name = "dd" }); 
     list.Add(new MyClass() { Id = 5, Name = "ee" }); 
     list.Add(new MyClass() { Id = 6, Name = "ff" }); 
     InitializeComponent(); 
    } 

    private ObservableCollection<MyClass> _list; 
    public ObservableCollection<MyClass> list 
    { 
     get{ return _list; } 
     set{ 
      _list = value; 
      updateProperty("list"); 
     } 
    } 

    Random r = new Random(0); 
    private void Button_Click(object sender, RoutedEventArgs e) 
    { 

     int id = (int)r.Next(6); 
     list[id].Id += 1; 
     int name = (int)r.Next(6); 
     list[name].Name = "update " + r.Next(20000); 
    } 

Mẫu Class:SourceUpdating thuộc tính được đặt thành true (đặt ràng buộc để thông báo TargetUpdate qua DataTrigger) khi bất kỳ thông báo nào đang được xử lý theo phương pháp theo phương thức updateProperty() và sau khi cập nhật được thông báo là UI, SourceUpdating được đặt thành false (sau đó đặt lại ràng buộc để không thông báo TargetUpdate qua số DataTrigger).

public class MyClass : INotifyPropertyChanged 
{ 
    private string name; 
    public string Name 
    { 
     get { return name; } 
     set { 
      name = value;updateProperty("Name"); 
     } 
    } 

    private int id; 
    public int Id 
    { 
     get { return id; } 
     set 
     { 
      id = value;updateProperty("Id"); 
     } 
    } 

    //the vaiable must set to ture when update in this calss is ion progress 
    private bool sourceUpdating; 
    public bool SourceUpdating 
    { 
     get { return sourceUpdating; } 
     set 
     { 
      sourceUpdating = value;updateProperty("SourceUpdating"); 
     } 
    }   

    public event PropertyChangedEventHandler PropertyChanged; 
    public void updateProperty(string name) 
    { 
     if (name == "SourceUpdating") 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(name)); 
      } 
     } 
     else 
     { 
      SourceUpdating = true;    
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(name)); 
      }    
      SourceUpdating = false;     
     } 
    } 

} 

Đầu ra:

Hai cập nhật đồng thời/Nút được nhấp một lần:

update1

Nhiều cập nhật đồng thời/Nút được nhấp nhiều lần:

update2

SO sau khi cập nhật, khi sắp xếp hoặc lọc đang xảy ra bindings biết rằng nó không phải gọi sự kiện TargetUpdated . Chỉ khi cập nhật thu thập nguồn đang được tiến hành, ràng buộc được đặt lại để gọi sự kiện TargetUpdated. Ngoài ra vấn đề màu ban đầu cũng được xử lý bằng cách này.

Tuy nhiên như logic vẫn có một số lần đến loại như đối với biên tập viên TextBox logic dựa trên với nhiều phức tạp của các kiểu dữ liệu và giao diện người dùng logic mã sẽ trở nên phức tạp hơn cũng cho ban đầu ràng buộc thiết lập lại toàn bộ hàng được hoạt hình như TargetUpdated được nâng lên cho tất cả các ô của một hàng.

0

Ý tưởng của tôi cho điểm (1) sẽ là xử lý điều này trong mã. Một cách sẽ là xử lý sự kiện TargetUpdated cho DataGridTextColumn và thực hiện kiểm tra bổ sung giá trị cũ so với giá trị mới và áp dụng kiểu chỉ nếu các giá trị khác nhau và có lẽ cách khác để tạo và xóa ràng buộc dựa trên lập trình dựa trên các sự kiện khác nhau trong mã của bạn (như tải ban đầu, làm mới, v.v.).

0

Tôi đề xuất sử dụng OnPropertyChanged cho mọi đạo cụ trong chế độ xem của bạn và cập nhật UIElement liên quan (bắt đầu hoạt ảnh hoặc bất kỳ thứ gì), vì vậy vấn đề của bạn sẽ được giải quyết (khi tải, sắp xếp, lọc, ...) và người dùng có thể xem ô nào đã thay đổi!

Các vấn đề liên quan