Determine if Diagram has changed

7 posts, 1 answers
  1. The Cowboy
    The Cowboy avatar
    19 posts
    Member since:
    Mar 2010

    Posted 04 May 2012 Link to this post

    What is the best method to determine if a given Diagram has changed (i.e. attributes of a shape changed, new shape, etc.) when not using a diagram bound with GraphSource?
  2. Francois Vanderseypen
    Francois Vanderseypen avatar
    46 posts
    Member since:
    Oct 2009

    Posted 04 May 2012 Link to this post

    Ultimately the diagram framework should implement an easy to use property which tells you whether the diagram has changed. For now, the best option is to compute a hash of the (saved) diagram. For example, something like the following:

    public int ComputeHash(string path) {
      System.Security.Cryptography.HashAlgorithm hashAlgorithm System.Security.Cryptography.HashAlgorithm.Create();
      FileStream fs = new FileStream(path, FileMode.Open);
      byte[] fileHash = hashAlgorithm.ComputeHash(fs);
      fs.Close();
      return BitConverter.ToInt32(fileHash, 0);
    }

    Hope this helps, Fr.
  3. UI for WPF is Visual Studio 2017 Ready
  4. The Cowboy
    The Cowboy avatar
    19 posts
    Member since:
    Mar 2010

    Posted 05 May 2012 Link to this post

    Agreed it should be built in to the RadDiagram.

    If I want to bind to my own "IsDirty" property (say for a save button), I really need to listen to all the events which would indicate changes to the Diagram... not pretty, but it will work.
  5. Francois Vanderseypen
    Francois Vanderseypen avatar
    46 posts
    Member since:
    Oct 2009

    Posted 05 May 2012 Link to this post

    As I tried to explain, you don't need to listen to all the events. You simply compare the hashes of the two XML files. Use the Save() method, compute the hash and compare with a previous hash value.

    Fr.

  6. The Cowboy
    The Cowboy avatar
    19 posts
    Member since:
    Mar 2010

    Posted 07 May 2012 Link to this post

    I understood your approach, but I guess I should have been a little clearer in what I am aiming for: a dependency property, to which I can bind--say a save button--and know when the RadDiagram is dirty.
  7. Answer
    Francois Vanderseypen
    Francois Vanderseypen avatar
    46 posts
    Member since:
    Oct 2009

    Posted 07 May 2012 Link to this post

    The trick goes as follows;

    add the hash computation to your code

    public int ComputeHash()
    {
        var hashAlgorithm = new SHA512Managed();
     
        var fs = new MemoryStream();
        var xml = diagram.Save();
        new StreamWriter(fs).Write(xml);
        fs.Position = 0;
        var fileHash = hashAlgorithm.ComputeHash(fs);
        fs.Close();
        return BitConverter.ToInt32(fileHash, 0);
    }

    In the onload event you set

    lastTick = DateTime.Now;
    this.refHash = this.ComputeHash();
    diagram.LayoutUpdated += DiagramOnLayoutUpdated;

    and add the handler

    private void DiagramOnLayoutUpdated(object sender, EventArgs eventArgs)
    {
        var now = DateTime.Now;
        if ((now - lastTick).TotalSeconds > 5)
        {
            var newhash = this.ComputeHash();
            this.SaveEnabled = this.refHash != newhash;
        }
    }

    This means that the check occurs only if some activity happened on the surface and I added a time window of five seconds since it otherwise overloads things, but you can change this as you wish.

    The dependency prop is standard:

    public static readonly DependencyProperty SaveEnabledProperty =
        DependencyProperty.Register("SaveEnabled", typeof(bool), typeof(MainWindow),
            new FrameworkPropertyMetadata(false,OnSaveEnabledChanged));
     
          
    public bool SaveEnabled
    {
        get { return (bool)GetValue(SaveEnabledProperty); }
        set { SetValue(SaveEnabledProperty, value); }
    }
     
          
    private static void OnSaveEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((MainWindow)d).OnSaveEnabledChanged(e);
    }
     
              
    protected virtual void OnSaveEnabledChanged(DependencyPropertyChangedEventArgs e)
    {
    }

    which can be bound to a button

    <telerik:RadButton Width="20" Height="50" Content="Save" Margin="5" IsEnabled="{Binding SaveEnabled}" />


    This is not the most pleasing way to proceed but I'd hope it helps you out, for now.


    Fr.
  8. The Cowboy
    The Cowboy avatar
    19 posts
    Member since:
    Mar 2010

    Posted 07 May 2012 Link to this post

    Thanks.  This will work, although the LayoutUpdated event is fired quite frequently--even when the mouse is just moving it seems--so, I will have to weigh the performance hit vs. functionality.  I look forward to having solved natively in future releases.
Back to Top
UI for WPF is Visual Studio 2017 Ready