2011-07-07 37 views
2

我一直在努力这一段时间了。我在我的应用程序中有一个Master/Details布局,和其他许多人一样,DataGrid在禁用它时遇到了问题。 Essencialy在从列表中选择一个元素以填充一系列字段后,用户按下“Edit”,这将禁用DataGrid并启用所有表单的字段。按下“保存”按钮将在保存数据后恢复这些操作...相当海峡向前。WPF DataGrid - 禁用时保留选择

我在Windows 7中与2010年深化发展VS .NET Framework 4的

我曾尝试:
1)基于this post,我曾尝试使用DataGrid在2009年6月版WPF工具包,但我有同样的反应。
2)基于this WPF CodePlex bug report,我试图创建一个基于DataGrid的自定义控件,并重写OnIsEnabledChanged调用来移除对“UnselectAllCells”的调用,但没有代码示例,我甚至无法启动它一旦。我曾尝试过:

public class FormMainDataGrid : DataGrid 
{ 
    static FormMainDataGrid() 
    { 
     IsEnabledProperty.OverrideMetadata(typeof(FormMainDataGrid), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsEnabledChanged))); 
    } 

    public FormMainDataGrid() : base() { } 

    private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     d.CoerceValue(CanUserAddRowsProperty); 
     d.CoerceValue(CanUserDeleteRowsProperty); 

     //this was added in new version !!! 
     /* 
     if (!(bool)(e.NewValue)) 
     { 
      ((DataGrid)d).UnselectAllCells(); 
     } 
     */ 

     // Many commands use IsEnabled to determine if they are enabled or not 
     CommandManager.InvalidateRequerySuggested(); 
    } 
} 

但是,只要我禁用DataGrid,这仍然取消选择当前选定的行。我试图interprete的最新留言(在Codeplex上的错误报告)像这样:

public class FormMainDataGrid : DataGrid 
{ 
    static FormMainDataGrid() 
    { 

    } 

    public static void OverrideStuff() 
    { 
     IsEnabledProperty.OverrideMetadata(typeof(FormMainDataGrid), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnIsEnabledChanged))); 
    } 

    public FormMainDataGrid() : base() { } 

    private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     d.CoerceValue(CanUserAddRowsProperty); 
     d.CoerceValue(CanUserDeleteRowsProperty); 

     //this was added in new version !!! 
     /* 
     if (!(bool)(e.NewValue)) 
     { 
      ((DataGrid)d).UnselectAllCells(); 
     } 
     */ 

     // Many commands use IsEnabled to determine if they are enabled or not 
     CommandManager.InvalidateRequerySuggested(); 
    } 
} 

public partial class App : Application 
{ 
    protected override void OnStartup(StartupEventArgs e) 
    { 
     FormMainDataGrid.OverrideStuff(); 
     base.OnStartup(e); 
    } 
} 

,但甚至不火法的修改版本。

首先,我正在为此做正确的方式?考虑到Deselection是由这种方法引起的,我可以完全替换为我自己的方法调用'OnIsEnabledChanged'的内部函数吗? 有没有另一种方法可以解决这个问题? 或更具体地说,我如何停止调用这个方法的基本版本,因为它不是一个覆盖,因此我不能'不'调用base.OnIsEnabledChanged

非常感谢!

回答

0

与上下键相同的问题仍然存在与IsHitTestVisible = false。

所以我最后做的是重新工作这样的自定义控件:

public class FormMainDataGrid : DataGrid 
    { 
     public FormMainDataGrid() : base() { 
      this.IsEnabledChanged += new DependencyPropertyChangedEventHandler(DataGrid_IsEnabledChanged); 
      this.SelectionChanged += new SelectionChangedEventHandler(DataGrid_SelectionChanged); 
     } 

     private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs args) 
     { 
      if (this.IsEnabled) 
      { 
       _selectedValue = this.SelectedValue; 
      } 
     } 

     private object _selectedValue; 

     private void DataGrid_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs args) 
     { 
      this.Dispatcher.BeginInvoke((Action)(() => 
      { 
       this.SelectedValue = _selectedValue; 
      }), null); 
     } 
    } 

这工作得很好...我只是要小心,因为改变的SelectedValue当控制是禁用的意志然后把它跟踪...

因此,总而言之,我相信你的解决方案是最完整的,但我允许我保持我的表单的代码为尽可能的精益&。

