Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF DataGrid-禁用时保留选择_C#_Wpf_Datagrid_Selection - Fatal编程技术网

C# WPF DataGrid-禁用时保留选择

C# WPF DataGrid-禁用时保留选择,c#,wpf,datagrid,selection,C#,Wpf,Datagrid,Selection,我已经为此挣扎了一段时间了。我的应用程序中有一个主/详细布局,与其他许多人一样,我面临着DataGrid在禁用时失去选择的问题。基本上,在从列表中选择一个元素以填充一系列字段后,用户按“编辑”,这将禁用DataGrid并启用表单的所有字段。保存数据后,按“保存”按钮将恢复这些操作。。。向前走了很长一段路 我正在使用.NETFramework4中的VS2010开发Windows7 我的尝试: 1) 基于,我曾尝试在2009年6月版的WPF工具包中使用DataGrid,但我有同样的反应。 2) 基于

我已经为此挣扎了一段时间了。我的应用程序中有一个主/详细布局,与其他许多人一样,我面临着DataGrid在禁用时失去选择的问题。基本上,在从列表中选择一个元素以填充一系列字段后,用户按“编辑”,这将禁用DataGrid并启用表单的所有字段。保存数据后,按“保存”按钮将恢复这些操作。。。向前走了很长一段路

我正在使用.NETFramework4中的VS2010开发Windows7

我的尝试:
1) 基于,我曾尝试在2009年6月版的WPF工具包中使用DataGrid,但我有同样的反应。
2) 基于,我尝试基于DataGrid创建一个自定义控件,并重写OniseEnabledChanged调用以删除对“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后立即取消选择当前选定的行。我试着这样解释最后的评论(在Codeplex bug报告中):

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);
    }
}  
但这甚至不会触发该方法的修改版本

首先,我走对了吗?考虑到取消选择是由此方法引起的,我是否可以完全替换我自己的方法对“OnIsEnabledChanged”的内部调用? 我还有别的办法解决这个问题吗? 或者更具体地说,我如何停止对该方法的基本版本的调用,因为它不是重写,因此我不能“不”调用
base.OnIsEnabledChanged


非常感谢

我通常不会专门为此禁用控件。我发现更好的方法是要么折叠保持其数据绑定最新的控件,要么如果我必须使其可见但不允许任何类型的交互,将一个部分透明的黑色边框放置在其上,该边框通常会折叠并在命令中可见。

使用上下键时仍然存在相同的问题,IshittesVisible=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会使它偏离轨道

总之,我相信您的解决方案是最完整的,但我的解决方案使我的表单代码尽可能精简


谢谢你的帮助

如果有人遇到相同的问题,请以后参考
重新设置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;
            }
        }
    }
}
公共类MyDataGrid:DataGrid { 静态MyDataGrid() { OverrideMetadata(typeof(MyDataGrid),新的CustomFrameworkPropertyMetadata(OniseEnabledChanged)); } /// ///修复了每当禁用DataGrid时都会清除DataGrid的选择的问题。 ///棘手:此问题仅在4.0安装中发生,在4.5(就地升级)安装中已修复。 /// /// /// 私有静态无效OnInsEnabledChanged(DependencyObject d、DependencyPropertyChangedEventArgs e) { d、 强制值(CanUserAddRowsProperty); d、 强制值(CanUserDeleteRowsProperty); //这在4.0 DLL中存在,而不是在就地升级4.5 DLL中。 //如果(!(bool)(e.NewValue)) //{ //((DataGrid)d).取消选择所有单元格(); //} CommandManager.InvalidateRequestSuggested(); } 类CustomFrameworkPropertyMetadata:FrameworkPropertyMetadata { 公共CustomFrameworkPropertyMetadata(PropertyChangedCallback PropertyChangedCallback) :base(propertyChangedCallback) { } 受保护的覆盖无效合并(PropertyMetadata baseMetadata,DependencyProperty dp) { //见:http://msdn.microsoft.com/en-us/library/system.windows.propertymetadata.merge.aspx //见:http://msdn.microsoft.com/en-us/library/ms751554.aspx //默认情况下,PropertyChangedCallbacks从继承层次结构中的所有所有者合并, //因此,只要属性发生更改,就会调用所有回调。 var thisPropertyChangedCallback=this.PropertyChangedCallback; base.Merge(baseMetadata,dp); //我们不希望出现这种默认行为; //这里不应该调用DataGrid的回调-它会清除选择,我们不希望这样。 //但是UIElement的回调应该在这里调用——它在视觉上禁用了该元素,我们仍然需要它。 if(baseMetadata.PropertyChangedCallback!=null) { 委托[]调用列表=baseMetadata.PropertyChangedCallback.GetInvocationList(); PropertyChangedCallback继承PropertyChangedCallback=null; foreach(调用列表中的var调用) { if(invocation.Method.DeclaringType==typeof(DataGrid)) { //不执行任何操作;不希望来自DataGrid的回调清除选择。 } 其他的 { inheritedPropertyChangedCallback=inheritedPropertyChangedCallback==null ?(PropertyChangedCallback)调用 :(PropertyChangedCallback)委托。合并(inheritedPropertyChangedCallback,调用); } } this.PropertyChangedCallback=thisPropertyChangedCallback!=null ?(PropertyChangedCallback)委托。合并(继承的PropertyChangedCallback,thisPropertyChangedCallback) :继承属性