WPF DataGrid में सिंगल क्लिक चेकबॉक्स चयन कैसे करें?


143

मेरे पास एक डेटाग्रिड है जिसमें पहला कॉलम टेक्स्ट कॉलम और दूसरा कॉलम चेकबॉक्स कॉलम के रूप में है। मैं जो चाहता हूं, अगर मैं चेक बॉक्स पर क्लिक करता हूं। इसकी जांच होनी चाहिए।

लेकिन, चयनित होने में दो क्लिक लगते हैं, पहले क्लिक के लिए सेल चयनित हो रही है, दूसरे क्लिक के लिए चेक बॉक्स की जाँच हो रही है। एक क्लिक के साथ चेक / अनचेक करने के लिए चेक बॉक्स कैसे बनाएं।

मैं WPF 4.0 का उपयोग कर रहा हूँ। DataGrid में कॉलम AutoGenerated हैं।


4
की डुप्लिकेट: stackoverflow.com/questions/1225836/… , लेकिन यह एक बेहतर शीर्षक है
सर्फ 1

जवाबों:


189

सिंगल क्लिक डेटागेट चेकबॉक्स के लिए आप बस नियमित चेकबॉक्स नियंत्रण को अंदर DataGridTemplateColumnऔर सेट कर सकते हैं UpdateSourceTrigger=PropertyChanged

<DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <CheckBox IsChecked="{Binding Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
    </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

4
वाह - मुझे खुशी है कि मैं अंत तक पढ़ा। यह पूरी तरह से काम करता है और काफी कम जटिल है, IMO इसे उत्तर के रूप में चिह्नित किया जाना चाहिए।
टॉड

2
यह भी ComboBox के लिए काम करता है। जैसे: रास्ते में, DataGridComboBoxColumn की तुलना में बेहतर है।
user1454265

2
यह तब नहीं होता है जब मैं दूसरे सेल में जाने के लिए / तीर को चेक / अनचेक करने के लिए स्पेस बार का उपयोग करता हूं।
योला

1
मैंने इस उत्तर की व्याख्या की है कि आपको "IsSelected" को बाइंड करना है, लेकिन यह सच नहीं है! आप बस अपने खुद के बंधन केDataGridTemplateColumn.CellTemplate साथ उपयोग कर सकते हैं और यह काम करेगा !! @ वीडियन-हुआंग के उत्तर ने मुझे यह समझने में मदद की कि, धन्यवाद!
AstralisSomnium

62

मैंने इसे निम्नलिखित शैली के साथ हल किया है:

<Style TargetType="DataGridCell">
     <Style.Triggers>
         <Trigger Property="IsMouseOver" Value="True">
             <Setter Property="IsEditing" Value="True" />
         </Trigger>
     </Style.Triggers>
 </Style>

निश्चित रूप से विशिष्ट कॉलमों के लिए इसे आगे अनुकूलित करना संभव है ...


8
अच्छा लगा। मैंने इसे मल्टीग्रेगर में बदल दिया और ReadOnly = False के लिए एक शर्त जोड़ दी लेकिन मूल दृष्टिकोण ने मेरे सरल मामले के लिए काम किया जहां कीबोर्ड नेविगेशन महत्वपूर्ण नहीं है।
मार्के

उस शैली को मेरी ग्रिड में जोड़ने से ऑपरेशन का एक अपवाद बढ़ जाता है जो मान्य नहीं है जबकि आइटम स्रोत उपयोग में है। इसके बजाय ItemControl.ItemsSource के साथ तत्वों को एक्सेस और संशोधित करें।
Alkampfer

1
यह अब तक का सबसे साफ तरीका है! अच्छा! (IsReadOnly = "True" के लिए एक मल्टीट्रैगर काम करेगा)
FooBarTheLittle

2
इस समाधान में कुछ अप्रत्याशित / अवांछित व्यवहार है। देखें stackoverflow.com/q/39004317/2881450
jHilscher

2
काम के लिए बाध्य के लिए, आप एक UpdateSourceTrigger = PropertyChanged की आवश्यकता होगी
AQuirky

27

सबसे पहले, मुझे पता है कि यह एक बहुत पुराना प्रश्न है, लेकिन मैंने अभी भी सोचा था कि मैं इसका उत्तर दूंगा।

मुझे कुछ दिनों पहले भी यही समस्या थी और इसके लिए आश्चर्यजनक रूप से संक्षिप्त समाधान आया (देखें यह ब्लॉग )। मूल रूप से, आपको बस DataGridCheckBoxColumnअपने XAML में परिभाषा को निम्नलिखित के साथ बदलना होगा :

