14

バックグラウンド プロセスによって 15 秒ごとにデータが更新される DataGrid があります。いずれかのデータが変更された場合は、値が変更されたセルを黄色で強調表示してから白に戻すアニメーションを実行したいと考えています。私は、次のことを行うことで、それを機能させています。

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>

そして、値が変化した場合に強調表示したい列にそれを適用しました

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

データベースのステータス フィールドの値が変更されると、希望どおりにセルが黄色で強調表示されます。しかし、いくつかの問題があります。

まず、データ グリッドが最初に読み込まれると、列全体が黄色で強調表示されます。すべての値が初めて読み込まれるため、TargetUpdated が起動することが予想されるため、これは理にかなっています。これを止める方法があると確信していますが、それは比較的マイナーなポイントです。

実際の問題は、グリッドが何らかの方法でソートまたはフィルタリングされている場合、列全体が黄色で強調表示されることです。データが変更されていないため、並べ替えによって TargetUpdated が発生する理由が理解できないと思います。表示方法だけです。

だから私の質問は、(1)初期ロードとソート/フィルターでこの動作を停止するにはどうすればよいですか、(2)私は正しい軌道に乗っていますか、これはこれを行う良い方法ですか?これはMVVMであることに言及する必要があります。

4

3 に答える 3

0

ビューモデルのすべての小道具に OnPropertyChanged を使用し、関連する UIElement (アニメーションの開始など) を更新することをお勧めします。これにより、問題が解決され (ロード、並べ替え、フィルターなど)、ユーザーはどのセルが変更されたかを見ることができます!

于 2015-05-07T14:34:20.847 に答える
0

ポイント(1)に対する私の考えは、コードでこれを処理することです。1 つの方法は、DataGridTextColumn の TargetUpdated イベントを処理し、古い値と新しい値に対して追加のチェックを行い、値が異なる場合にのみスタイルを適用することです。おそらく別の方法は、バインディングを作成して削除することです。コード内のさまざまなイベント (初期ロード、更新など) に基づいてプログラム的に。

于 2012-06-01T19:50:49.030 に答える
0

TargetUpdated本当に唯一の UI 更新ベースのイベントであるため。更新がどのように行われているかは問題ではありません。すべてのDataGridCells残りをその場所に並べ替えている間、並べ替えの結果に従ってそれらのデータのみが変更されるため、TargetUpdated発生します。したがって、WPF アプリのデータ層に依存する必要があります。これを実現するためにDataGridCell、データ層で更新が行われている場合にトレースするような変数に基づいて Binding をリセットしました。

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>

コード ビハインド (ウィンドウの DataContext オブジェクト):

 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);
    }

モデル クラス: SourceUpdatingプロパティは true に設定されます (これにより、 をTargetUpdate介しDataTrigger) メソッドで通知が進行中でMyClassupdateProperty()更新が に通知された後UISourceUpdatingfalse に設定されます (その後、TargetUpdateを介して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;                
        }
    }

}

出力:

2 つの同時更新/ ボタンが 1 回クリックされる:

アップデート1

多くの同時更新/ボタンが何度もクリックされた:

update2

TargetUpdated SO 更新後、並べ替えまたはフィルタリングが行われると、バインディングはイベントを呼び出す必要がないことを認識します。ソース コレクションの更新が進行中の場合にのみ、バインドがリセットされてTargetUpdatedイベントが呼び出されます。初期の発色問題もこれで解決。

TextBoxただし、エディターの場合、ロジックはデータ型と UI ロジックの複雑さに基づいているため、ロジックにはまだいくつかの種類があるため、コードはより複雑になり、初期バインディングのリセットでも行全体がアニメーション化されTargetUpdated、行のすべてのセルに対して発生します。 .

于 2016-06-02T09:59:57.463 に答える