【问题标题】:WPF MVVM popup with checkBox inside DataGrid no fire events带有复选框的 WPF MVVM 弹出窗口在 DataGrid 内没有触发事件
【发布时间】:2018-03-12 09:34:37
【问题描述】:

这是我的目标(简化):创建一个 userControl 来显示可读的 bitField。

值为0x3的例子:想显示option1(bit 1):enable,option2(bit 2):enable,option3(bit 3):disable ...

userControl 行为:如果我单击此控件,它会打开一个带有复选框的弹出窗口(如组合框),允许您启用 optionX(这将更改值和显示的文本)。

这是我用于 UserControl 视图的源代码

<UserControl x:Name="userControl" x:Class="MyProg.Views.BitField"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:MyProg.Views"
             mc:Ignorable="d"
             >

    <Grid x:Name="LayoutRoot"  Height="{Binding ActualHeight, ElementName=userControl, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ActualWidth, ElementName=userControl, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <ToggleButton x:Name="TogglePopupButton" Background="Transparent" BorderBrush="Transparent" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"  >
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="auto" />
                </Grid.ColumnDefinitions>
                <Label Content="{Binding Path=Text}" Grid.Column="0" VerticalAlignment="Center" Margin="0,-5,0,-5" />
                <Path x:Name="Arrow" Grid.Column="1" Fill="Black"  VerticalAlignment="Center" Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z" HorizontalAlignment="Right"/>
            </Grid>
        </ToggleButton>

        <Popup x:Name="ToggledPopup" StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=TogglePopupButton, Mode=TwoWay}" Width="{Binding ActualWidth, ElementName=userControl, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"  Grid.Row="1">
            <Border Background="White" BorderThickness="1" BorderBrush="Black">
                <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="5"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="5"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>

                        <CheckBox Content="option 1" Grid.Column="0" />
                        <CheckBox Content="option 2" Grid.Column="2" />
                        <CheckBox Content="option 3" Grid.Column="4" />
                    </Grid>
                </ScrollViewer>
            </Border>
        </Popup>
    </Grid>

</UserControl>

绑定值的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MyProg.ViewModels;

namespace MyProg.Views
{
    /// <summary>
    /// Interaction logic for BitField.xaml
    /// </summary>
    public partial class BitField : UserControl
    {
        internal vmBitField m_ViewModel;

        public BitField()
        {
            InitializeComponent();
            // Load the viewModel
            m_ViewModel = new vmBitField();
            LayoutRoot.DataContext = m_ViewModel;
            m_ViewModel.PropertyChanged += M_ViewModel_PropertyChanged;
        }

        private void M_ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Value")
            {
                if(IntValue != m_ViewModel?.Value)
                    IntValue = (int)m_ViewModel.Value;
            }
        }

        /// <summary>
        /// Gets or sets the value which is displayed
        /// </summary>
        public int IntValue
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value);}
        }

        /// <summary>
        /// Identified the Value dependency property
        /// </summary>
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("IntValue", typeof(int), typeof(BitField), new PropertyMetadata(0, OnIntValueSet));

        private static void OnIntValueSet(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((BitField)d).m_ViewModel.Value = (uint?)(int)e.NewValue;
        }
    }
}

和 UserControl 视图模型

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MyProg.MVVM;

namespace MyProg.ViewModels
{
    class vmBitField : ViewModelBase
    {
        #region Members
        protected uint m_Value = 0; // 7
        #endregion