<DataGridTemplateColumn Header="MyCheckBoxColumnHeader">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding Path=MyViewModelProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

इस समाधान का उल्टा स्पष्ट है - यह केवल XAML है; इस प्रकार यह अतिरिक्त यूआई लॉजिक के साथ आपके कोड-बैक पर बोझ डालने से प्रभावी रूप से आपको बचाता है और एमवीवीएम ज़ीलॉट्स की आँखों में आपकी स्थिति बनाए रखने में मदद करता है;)।


1
यह कॉन्स्टेंटिन सलावातोव के जवाब के समान है और यह मेरे लिए काम करता है। कोड नमूने को शामिल करने के लिए +1, जहां उसका नहीं था। एक पुराने प्रश्न के अच्छे उत्तर के लिए धन्यवाद।
डॉन हेरोड

1
इसके साथ समस्या यह है कि यदि आप इसे कॉम्बोक्स कॉलम के साथ करते हैं, तो थोड़ा ड्रॉपडाउन बटन उस कॉलम के सभी सेल के लिए हर समय दिखाई देगा। सिर्फ जब आप सेल पर क्लिक करते हैं।
user3690202

18

बनाने के Konstantin Salavatov के जवाब के साथ काम करने AutoGenerateColumns, के लिए एक ईवेंट हैंडलर जोड़ने DataGridके AutoGeneratingColumnनिम्न कोड के साथ:

if (e.Column is DataGridCheckBoxColumn && !e.Column.IsReadOnly)
{
    var checkboxFactory = new FrameworkElementFactory(typeof(CheckBox));
    checkboxFactory.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Center);
    checkboxFactory.SetValue(FrameworkElement.VerticalAlignmentProperty, VerticalAlignment.Center);
    checkboxFactory.SetBinding(ToggleButton.IsCheckedProperty, new Binding(e.PropertyName) { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });

    e.Column = new DataGridTemplateColumn
        {
            Header = e.Column.Header,
            CellTemplate = new DataTemplate { VisualTree = checkboxFactory },
            SortMemberPath = e.Column.SortMemberPath
        };
}

इससे सभी DataGridस्वतः-जनरेट किए गए चेकबॉक्स कॉलम "सिंगल क्लिक" संपादन योग्य बन जाएंगे।


ऑटोजेनरेटेड कॉलम दृष्टिकोण में भरने के लिए धन्यवाद, यह हाथ मुझे एक उपयुक्त दिशा में इंगित करता है।
192 पर el2iot2

17

गोब्लिन के उत्तर में संदर्भित ब्लॉग के आधार पर, लेकिन .NET 4.0 में काम करने के लिए और पंक्ति-चयन मोड के साथ संशोधित किया गया।

ध्यान दें कि यह DataGridComboBoxColumn संपादन को गति देता है - संपादन मोड में प्रवेश करके और सिंगल क्लिक या टेक्स्ट इनपुट पर ड्रॉपडाउन प्रदर्शित करता है।

XAML:

        <Style TargetType="{x:Type DataGridCell}">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown" />
            <EventSetter Event="PreviewTextInput" Handler="DataGridCell_PreviewTextInput" />
        </Style>

कोड के पीछे:

    private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private void DataGridCell_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        GridColumnFastEdit(cell, e);
    }

    private static void GridColumnFastEdit(DataGridCell cell, RoutedEventArgs e)
    {
        if (cell == null || cell.IsEditing || cell.IsReadOnly)
            return;

        DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
        if (dataGrid == null)
            return;

        if (!cell.IsFocused)
        {
            cell.Focus();
        }

        if (cell.Content is CheckBox)
        {
            if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
            {
                if (!cell.IsSelected)
                    cell.IsSelected = true;
            }
            else
            {
                DataGridRow row = FindVisualParent<DataGridRow>(cell);
                if (row != null && !row.IsSelected)
                {
                    row.IsSelected = true;
                }
            }
        }
        else
        {
            ComboBox cb = cell.Content as ComboBox;
            if (cb != null)
            {
                //DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
                dataGrid.BeginEdit(e);
                cell.Dispatcher.Invoke(
                 DispatcherPriority.Background,
                 new Action(delegate { }));
                cb.IsDropDownOpen = true;
            }
        }
    }


    private static T FindVisualParent<T>(UIElement element) where T : UIElement
    {
        UIElement parent = element;
        while (parent != null)
        {
            T correctlyTyped = parent as T;
            if (correctlyTyped != null)
            {
                return correctlyTyped;
            }

            parent = VisualTreeHelper.GetParent(parent) as UIElement;
        }
        return null;
    }