感谢您的帮助!

1

我通常不会专门为此原因禁用控件。我已经发现要么使得保持其数据绑定当前的控件崩溃或者如果我必须保持其可见但不允许任何交互,将通常折叠并且在命令上可见的部分透明的黑色边框置于其上。

+0

THX战士。叠加的问题是,即使通过放置DataGrid Focusable = False,AllowKeyboardFocus = False,用户仍然可以使用该选择(按下键盘上的向上和向下箭头,出于某种原因导致焦点转到下一个直到它触及DataGrid,然后开始滚动它)。我意识到,行细节模式更受鼓励,但我不是UI设计师,像这样的设计限制不会让设计师感到高兴! ;-) – JFTxJ

+0

尝试设置IsHitTestVisible = False。用户不应该能够影响它。 – CodeWarrior

3

为了将来的参考,如果有人遇到同样的问题。
重新设置SelectedValue有很多副作用。
这是覆盖在网格中的元数据的正确方法是:

public class MyDataGrid : DataGrid 
{ 
    static MyDataGrid() 
    { 
     IsEnabledProperty.OverrideMetadata(typeof(MyDataGrid), new CustomFrameworkPropertyMetadata(OnIsEnabledChanged)); 
    } 

    /// <summary> 
    /// Fixes the issue that the DataGrid's selection is cleared whenever the DataGrid is disabled. 
    /// Tricky: this issue only happens for 4.0 installations, it is fixed in 4.5 (in-place upgrade) installations. 
    /// </summary> 
    /// <param name="d"></param> 
    /// <param name="e"></param> 
    private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     d.CoerceValue(CanUserAddRowsProperty); 
     d.CoerceValue(CanUserDeleteRowsProperty); 

     //this is there in 4.0 dlls, not in the in-place upgrade 4.5 dlls. 
     //if (!(bool)(e.NewValue)) 
     //{ 
     // ((DataGrid)d).UnselectAllCells(); 
     //} 

     CommandManager.InvalidateRequerySuggested(); 
    } 

    class CustomFrameworkPropertyMetadata : FrameworkPropertyMetadata 
    { 
     public CustomFrameworkPropertyMetadata(PropertyChangedCallback propertyChangedCallback) 
      : base(propertyChangedCallback) 
     { 
     } 

     protected override void Merge(PropertyMetadata baseMetadata, DependencyProperty dp) 
     { 
      // See: http://msdn.microsoft.com/en-us/library/system.windows.propertymetadata.merge.aspx 
      // See: http://msdn.microsoft.com/en-us/library/ms751554.aspx 
      // By default, PropertyChangedCallbacks are merged from all owners in the inheritance hierarchy, 
      // so all callbacks are called whenever the property changes. 
      var thisPropertyChangedCallback = this.PropertyChangedCallback; 

      base.Merge(baseMetadata, dp); 

      // We do NOT want that default behavior here; 
      // The callback of DataGrid should not be called here - it clears the selection, we don't want that. 
      // But the callback of UIElement should be called here - it visually disabled the element, we still want that. 
      if (baseMetadata.PropertyChangedCallback != null) 
      { 
       Delegate[] invocationList = baseMetadata.PropertyChangedCallback.GetInvocationList(); 
       PropertyChangedCallback inheritedPropertyChangedCallback = null; 
       foreach (var invocation in invocationList) 
       { 
        if (invocation.Method.DeclaringType == typeof(DataGrid)) 
        { 
         // Do nothing; don't want the callback from DataGrid that clears the selection. 
        } 
        else 
        { 
         inheritedPropertyChangedCallback = inheritedPropertyChangedCallback == null 
          ? (PropertyChangedCallback)invocation 
          : (PropertyChangedCallback)Delegate.Combine(inheritedPropertyChangedCallback, invocation); 
        } 

       } 
       this.PropertyChangedCallback = thisPropertyChangedCallback != null 
                ? (PropertyChangedCallback)Delegate.Combine(inheritedPropertyChangedCallback, thisPropertyChangedCallback) 
                : inheritedPropertyChangedCallback; 
      } 
     } 
    } 
} 



注意,在这篇文章中提到的问题只发生在安装4.0的安装没有4.5。
它在.net 4.5中“固定”,即使是针对4.0 (“4.5是in-place upgrade”场景/ misery)的应用程序。

问候,
公园