        #region Properties
        public uint? Value { get { return m_Value; } set { if (value != m_Value) { m_Value = (uint)value; RaiseEventPropertyChanged("Option1"); RaiseEventPropertyChanged("Option2"); RaiseEventPropertyChanged("Option3"); RaiseEventPropertyChanged("Text"); } } }
        public bool Option1 { get {return (Value & 0x1) == 1; } set { if (value != Option1) { m_Value ^= 0x1; RaiseEventPropertyChanged("Option1"); RaiseEventPropertyChanged("Value"); RaiseEventPropertyChanged("Text"); } } }
        public bool Option2 { get { return (Value & 0x2) == 1; } set { if (value != Option2) { m_Value ^= 0x2; RaiseEventPropertyChanged("Option2"); RaiseEventPropertyChanged("Value"); RaiseEventPropertyChanged("Text"); } } }
        public bool Option3 { get { return (Value & 0x4) == 1; } set { if (value != Option3) { m_Value ^= 0x4; RaiseEventPropertyChanged("Option3"); RaiseEventPropertyChanged("Value"); RaiseEventPropertyChanged("Text"); } } }
        public string Text { get { return "Option1:" + Option1 + " Option2:" + Option2 + " Option3:" + Option3; } }
        #endregion

        #region Contructors
        public vmBitField()
        {
        }
        #endregion

        #region Methodes
        #endregion
    }
}

当我在页面或窗口中插入此 userControl 时,这可以正常工作。

<local:LockType IntValue="{Binding Path=ValueAsInt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

现在,我有一个包含很多位域的列表。我想在数据网格中显示所有这些。所以我想在dataGrid中插入这个userControl。 这是添加数据网格的代码

<DataGrid Grid.Row="13"  Grid.ColumnSpan="3" AutoGenerateColumns="False" Name="dataGrid1" AlternationCount="2"
                  ItemsSource="{Binding Values}" 
                  CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserReorderColumns="False" >
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Id" HeaderStyle="{StaticResource DataGridHeaderCenter}" 
                                CellTemplate="{StaticResource IdText}"/>
        <DataGridTemplateColumn Header="Value" Width="400" HeaderStyle="{StaticResource DataGridHeaderCenter}" >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <local1:LockType IntValue="{Binding Path=ValueAsInt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="CurrentValue" 
                                CellTemplate="{StaticResource CurrentValueText}" />
    </DataGrid.Columns>
</DataGrid>

当我的用户控件在数据网格中时,当我单击切换按钮时,它会正确打开弹出窗口,但是我无法与弹出窗口中的任何复选框进行交互(选中或取消选中)。

任何人都可以帮助我找出为什么弹出窗口中的复选框没有触发事件? 如果需要,我可以添加更多信息。

最好的问候 杰米

【问题讨论】:

    标签: c# wpf mvvm datagrid popup


    【解决方案1】:

    您必须将弹出窗口的 F​​ocusManager.IsFocusScope 设置为 true。 您还可以通过样式设置器设置单元格的 IsFocussable 属性。

    <Style TargetType="{x:Type DataGridCell}"> <Setter Property="Focusable" Value="False"></Setter> </Style>
    

    它不允许您在弹出窗口上编辑任何内容的问题是因为单元格编辑尚未结束。因此,您还可以通过注册 DataGrid_CellEditEnding 事件来执行以下操作。

    private static void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
    {
        if (e.Column.GetType() == typeof(DataGridTemplateColumn))
        {
            var popup = GetVisualChild<Popup>(e.EditingElement);
            if (popup != null && popup.IsOpen)
            {
                e.Cancel = true;
            }
        }   
    }
    

    【讨论】:

    • 感谢您的回复,但无法正常工作。我将此添加到弹出窗口、复选框、数据网格、DataGridTemplateColumn、用户控件中,但没有任何效果。 IsFocussable 属性是指 Focusable="True",因为我找不到这个属性。
    • 所以它正在工作。我不需要在弹出窗口中设置 FocusManager.IsFocusScope。只添加` 跨度>
    • 是的,我在告诉你为什么它不起作用,因为那个事件没有完成并且focusable = false,那个事件甚至没有开始。我很高兴它有效!如果问题解决了您的问题,请将问题标记为已回答。
    猜你喜欢
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    • 2010-12-11
    • 2017-10-16
    • 1970-01-01
    相关资源
    最近更新 更多