इस समाधान ने मेरे लिए सबसे अच्छा काम किया। मेरा बाध्य दृश्यमॉडल अन्य समाधानों के साथ अद्यतन नहीं कर रहा था।
BrokeMyLegBiking

@surfen, क्या मुझे उपरोक्त शैली और कोड हर पृष्ठ और उसके कोडहैंड में डालने की आवश्यकता है, अगर मेरे पास कई पृष्ठ हैं, जिसमें डेटाग्रिड है। तो क्या स्टाइल और कोड का उपयोग आम जगह पर करने के बजाय इसे बनाने में संभव है? हर पेज
एंजेल

आपको खाली एक्शन भेजने की आवश्यकता क्यों है?
user3690202

@ user3690202 यह विंडोज में DoEvents की तरह है। BeginEdit को कॉल करने के बाद आपको वास्तव में संपादन मोड में प्रवेश करने के लिए सेल की प्रतीक्षा करनी होगी।
जीका स्केला

@ Ji @íSkála - मुझे इस समस्या के समाधान में कभी ऐसा करने की आवश्यकता नहीं है, लेकिन मैं समझता हूँ कि आप क्या कह रहे हैं - धन्यवाद!
user3690202

10

मैंने इन सुझावों की कोशिश की है, और बहुत से अन्य मैंने अन्य साइटों पर पाए हैं, लेकिन उनमें से कोई भी मेरे लिए बहुत काम नहीं करता है। अंत में, मैंने निम्नलिखित समाधान बनाया।

मैंने अपना खुद का डेटाग्रिड-इनहेरिटेड कंट्रोल बनाया है, और बस इस कोड को इसमें जोड़ा है:

public class DataGridWithNavigation : Microsoft.Windows.Controls.DataGrid
{
    public DataGridWithNavigation()
    {
        EventManager.RegisterClassHandler(typeof(DataGridCell), 
            DataGridCell.PreviewMouseLeftButtonDownEvent,
            new RoutedEventHandler(this.OnPreviewMouseLeftButtonDown));
    }


    private void OnPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
        {
          DependencyObject obj = FindFirstControlInChildren(cell, "CheckBox");
            if (obj != null)
            {
                System.Windows.Controls.CheckBox cb = (System.Windows.Controls.CheckBox)obj;
                cb.Focus();
                cb.IsChecked = !cb.IsChecked;
            }
        }
    }

    public DependencyObject FindFirstControlInChildren(DependencyObject obj, string controlType)
    {
        if (obj == null)
            return null;

        // Get a list of all occurrences of a particular type of control (eg "CheckBox") 
        IEnumerable<DependencyObject> ctrls = FindInVisualTreeDown(obj, controlType);
        if (ctrls.Count() == 0)
            return null;

        return ctrls.First();
    }

    public IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, string type)
    {
        if (obj != null)
        {
            if (obj.GetType().ToString().EndsWith(type))
            {
                yield return obj;
            }

            for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
                {
                    if (child != null)
                    {
                        yield return child;
                    }
                }
            }
        }
        yield break;
    }
}

यह सब क्या करता है?

खैर, हर बार जब हम अपने डेटाग्रिड में किसी सेल पर क्लिक करते हैं, तो हम देखते हैं कि सेल में चेकबॉक्स नियंत्रण है या नहीं। यदि ऐसा होता है , तो हम उस चेकबॉक्स पर ध्यान केंद्रित करेंगे और उसके मूल्य को टॉगल करेंगे

यह मेरे लिए काम करने लगता है, और एक अच्छा, आसानी से पुन: प्रयोज्य समाधान है।

यह निराशाजनक है कि हमें ऐसा करने के लिए कोड लिखने की आवश्यकता है। पहला माउस क्लिक (एक डेटाग्रिड के चेकबॉक्स पर) की व्याख्या "अनदेखा" की जाती है, क्योंकि WPF इसे पंक्ति को एडिट मोड में डालने के लिए उपयोग करता है, यह तार्किक लग सकता है, लेकिन वास्तविक दुनिया में, यह हर वास्तविक एप्लिकेशन के काम करने के तरीके के खिलाफ जाता है।

यदि कोई उपयोगकर्ता अपनी स्क्रीन पर एक चेकबॉक्स देखता है, तो उसे टिक / अनटिक करने के लिए एक बार उस पर क्लिक करने में सक्षम होना चाहिए। कहानी का अंत।


1
धन्यवाद, मैंने "समाधान" का एक गुच्छा लेने की कोशिश की है, लेकिन यह पहली बार है जो वास्तव में हर बार काम करता है। और यह मेरे एप्लिकेशन आर्किटेक्चर में खूबसूरती से फिट बैठता है।
Guge

