您好,登錄后才能下訂單哦!
如何在c#中使用WPF對DataGrid中的Cell進行編輯?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
<Window x:Class="DataGridCellDoubleClickDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:xceed="http://schemas.xceed.com/wpf/xaml/datagrid" xmlns:models="clr-namespace:DataGridCellDoubleClickDemo.Models" xmlns:views="clr-namespace:DataGridCellDoubleClickDemo.Views" mc:Ignorable="d" Title="DataGridDemo" Height="450" Width="800"> <Window.Resources> <DataTemplate x:Key="CustomTemplate"> <Border BorderThickness="1" BorderBrush="Blue"> <TextBlock Text="{Binding Path=Display }" FontWeight="Bold" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" /> </Border> </DataTemplate> <DataTemplate x:Key="RowHeadTemplate" DataType="{x:Type models:RecipeControlVariable}"> <TextBlock Text="{Binding DisplayName}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Foreground="Black" FontSize="12"/> </DataTemplate> <xceed:DataGridCollectionViewSource x:Key="recipeData" Source="{Binding RecipeVariables}"></xceed:DataGridCollectionViewSource> </Window.Resources> <Grid> <xceed:DataGridControl x:Name="DataGridControl" AutoCreateColumns="False" FontSize="13" VerticalContentAlignment="Center" BorderBrush="Gray" BorderThickness="1" ItemsPrimaryAxis="Horizontal" PagingBehavior="LeftToRight" UpdateSourceTrigger="CellContentChanged" SelectionUnit="Cell" SelectionMode="Single" ItemsSource="{Binding Source={StaticResource recipeData}}"> <xceed:DataGridControl.View> <xceed:TableflowView FixedColumnCount="1" ContainerHeight="30" x:Name="tblView" VerticalGridLineThickness="0.5" HorizontalGridLineBrush="Gray" HorizontalGridLineThickness="1" VerticalGridLineBrush="Black" RowFadeInAnimationDuration="0" ScrollingAnimationDuration="0" ColumnStretchMinWidth="10" DetailIndicatorWidth="20" ShowRowSelectorPane="False" ShowScrollTip="False" UseDefaultHeadersFooters="False"> <xceed:TableflowView.FixedHeaders> <DataTemplate> <xceed:ColumnManagerRow AllowColumnReorder="False" AllowColumnResize="True" AllowDrop="False" AllowSort="False" /> </DataTemplate> </xceed:TableflowView.FixedHeaders> </xceed:TableflowView> </xceed:DataGridControl.View> <xceed:DataGridControl.DefaultCellEditors> <xceed:CellEditor x:Key="{x:Type models:SmartCellViewModel}"> <xceed:CellEditor.EditTemplate> <DataTemplate> <views:SmartCellEditor Content="{xceed:CellEditorBinding}" VerticalAlignment="Center" Height="{Binding ActualHeight,RelativeSource={RelativeSource AncestorType={x:Type Border},AncestorLevel=1}}"></views:SmartCellEditor> </DataTemplate> </xceed:CellEditor.EditTemplate> </xceed:CellEditor> </xceed:DataGridControl.DefaultCellEditors> </xceed:DataGridControl> </Grid> </Window>
在View部分主要是通過引用Xceed中的DataGridControl控件進行擴展的,這個里面主要是需要設置DataGridControl的View和DefaultCellEditor這個里面DefaultCellEditor是本文的重點,這個就是單元格Cell雙擊后進行編輯的主體,在這個里面我們需要指定CellEditor的EditTemplate,這里面需要匹配一個DataTemplate,這個里面是一個SmartCellEditor的子View,下面我們來看看這個SmartCellEditor里面是什么內容?
<UserControl x:Class="DataGridCellDoubleClickDemo.Views.SmartCellEditor" 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:conv="clr-namespace:DataGridCellDoubleClickDemo.Converters" xmlns:xceed="clr-namespace:Xceed.Wpf.Toolkit;assembly=Xceed.Wpf.Toolkit" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <UserControl.Resources> <conv:VisibilityConverter x:Key="visConverter" /> <conv:TimeSpanConverter x:Key="timeSpanConverter" /> <conv:NumConverter x:Key="numConverter" /> <conv:BoolConverter x:Key="boolConverter" /> </UserControl.Resources> <StackPanel Margin="0"> <!--TextBlock--> <TextBlock x:Name="textBlock" Background="{Binding Background}" Foreground="{Binding Foreground}" Text="{Binding Path=Display,Mode=OneWay}" ToolTip="{Binding ToolTip}" FontWeight="{Binding FontWeight}" VerticalAlignment="Stretch" Visibility="{Binding Path=., Converter={StaticResource visConverter},ConverterParameter=TextBlock}"/> <!--Editable ComboBox--> <ComboBox x:Name="editableComboBox" ItemsSource="{Binding SmartCellData.Selections}" IsEditable="True" VerticalAlignment="Stretch" VerticalContentAlignment="Center" DisplayMemberPath="SelectionDisplayName" Text="{Binding CellValue,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding Path=., Converter={StaticResource visConverter},ConverterParameter=EditableComboBox}" /> <!--Readonly ComboBox--> <ComboBox x:Name="readonlyComboBox" VerticalAlignment="Center" VerticalContentAlignment="Stretch" ItemsSource="{Binding SmartCellData.Selections}" IsEditable="False" DisplayMemberPath="SelectionDisplayName" SelectedValuePath="ControlName" SelectedValue="{Binding Path=CellValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding Path=., Converter={StaticResource visConverter},ConverterParameter=ReadonlyComboBox}" /> <!--Text Input TextBox--> <TextBox HorizontalContentAlignment="Left" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Text="{Binding CellValue}" Visibility="{Binding Path=., Converter={StaticResource visConverter},ConverterParameter=TextBox}" TextAlignment="Left" /> <!--Number Input TextBox--> <xceed:DecimalUpDown HorizontalContentAlignment="Left" VerticalAlignment="Stretch" VerticalContentAlignment="Center" FormatString="G" Value="{Binding Path=CellValue,Converter={StaticResource numConverter},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Increment="1" Visibility="{Binding Path=., Converter={StaticResource visConverter},ConverterParameter=DecimalUpDown}" TextAlignment="Left" /> <!--CheckBox--> <CheckBox x:Name="checkBox" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Content="{Binding Tag}" IsChecked="{Binding Path=CellValue,Converter={StaticResource boolConverter},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding Path=., Converter={StaticResource visConverter},ConverterParameter=CheckBox}" /> <!--TimePicker--> <xceed:DateTimeUpDown Format="Custom" FormatString="HH:mm:ss" VerticalAlignment="Stretch" VerticalContentAlignment="Center" Value="{Binding Path=CellValue,Converter={StaticResource timeSpanConverter},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding Path=., Converter={StaticResource visConverter},ConverterParameter=TimePicker}" CultureInfo="uk-UA" /> </StackPanel> </UserControl>
在這個里面我們在一個StackPanel中放置了匹配各種數據類型的Template,并且每一個的Visibility都是由visConverter這個自定義的Converter來實現的,后面我們會分析這個Converter里面的內容,這些代碼的整體思想就是每次這個StackPanel里面的Template都只有一個可以顯示,其它的都是隱藏的,哪一個會顯示是根據當前的數據類型決定的,每一個注釋表示每一個類型的數據,比如我們如果定義的是Bool類型,那么當我們雙擊單元格Cell的時候會出現一個CheckBox供我們編輯,所以這個里面我們需要根據我們定義的數據類型來擴展對應的模板,當我們雙擊單元格的時候就會顯示這個模板從而進行編輯數據。
這個里面是定義的MainWindow對應的DataContext,在這里面我們會初始化綁定到MainWindow中DataGridControl的ItemsSource,我們先來看看這個里面核心的代碼并就其中的要點進行分析。
using DataGridCellDoubleClickDemo.Models; using System; using System.Collections.ObjectModel; using System.Windows; namespace DataGridCellDoubleClickDemo { public class MainWindowViewModel : NotificationObject { public MainWindowViewModel(Xceed.Wpf.DataGrid.DataGridControl dataGridControl) { DataGridControl = dataGridControl; InitRecipeVariables(); } #region Properties private ObservableCollection<RecipeControlVariable> _RecipeVariables = new ObservableCollection<RecipeControlVariable>(); public ObservableCollection<RecipeControlVariable> RecipeVariables { get { return _RecipeVariables; } set { if (value != _RecipeVariables) { _RecipeVariables = value; OnPropertyChanged(nameof(RecipeVariables)); } } } public Xceed.Wpf.DataGrid.DataGridControl DataGridControl { get; set; } #endregion #region Private Methods private void InitRecipeVariables() { _RecipeVariables.Add(new RecipeControlVariable { ControlName = "Name", DisplayName = "Name", StepValues = new ObservableCollection<SmartCellViewModel> { new SmartCellViewModel { CellValue="Step", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "Name", DisplayName = "Name", VariableEditorType=RecipeVariableEditorType.TextInput } }, new SmartCellViewModel { CellValue="Step", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "Name", DisplayName = "Name", VariableEditorType=RecipeVariableEditorType.TextInput } } } }); _RecipeVariables.Add(new RecipeControlVariable { ControlName = "Time", DisplayName = "Process Time(Sec)", StepValues = new ObservableCollection<SmartCellViewModel> { new SmartCellViewModel { CellValue="0", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "Time", DisplayName = "Process Time(Sec)", VariableEditorType=RecipeVariableEditorType.NumInput } }, new SmartCellViewModel { CellValue="0", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "Time", DisplayName = "Process Time(Sec)", VariableEditorType=RecipeVariableEditorType.NumInput } } } }); _RecipeVariables.Add(new RecipeControlVariable { ControlName = "FrontChemical", DisplayName = "FrontChemical", StepValues = new ObservableCollection<SmartCellViewModel> { new SmartCellViewModel { CellValue="None", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "FrontChemical", DisplayName = "FrontChemical", VariableEditorType=RecipeVariableEditorType.ReadOnlySelection, Selections=new ObservableCollection<SelectionItem> { new SelectionItem { SelectionControlName="CHEM1", SelectionDisplayName="CHEM1", }, new SelectionItem { SelectionControlName="N2", SelectionDisplayName="N2", }, new SelectionItem { SelectionControlName="CDIW", SelectionDisplayName="CDIW", }, new SelectionItem { SelectionControlName="", SelectionDisplayName="None", } } } }, new SmartCellViewModel { CellValue="None", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "FrontChemical", DisplayName = "FrontChemical", VariableEditorType=RecipeVariableEditorType.ReadOnlySelection, Selections=new ObservableCollection<SelectionItem> { new SelectionItem { SelectionControlName="CHEM1", SelectionDisplayName="CHEM1", }, new SelectionItem { SelectionControlName="N2", SelectionDisplayName="N2", }, new SelectionItem { SelectionControlName="CDIW", SelectionDisplayName="CDIW", }, new SelectionItem { SelectionControlName="", SelectionDisplayName="None", } } } } } }); _RecipeVariables.Add(new RecipeControlVariable { ControlName = "NozzleBindingSetting", DisplayName = "Nozzle Scan", StepValues = new ObservableCollection<SmartCellViewModel> { new SmartCellViewModel { CellValue="Default", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "NozzleBindingSetting", DisplayName = "Nozzle Scan", VariableEditorType=RecipeVariableEditorType.TextInput } }, new SmartCellViewModel { CellValue="Default", ErrorInfo=null, SmartCellData=new RecipeVariableItem { ControlName = "NozzleBindingSetting", DisplayName = "Nozzle Scan", VariableEditorType=RecipeVariableEditorType.TextInput } } } }); } #endregion /// <summary> /// reload datagrid content /// </summary> public void RefreshDataGrid() { try { if (null == DataGridControl) return; //generate columns in Grid DataGridControl.CurrentColumn = null; if (DataGridControl.Columns.Count > 0) DataGridControl.Columns.Clear(); var template = (DataTemplate)this.DataGridControl.FindResource("CustomTemplate"); var rowTemplate = (DataTemplate)this.DataGridControl.FindResource("RowHeadTemplate"); DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column() { Width = 140, Title = "Name", FieldName = ".", CellContentTemplate = rowTemplate }); var cellEditor = DataGridControl.DefaultCellEditors[typeof(SmartCellViewModel)]; for (int index = 0; index < RecipeVariables[0].StepValues.Count; index++) { int width = 1; for (int n = 0; n < RecipeVariables.Count; n++) { string display = RecipeVariables[n].StepValues[index].Display; if (!string.IsNullOrWhiteSpace(display)) { int temp = display.Length * 7; width = Math.Max(temp, width); } } width = (int)(width * 1.1); width = Math.Max(width, 80); DataGridControl.Columns.Add(new Xceed.Wpf.DataGrid.Column() { Title = string.Format("Step {0}", index + 1), FieldName = string.Format("StepValues[{0}]", index), CellContentTemplate = template, AllowSort = false, Width = width, MaxWidth = width * 2, CellEditor = cellEditor }); } } catch (Exception ex) { }
在這個里面我們重點分析下RefreshDataGrid這個子函數,在我們的MainWindowViewModel中我們定義的RecipeVariables是最終綁定到MainWindow中定義的DataGridControl中的ItemsSource,是整個控件的數據源,由于我們這個DataGird的第一列和后面的Step列數據類型不同,所以我們的RefreshDataGrid函數中增加Column列的時候是分作兩個部分,第一個部分是單獨增加一列,后面的列是通過循環StepValues這個集合來動態進行增加的,代碼中我們定義了多少個StepValue,那么后面就會有多少列,這個里面的重點是增加Column的時候FieldName的賦值,這個是十分關鍵的,這個關系到能夠讓每一列獲取到正確的數據源,例如第一列賦值Filed= “.” 表示直接從當前綁定的數據源獲取數據,另外后面的Step列的每一個FieldName是動態進行賦值的,賦值語句是:FieldName = string.Format("StepValues[{0}]", index),這個里面Index是一個動態值,這個是非常關鍵的一步,另外后面的Step列由于需要通過雙擊進行編輯所以每一個Column是需要賦值CellEditor對象的,另外這個ViewModel中的DataGridControl是通過構造函數進行賦值的,構造函數中的賦值就是MainWindow中定義的DataGridControl對象,這個在閱讀代碼時需要特別注意。
Models主要是定義的數據集合,我們的代碼中主要包括RecipeControlVariable和SmartViewModel這兩個部分,這兩個部分分別對應DataGridControl的數據源以及雙擊進行編輯的SmartCellEditor兩個部分一一對應。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。