यह समाधान बाइंडिंग को अद्यतन करने वाले मुद्दों के परिणामस्वरूप होता है, जबकि यहाँ: wpf.codeplex.com/wikipage?title=Single-Click%20Editing नहीं करता है।
जस्टिन साइमन

2
बहुत जटिल। मेरा जवाब देखिए। :)
कॉन्स्टेंटिन सालावटोव

1
5 वर्षों के बाद यह कोड अभी भी सामाजिक जीवन के लिए समय बचा रहा है :) कुछ सरल आवश्यकताओं के लिए, @KonstantinSalavatov समाधान पर्याप्त है। मेरे मामले में मैंने हैंडलर के साथ डायनेमिक इवेंट एसोसिएशन को प्राप्त करने के लिए माइक के समाधान के साथ अपने कोड को मिलाया, मेरे ग्रिड में स्तंभों की डायनामिक संख्या है, डेटाबेस में परिवर्तनों को संग्रहीत करने के लिए विशिष्ट सेल में एक क्लिक के साथ।
फेर आर

8

यहाँ बहुत सरल उपाय है।

          <DataGridTemplateColumn MinWidth="20" >
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Grid>
                            <CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        </Grid>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

यदि आप DataGridCheckBoxColumnकार्यान्वित करने के लिए उपयोग करते हैं, तो पहली क्लिक फोकस करने के लिए है, दूसरी क्लिक चेक करने के लिए है।

लेकिन DataGridTemplateColumnलागू करने के लिए केवल एक क्लिक की जरूरत है।

DataGridComboboxBoxColumnद्वारा उपयोग और कार्यान्वयन का अंतर DataGridTemplateColumnभी समान है।


मेरे लिए अच्छा स्पष्टीकरण और तुरन्त काम किया, धन्यवाद!
AstralisSomnium

8

मैंने इसके साथ हल किया:

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Viewbox Height="25">
                <CheckBox IsChecked="{Binding TheProperty, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
            </Viewbox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

एकल क्लिक पर सक्रिय चेकबॉक्स!


2
मुझे चेकबॉक्स को व्यूबॉक्स में लपेटने की आवश्यकता नहीं थी, लेकिन इस जवाब ने मेरे लिए काम किया।
JGeerWM

3
यह मेरे लिए स्वीकृत जवाब की तुलना में बहुत अधिक क्लीनर समाधान है। व्यूबॉक्स की भी जरूरत नहीं। मज़ेदार यह परिभाषित चेकबॉक्स कॉलम से बेहतर कैसे काम करता है।
केनजरा

6

पर आधारित जिम एडोर्नो के जवाब और उनकी पोस्ट पर टिप्पणियों के , यह इसके साथ समाधान है MultiTrigger:

<Style TargetType="DataGridCell">
  <Style.Triggers>
    <MultiTrigger>
      <MultiTrigger.Conditions>
    <Condition Property="IsReadOnly" Value="False" />
    <Condition Property="IsMouseOver" Value="True" />
      </MultiTrigger.Conditions>
      <Setter Property="IsEditing" Value="True" />
    </MultiTrigger>
  </Style.Triggers>
</Style>

5

फिर भी एक और सरल उपाय इस शैली को अपने DataGridColumn में जोड़ना है। आपकी शैली का शरीर खाली हो सकता है।

<DataGridCheckBoxColumn>
     <DataGridCheckBoxColumn.ElementStyle>
          <Style TargetType="CheckBox">
           </Style>
     </DataGridCheckBoxColumn.ElementStyle>
</DataGridCheckBoxColumn>

2
चेक / अनचेक करने के लिए स्पेस बार दबाने से चेकबॉक्स बाईं ओर से मध्य में चला जाएगा। स्टाइल में <सेटर प्रॉपर्टी = "हॉरिज़ॉन्टल एलाइमेंट" वैल्यू = "सेंटर" /> जोड़ने से चेकबॉक्स को हिलने से रोका जा सकेगा।
यिंगिंगचेन

1
<Style x:Key="StilCelula" TargetType="DataGridCell"> 
<Style.Triggers>
 <Trigger Property="IsMouseOver" Value="True">
   <Setter Property="IsEditing" 
     Value="{Binding RelativeSource={x:Static RelativeSource.Self}, 
     Converter={StaticResource CheckBoxColumnToEditingConvertor}}" />
 </Trigger>
</Style.Triggers>
<Style>
Imports System.Globalization
Public Class CheckBoxColumnToEditingConvertor
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.Convert
        Try

            Return TypeOf TryCast(value, DataGridCell).Column Is DataGridCheckBoxColumn
        Catch ex As Exception
            Return Visibility.Collapsed
        End Try
    End Function

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.