WPF Datagrid SelectedIndex issue - c#

I have a Datagrid to which I have added the DataGrid_SelectedCellsChanged event to show RowDetails for that specific cell when clicked.
This is working all fine as it should, but now I have on some that the event fires once, but after that it won't trigger it anymore if I select a cell in the same row. I checked in DataGrid_SelectCellColumnChanged and it won't change the value of the SelectedIndex (dg.SelectedIndex), even so I force it to with static values. Can someone maybe explain that, or have an idea what causes that problem?
Here is some of the code:
Create datagrid:
public static DataGrid AddDataGrid(ViewInfo viewInfo, System.Data.DataSet ds, UIElement parent, bool isReadOnly, bool setHighlight = true, System.Windows.Input.MouseButtonEventHandler clickEvent = null, EventHandler<DataGridCellEditEndingEventArgs> editEndEvent = null, string tagName = "", bool addDataContext = true)
{
try
{
DataTable dt = null;
////Reconfigure the Column Types in the Table for Sorting later
//if (DataGridExtension.CheckDataTableColumnTypeForDate(ds.Tables[0]))
//{
// dt = DataGridExtension.ReConfigureDataTableColumnType(ds.Tables[0]);
//}
//else
//{
// dt = ds.Tables[0];
//}
dt = ds.Tables[0];
DataGrid dg = new DataGrid
{
Name = "DataGrid__" + viewInfo.SprocName,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Margin = (tagName == "SubGrid") ? new Thickness(5, 5, 5, 10) : new Thickness(10, 0, 0, 0),
AutoGenerateColumns = true,
Style = TriggerStyleUtility.CreateStyle<DataGrid>(DataGrid.AlternatingRowBackgroundProperty, Brushes.LightGray),
AlternationCount = 2,
IsReadOnly = isReadOnly,
CanUserAddRows = false,
CanUserDeleteRows = false,
Visibility = Visibility.Visible
};
dg.CellStyle = TriggerStyleUtility.CreateStyle<DataGridCell>(DataGridCell.PaddingProperty, new Thickness(10), dg.CellStyle);
Style st = new Style(typeof(DataGridCell));
st.Setters.Add(new Setter(DataGridCell.PaddingProperty, new Thickness(10)));
//dg.CellStyle = st;
//set events
dg.AutoGeneratingColumn += DataGrid_AutoGeneratingColumn;
dg.Loaded += DataGrid_Loaded;
if (clickEvent != null) dg.MouseDoubleClick += clickEvent;
if (editEndEvent != null) dg.CellEditEnding += editEndEvent;
dg.Sorting += DataGrid_Sorting;
//ColumnCount = ds.Tables[0].Columns.Count;
ColumnCount = dt.Columns.Count;
List<object> list = new List<object>
{
viewInfo
};
if (addDataContext) list.InsertRange(0, new List<object>() { ds } );
dg.DataContext = list;
//dg.ItemsSource = ds.Tables[0].DefaultView;
dg.ItemsSource = dt.DefaultView;
UIElementExtensions.SetHighlight(dg, setHighlight);
//use this to evaluate if it is a SubGrid when Autogenerating Columns for ValueConverter
dg.Tag = tagName;
if (tagName == "SubGrid")
{
dg.MaxHeight = 600d;
dg.SelectedCellsChanged += SubDataGrid_SelectedCellsChanged;
}
//set event for Cell selection changed (triggers when selected row changes)
if (viewInfo.AddPNummerClick) dg.SelectedCellsChanged += DataGrid_SelectedCellsChanged;
//enable and set RowDetails, and events
//if (ds.Tables[0].Rows.Count > 0 && viewInfo.AddRowDetails)
if (dt.Rows.Count > 0 && viewInfo.AddRowDetails)
{
//set event for Cell selection changed (triggers when selected row changes)
if (!viewInfo.AddPNummerClick) dg.SelectedCellsChanged += DataGrid_SelectedCellsChanged;
//add event when cell is clicked (triggers on each cell)
st = new Style(typeof(DataGridCell));
st.Setters.Add(new EventSetter(DataGridCell.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(DataGrid_SelectCellColumnChanged)));
dg.CellStyle = st;
//add event for select row changes (used to bring focus to SubGrid)
st = new Style(typeof(DataGridRow));
st.Setters.Add(new EventSetter(DataGridRow.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(DataGrid_SelectRowDetails)));
dg.RowStyle = st;
//create default Template for RowDetails
DataGridExtension.CreateRowDetailsTemplate(dg);
}
//if no data set dummy item for NoDataTrigger
//if (dt.Rows.Count == 0)
if (ds.Tables[0].Rows.Count == 0)
{
dg.ItemsSource = new List<int> { -1 };
dg.Tag = "empty";
DataGridExtension.AddDataTemplate(dg, "Keine Daten gefunden!");
DataGridExtension.SetNoDataTrigger(dg);
}
//check parent and set appropriate position for DataGrid
if (parent.GetType() == typeof(DockPanel))
{
DockPanel.SetDock(dg, Dock.Top);
}
else
{
Grid.SetRow(dg, 1);
}
//add DatGrid to parent, so Highlights and DataGrid types can be processed (UpdateLayout)
ControlUtility.AddUIElement(parent, dg);
//highlight cells in DataGrid by max and lowest value in column
if (setHighlight) DataGridExtension.StartCellHighlight(dg, viewInfo);
//disable specific grid items (column, row, cell)
if (viewInfo.DisableTableItems != "") DataGridExtension.DisableGridElements(dg, viewInfo);
return dg;
}
catch (Exception ex)
{
FileLogger.HandleError("", false, true, "Error (DataGridUtility, AddDataGrid): " + Environment.NewLine + ex.Message, App._LogFilePath, App._LogFileName);
return null;
}
}
Code for DataGrid_SelectCellColumnChanged:
public static void DataGrid_SelectCellColumnChanged(object sender, MouseButtonEventArgs e)
{
try
{
DataGridCell dc = (DataGridCell)sender;
DataGrid dg = ControlUtility.FindParent<DataGrid>(dc);
UIElementExtensions.SetCurrentColumnIndex(dg, dc.Column.DisplayIndex);
if (dc.Column.DisplayIndex == 0) return;
int col = UIElementExtensions.GetCurrentColumnIndex(dg);
int row = UIElementExtensions.GetCurrentRowIndex(dg);
//change SelectedIndex to current Item Row, needed to trigger the cell changed event
if (dg.SelectedIndex == -1 || UIElementExtensions.GetCurrentColumnIndex(dg) == dg.SelectedIndex || (UIElementExtensions.GetCurrentColumnIndex(dg) != dg.SelectedIndex && UIElementExtensions.GetCurrentColumnIndex(dg) != 0))
{
var currentRowIndex = dg.Items.IndexOf(dg.CurrentItem);
bool changed = (UIElementExtensions.GetCurrentColumnIndex(dg) != dg.SelectedIndex && UIElementExtensions.GetCurrentColumnIndex(dg) != 0) ? true : false;
//if current RowIndex is different, set SelectedIndex to current row
//otherwise reset to -1 and back to current RowIndex, so cell change event can trigger
if (currentRowIndex != -1 && UIElementExtensions.GetCurrentColumnIndex(dg) != dg.SelectedIndex && !changed)
{
dg.SelectedIndex = currentRowIndex;
}
else
{
if (currentRowIndex == 0) return;
int test = UIElementExtensions.GetCurrentColumnIndex(dg);
// here it triggers normally the DataGrid_SelectedCellsChanged event, which usually works
dg.SelectedIndex = col; // UIElementExtensions.GetCurrentColumnIndex(dg);
/* trying to force it, but when debugging the SelectedIndex stays the same even after trying to set it static now,
and SelectedIndex has different value as test. It doesn't take the value????? */
if (dg.SelectedIndex != test) dg.SelectedIndex = 5;
App._CurrentColumnIndex = dg.SelectedIndex;
}
}
}
catch (Exception ex)
{
FileLogger.HandleError("", false, true, "Error (DataGridUtility, DataGrid_SelectedCellsChanged): " + Environment.NewLine + ex.Message, App._LogFilePath, App._LogFileName);
}
}
Class UIElementExtensions:
public class UIElementExtensions
{
//add Property "CurrentColumnIndex" and "CurrentRowIndex" to called UIElement
public static readonly DependencyProperty CurrentColumnIndexProperty = DependencyProperty.RegisterAttached("CurrentColumnIndex", typeof(int), typeof(UIElementExtensions), new FrameworkPropertyMetadata(null));
public static int GetCurrentColumnIndex(UIElement element)
{
if (element == null) throw new ArgumentNullException("element");
return (int)element.GetValue(CurrentColumnIndexProperty);
}
public static void SetCurrentColumnIndex(UIElement element, int value)
{
if (element == null) throw new ArgumentNullException("element");
element.SetValue(CurrentColumnIndexProperty, value);
}
public static readonly DependencyProperty CurrentRowIndexProperty = DependencyProperty.RegisterAttached("CurrentRowIndex", typeof(int), typeof(UIElementExtensions), new FrameworkPropertyMetadata(null));
public static int GetCurrentRowIndex(UIElement element)
{
if (element == null) throw new ArgumentNullException("element");
return (int)element.GetValue(CurrentRowIndexProperty);
}
public static void SetCurrentRowIndex(UIElement element, int value)
{
if (element == null) throw new ArgumentNullException("element");
element.SetValue(CurrentRowIndexProperty, value);
}
//add Property "Highlight" to called UIElement
public static readonly DependencyProperty HighlightProperty = DependencyProperty.RegisterAttached("Highlight", typeof(bool), typeof(UIElementExtensions), new FrameworkPropertyMetadata(null));
public static bool GetHighlight(UIElement element)
{
if (element == null) throw new ArgumentNullException("element");
return (bool)element.GetValue(HighlightProperty);
}
public static void SetHighlight(UIElement element, bool value)
{
if (element == null) throw new ArgumentNullException("element");
element.SetValue(HighlightProperty, value);
}
}
Code DataGrid_SelectedCellsChanged:
public static void DataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
try
{
DataGrid dg = (DataGrid)sender;
if (dg.SelectedIndex == -1) return;
DataGridRow row = (DataGridRow)(dg.ItemContainerGenerator.ContainerFromItem(dg.SelectedItem));
//return if no row found (happens when sorting by column)
if (row == null) return;
// Getting the ContentPresenter of the row details
DataGridDetailsPresenter presenter = ControlUtility.FindVisualChild<DataGridDetailsPresenter>(row);
Grid parent = ControlUtility.FindVisualChild<Grid>(presenter);
//update presenter Layout to get Grid if presenter is still null
if (parent == null)
{
presenter.UpdateLayout();
parent = ControlUtility.FindVisualChild<Grid>(presenter);
}
DataRowView dataRow = (DataRowView)dg.SelectedItem;
//do stuff
}
}
Edit: To make this a little more clear, this normally works as it should, only on some loaded sprocs it doesn't work. I changed the sprocs on which it doesn't work with code from where it works, but the problem consists, so that can't be the issue. Also if I click another cell in another row, than it works again, but again only for one time. On other sprocs it always works.
Also how can a field (public int SelectedIndex { get; set; }) not be forced to take a value? That's what irritates me the most on it.
FYI: the problem is in the DataGrid_SelectCellColumnChanged event. When SelectedIndex is changed here. This normally triggers the DataGrid_SelectedCellsChanged, when it works.
I appreciate any help on this.

Related

Changing font to DataGridView row is not working in WinForms C#

I have methods which manages datagridview object:
internal static void LoadChannelsInGrid(DataGridView dg, Label noDataLbl, string feedUrl)
{
var response = RssManager.GetRss(feedUrl);
if (response != null)
{
noDataLbl.Visible = false;
dg.Visible = true;
var items = response.OrderByDescending(s => s.PubDateUnix);
dg.DataSource = items.ToArray();
FontifyDataGrid(dg);
}
else
{
noDataLbl.Visible = true;
dg.Visible = false;
}
}
and
private static void FontifyDataGrid(DataGridView dg)
{
for (var i = 0; i < dg.Rows.Count; i++)
{
var item = dg.Rows[i].DataBoundItem as ChannelData;
if (item == null)
{
continue;
}
if (!item.IsLoaded)
{
var actualFont = new Font("Microsoft Sans Serif", 7.8f, FontStyle.Bold);
dg.Rows[i].DefaultCellStyle.Font = actualFont;
}
}
}
and I call :
LoadChannelsInGrid(dataGridView1, noDataLbl, "https://....");
Seems that rows (which model item satisfy IsLoaded value) don't have bold style, still looks regular.
Why ?
If I understood correctly, you need the font to be bold when the IsLoaded property is true.
In that case you need to update your if (!item.IsLoaded) to if (item.IsLoaded)

WPF validation run-time generated forms

I'm creating a WPF application which generates a form based on a model to edit it. I use reflection to go through all properties of the model to create inputfields for the properties. The GenerateForm method iterates through the properties and uses the SimpleInputFactory to generate input fields. I want to validate the input of the generated fields, but all validation methods require that you know what you are going to validate (either it's using generics or you have to specify it on the binding in the XAML). I want to validate the input based on attributes in the models. Is there any existing way of doing this? I could just make it myself, but if there is some existing way it would help.
Thanks in advance.
public static Grid GenerateForm(List<object> basisgegevensModels, AddOrEdit addOrEdit)
{
if (basisgegevensModels.Count <= 0)
return null;
Grid formGrid = new Grid();
formGrid.Margin = new Thickness(20,20,20,20);
formGrid.HorizontalAlignment = HorizontalAlignment.Stretch;
AddColumnToGrid(formGrid, GridUnitType.Star, 1);
AddColumnToGrid(formGrid, GridUnitType.Star, 3);
AddColumnToGrid(formGrid, GridUnitType.Star, 1);
AddColumnToGrid(formGrid, GridUnitType.Star, 3);
AddRowToGrid(formGrid, GridUnitType.Auto, 0);
var propertyInfos = new List<PropertyInfo>();
foreach (var propertyInfo in basisgegevensModels[0].GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance))
{
var visibleAttribute = propertyInfo.GetCustomAttributes(typeof(Visible), false).Cast<Visible>().FirstOrDefault();
if (visibleAttribute == null || visibleAttribute.IsVisible)
propertyInfos.Add(propertyInfo);
}
int column = 0;
int row = 0;
foreach (var property in propertyInfos)
{
if (row >= Math.Ceiling((decimal)propertyInfos.Count / 2) && row != 0 && column != 2)
{
column = 2;
row = 0;
}
var displayNameAttribute = basisgegevensModels[0].GetType().GetProperty(property.Name).GetCustomAttributes(typeof(DisplayNameAttribute), false)
.Cast<DisplayNameAttribute>().FirstOrDefault();
string displayName;
if (displayNameAttribute != null)
displayName = displayNameAttribute.DisplayName;
else
displayName = property.Name;
bool isEditAllowed = true;
if (addOrEdit == AddOrEdit.Edit)
{
var editAllowed =
basisgegevensModels[0].GetType()
.GetProperty(property.Name)
.GetCustomAttributes(typeof (EditAllowed), false)
.Cast<EditAllowed>()
.FirstOrDefault();
if (editAllowed != null)
isEditAllowed = editAllowed.IsEditAllowed;
}
//add label for inputfield
TextBlock label = SimpleInputFieldFactory.CreateTextBlock(displayName, column, row);
label.VerticalAlignment = VerticalAlignment.Center;
formGrid.Children.Add(label);
column++;
//add input field
formGrid.Children.Add(SimpleInputFieldFactory.CreateInputField(basisgegevensModels, property, isEditAllowed, column, row, 300, HorizontalAlignment.Left));
column--;
row++;
if (column == 0)
{
AddRowToGrid(formGrid, GridUnitType.Auto, 0);
}
}
return formGrid;
}
SimpleInputFieldFactory Class:
public class SimpleInputFieldFactory
{
public static Control CreateInputField(List<object> basisgegevensModels, PropertyInfo property, bool editAllowed, int column, int row, double inputFieldWidth, HorizontalAlignment inputFieldHorAlignment)
{
Control inputField = null;
var triggers = new List<System.Windows.Interactivity.EventTrigger>();
var multiBinding = new MultiBinding();
multiBinding.NotifyOnSourceUpdated = true;
multiBinding.Mode = BindingMode.TwoWay;
multiBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
foreach (var basisgegevensModel in basisgegevensModels)
{
Binding binding = new Binding(property.Name)
{
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Source = basisgegevensModel,
Mode = BindingMode.TwoWay
};
multiBinding.Bindings.Add(binding);
}
//add inputfield
if (property.PropertyType == typeof(string) || property.PropertyType == typeof(int))
{
string valueAsString = "";
if (property.GetValue(basisgegevensModels[0]) != null)
valueAsString = property.GetValue(basisgegevensModels[0]).ToString();
inputField = CreateTextBox(valueAsString, column, row);
triggers.Add(new System.Windows.Interactivity.EventTrigger("EditValueChanged"));
}
else if (property.PropertyType == typeof(bool))
{
bool valueAsBool = false;
if (property.GetValue(basisgegevensModels[0]) != null)
valueAsBool = (bool)property.GetValue(basisgegevensModels[0]);
inputField = CreateCheckBox(valueAsBool, column, row);
triggers.Add(new System.Windows.Interactivity.EventTrigger("EditValueChanged"));
}
else if (property.PropertyType.BaseType == typeof(Enum))
{
int valueAsInt = 0;
if (property.GetValue(basisgegevensModels[0]) != null)
valueAsInt = (int)property.GetValue(basisgegevensModels[0]);
inputField = CreateDropDown(property.PropertyType, valueAsInt, column, row);
triggers.Add(new System.Windows.Interactivity.EventTrigger("EditValueChanged"));
((ComboBoxEdit)inputField).SelectedIndex = valueAsInt;
((ComboBoxEdit)inputField).IsTextEditable = false;
}
//add general settings, bindings and triggers
if (inputField != null)
{
inputField.Width = inputFieldWidth;
inputField.HorizontalAlignment = inputFieldHorAlignment;
inputField.Margin = new Thickness(5);
inputField.IsEnabled = editAllowed;
var multiEditAllowedAttribute = property.GetCustomAttributes(typeof(MultiEditAllowed), false)
.Cast<MultiEditAllowed>().FirstOrDefault();
//only add binding and trigger if 1 entity is selected OR multiedit is allowed
if (basisgegevensModels.Count == 1 || multiEditAllowedAttribute == null || multiEditAllowedAttribute.IsMultiEditAllowed)
{
multiBinding.Converter = new MultiEditValueConverter();
inputField.SetBinding(BaseEdit.EditValueProperty, multiBinding);
foreach (var trigger in triggers)
{
var action = new ActionMessage();
action.MethodName = "InputChanged";
trigger.Actions.Add(action);
Interaction.GetTriggers(inputField).Add(trigger);
}
}
else
{
inputField.IsEnabled = false;
}
return inputField;
}
return null;
}
public static List<string> GetEnumList(Type enumType)
{
if (!enumType.IsEnum)
{
return new List<string>();
}
return Enum.GetNames(enumType).ToList();
}
public static TextBlock CreateTextBlock(string text, int column, int row)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = text;
Grid.SetColumn(textBlock, column);
Grid.SetRow(textBlock, row);
return textBlock;
}
private static TextEditBase CreateTextBox(string text, int column, int row)
{
TextEdit textBox = new TextEdit();
textBox.Text = text;
Grid.SetColumn(textBox, column);
Grid.SetRow(textBox, row);
return textBox;
}
private static CheckEdit CreateCheckBox(bool isChecked, int column, int row)
{
CheckEdit checkBox = new CheckEdit();
checkBox.IsChecked = isChecked;
Grid.SetColumn(checkBox, column);
Grid.SetRow(checkBox, row);
return checkBox;
}
private static ComboBoxEdit CreateDropDown(Type enumType, int value, int column, int row)
{
ComboBoxEdit dropDown = new ComboBoxEdit();
foreach (var enumValue in GetEnumList(enumType))
{
dropDown.Items.Add(enumValue);
}
dropDown.SelectedIndex = value;
Grid.SetColumn(dropDown, column);
Grid.SetRow(dropDown, row);
return dropDown;
}
}
Yes, you can use the System.ComponentModel.DataAnnotations for validation.
Documentation for the base namespace : MSDN: System.ComponentModel.DataAnnotations
Examples include RequiredAttribute and RangeAttribute.
Microsoft also provide an excellent example of how to provide validation feedback in realtime to the user in WPF using the ErrorTemplate and Binding in the following example: MSDN: Validation in MVVM using Data Annotations
I've also developed a small framework for my own purposes which incorporates these techniques - basically a base class where you need to decorate your VM with ValidationAttribute derived attributes and use the appropriate Binding and WPF takes care of the rest. GitHub: ValidatingBaseViewModel

DataGridView Tag value for rows is null

I have 2 DataGridView controls on a form. Both have same number and types of columns. 1 TextBox Column and 2 CheckBoxColumns.
The Problem is that first DataGridView is working fine but the other one is not. both have same binding methods and datasource. The problems with the second DataGridView on the same form are..
Checkbox values are not set
currentrow.Tag value is null when I try to retrieve the value
Below is the code i'm using to bind the DataGridViews and setting checkbox values
public void BindGridView(DataGridView gv)
{
var actuallist = UserOperations.GetPermissions(RoleId, (int)(Enumerations.ModuleType.Basic));
Common.Common.StyleGridView(gv);
gv.AutoGenerateColumns = false;
gv.Columns["ModuleName"].DataPropertyName = "ModuleName";
gv.DataSource = actuallist;
int j = 0;
foreach (DataGridViewRow row in gv.Rows)
{
row.Tag = actuallist[j++].ModuleId;
}
int k = 0;
bool r = false;
foreach (DataGridViewRow row in gv.Rows)
{
r = actuallist[k++].PermissionGranted;
if (r)
((DataGridViewCheckBoxCell)row.Cells[1]).Value = r;
else
((DataGridViewCheckBoxCell)row.Cells[2]).Value = !r;
}
}
private void gvPermissions_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (gvPermissions.Columns[e.ColumnIndex].Name == "Granted")
{
bool isChecked = (bool)gvPermissions[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
gvPermissions.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = !isChecked;
gvPermissions.Rows[e.RowIndex].Cells[e.ColumnIndex + 1].Value = isChecked;
gvPermissions.EndEdit();
}
if (gvPermissions.Columns[e.ColumnIndex].Name == "Denied")
{
bool isChecked = (bool)gvPermissions[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
gvPermissions.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = !isChecked;
gvPermissions.Rows[e.RowIndex].Cells[e.ColumnIndex - 1].Value = isChecked;
gvPermissions.EndEdit();
}
}

Get the cell value of the third column on button click

I have a button in the first column of my datagrid, and when I click it I'm trying to get the cell value of 3rd column of that row I clicked the button on. So for example I click the button on row 3 of my datagrid I want the cell value of column 3, row 3 which is an int. How can I do that?
XAML for the button:
<Control:DataGrid.Columns>
<Control:DataGridTemplateColumn>
<Control:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="ShowHideDetailsClick" Foreground="Black">+</Button>
</DataTemplate>
</Control:DataGridTemplateColumn.CellTemplate>
</Control:DataGridTemplateColumn>
<Control:DataGrid.Columns>
C# to handle click:
private void ShowHideDetailsClick(object sender, RoutedEventArgs e)
{
//want to get cell value here
System.Windows.Controls.Button expandCollapseButton = (System.Windows.Controls.Button)sender;
DependencyObject obj = (DependencyObject)e.OriginalSource;
while (!(obj is ExtendedGrid.Microsoft.Windows.Controls.DataGridRow) && obj != null) obj = VisualTreeHelper.GetParent(obj);
if (obj is ExtendedGrid.Microsoft.Windows.Controls.DataGridRow)
{
if (null != expandCollapseButton && "+" == expandCollapseButton.Content.ToString())
{
(obj as ExtendedGrid.Microsoft.Windows.Controls.DataGridRow).DetailsVisibility = Visibility.Visible;
expandCollapseButton.Content = "-";
}
else
{
(obj as ExtendedGrid.Microsoft.Windows.Controls.DataGridRow).DetailsVisibility = Visibility.Collapsed;
expandCollapseButton.Content = "+";
}
}
}
I use a DataTable to fill my datagrid with data retrieved from a database, see code below:
public DataTable SourceTable
{
get
{
return _sourceTable;
}
set
{
_sourceTable = value;
OnPropertyChanged("SourceTable");
}
}
SourceTable = new DataTable();
SourceTable.Columns.AddRange(new DataColumn[]{
new DataColumn("InputID", typeof(int)),
new DataColumn("TraderID", typeof(string)),
new DataColumn("TradeDate", typeof(DateTime)),
new DataColumn("TradeTime", typeof(TimeSpan)),
new DataColumn("ClientName", typeof(string)),
new DataColumn("CurPair", typeof(string)),
new DataColumn("Amnt", typeof(int)),
new DataColumn("Action", typeof(string)),
new DataColumn("ExecutedRate", typeof(decimal))
});
DataRow rowSource = null;
var OpenTradesQuery = from qa in connection.QuickAnalyzerInputs
where qa.TradeClosedDateTime == null
select new
{
qa.InputID,
qa.TraderID,
qa.ClientTradedDate,
qa.ClientTradedTime,
qa.ClientName,
qa.CurrencyPair,
qa.TradedAmount,
qa.Action,
qa.ExecutedRate
};
foreach (var rowObj in OpenTradesQuery)
{
rowSource = SourceTable.NewRow();
SourceTable.Rows.Add(rowObj.InputID, rowObj.TraderID, rowObj.ClientTradedDate, rowObj.ClientTradedTime, rowObj.ClientName, rowObj.CurrencyPair, rowObj.TradedAmount, rowObj.Action, rowObj.ExecutedRate);
}
And then in my XAML the datagrid is binding SourceTable
Before anything, I'll suggest to create a little Class that will contains information about the Rows of the Database, that will populate the Datagrid. This will help you for some facilities in your code. Also that will help for implementing my answer.
The Class will be something like this:
public class PopulateData
{
public int InputID;
public String TraderID;
public DateTime TradeDate;
public TimeSpan TradeTime;
public string ClientName;
public string CurPair;
public int Amnt;
public string Action;
public decimal ExecutedRate;
public PopulateData(int iId, string tId, DateTime date, TimeSpan tTime, string cName, string curPair, int amnt, string Act, decimal ExRate)
{
InputID = iId;
TraderID = tId;
TradeDate = date;
TradeTime = tTime;
ClientName = cName;
CurPair = curPair;
Amnt = amnt;
Action = Act;
ExecutedRate = ExRate;
}
}
So when you populate the SourceTable, do something like this:
foreach (var rowObj in OpenTradesQuery)
{
rowSource = SourceTable.NewRow();
SourceTable.Rows.Add(new PopulateData( rowObj.InputID, rowObj.TraderID, rowObj.ClientTradedDate, rowObj.ClientTradedTime, rowObj.ClientName, rowObj.CurrencyPair, rowObj.TradedAmount, rowObj.Action, rowObj.ExecutedRate));
}
After you get the row corresponding to your button (the DataGridRow) it's almost done:
You now have to get what is inside the row; a PopulateData actually.
private void ShowHideDetailsClick(object sender, RoutedEventArgs e)
{
System.Windows.Controls.Button expandCollapseButton = (System.Windows.Controls.Button)sender;
DependencyObject obj = (DependencyObject)e.OriginalSource;
while (!(obj is ExtendedGrid.Microsoft.Windows.Controls.DataGridRow) && obj != null) obj = VisualTreeHelper.GetParent(obj);
//Get your entire row view here
if(obj != null && obj is ExtendedGrid.Microsoft.Windows.Controls.DataGridRow)
{
DataGridRow d = obj as DataGridRow; //Convert into DataGridRow
PopulateData st = d.Item as PopulateData; //Get the PopulateData
if (st.TraderID == "what you wants") //Or something else in the Class
{
// some stuff here
}
}
if (obj is ExtendedGrid.Microsoft.Windows.Controls.DataGridRow)
{
if (null != expandCollapseButton && "+" == expandCollapseButton.Content.ToString())
{
(obj as ExtendedGrid.Microsoft.Windows.Controls.DataGridRow).DetailsVisibility = Visibility.Visible;
expandCollapseButton.Content = "-";
}
else
{
(obj as ExtendedGrid.Microsoft.Windows.Controls.DataGridRow).DetailsVisibility = Visibility.Collapsed;
expandCollapseButton.Content = "+";
}
}
}
and that's it , let me know if it works for you.

Problem with the DevExpress XtraGridView control

I have one xtragrid control on my devxpress form . I've created the columns of my grid at runtime when i load the form . I'm developing the Field chooser for my grid view which is situated on the same form. For that i used the repositoryItemCheckedComboBoxEditcontrol & in that control i added the column names which will be present in the xtragrid.
Basically i created the columns to the xtragrid with the Visible property to false. When user checks particular column name by using repositoryItemCheckedComboBoxEdit then i set the Visible to true & again if user unchecked the column name then again i set the visible to false. & while creating column i set the width of the column.
Problem which i'm facing is that if user select the all fields from the repositoryItemCheckedComboBoxEdit then the grid control should show the horizontal scroll bar automatically when require.
And another problem is that with the columns is besides setting the width of the column, it is not showing the required width of that column . it shrinks that all column width .
code which i use for creating column to the xtragridview at run time is as follows -
public void AddGridColumn(string fieldName, string caption, int nRowWidth, RepositoryItem Item, object oCollection, string DisplayMember, string ValueMember, string format, FormatType type)
{
DevExpress.XtraGrid.Columns.GridColumn column = ColumnView.Columns.AddField(fieldName);
column.Caption = caption;
column.ColumnEdit = Item;
column.DisplayFormat.FormatType = type;
column.DisplayFormat.FormatString = format;
column.VisibleIndex = ColumnView.VisibleColumns.Count;
column.Width = nRowWidth;
}
code for the field chooser is as follows -
I used this function for filling the items of the repositoryItemCheckedComboBoxEdit control
private void FieldCollection()
{
allFields = new ArrayList();
columnNames = new Dictionary<string, string>();
allFields.Clear();
repositoryItemCheckedComboBoxEdit1.Items.Clear();
for (int i = 0; i < gvBase.Columns.Count; i++)
{
allFields.Add(gvBase.Columns[i].Caption );
if (gvBase.Columns[i].FieldName != "ContactID")
{
if (gvBase.Columns[i].Visible == true)
{
if (gvBase.Columns[i].Caption != "Label1" && gvBase.Columns[i].Caption != "Label2" && gvBase.Columns[i].Caption != "Label3" && gvBase.Columns[i].Caption != "Label4" && gvBase.Columns[i].Caption != "Label5")
repositoryItemCheckedComboBoxEdit1.Items.Add(gvBase.Columns[i].Caption, CheckState.Checked);
if (!columnNames.ContainsKey(gvBase.Columns[i].Caption))
columnNames.Add(gvBase.Columns[i].Caption, gvBase.Columns[i].FieldName);
}
else
{
if (gvBase.Columns[i].Caption != "Label1" && gvBase.Columns[i].Caption != "Label2" && gvBase.Columns[i].Caption != "Label3" && gvBase.Columns[i].Caption != "Label4" && gvBase.Columns[i].Caption != "Label5")
repositoryItemCheckedComboBoxEdit1.Items.Add(gvBase.Columns[i].Caption, CheckState.Unchecked);
if (!columnNames.ContainsKey(gvBase.Columns[i].FieldName))
columnNames.Add(gvBase.Columns[i].Caption, gvBase.Columns[i].FieldName);
}
}
}
cmbFieldChooser.EditValue = "";
}
this is used for the repositoryItemCheckedComboBoxEdit control event -
private void cmbFieldChooser_EditValueChanged(object sender, EventArgs e)
{
ArrayList temp = new ArrayList();
temp.AddRange(allFields);
string[] strFields = cmbFieldChooser.EditValue.ToString().Split(',');
for (int i = 0; i < strFields.Length; i++)
{
if (temp.Contains(strFields[i].Trim()))
temp.Remove(strFields[i].Trim());
if (strFields[i] != "")
{
if (columnNames.ContainsKey(strFields[i].Trim()))
{
if (gvBase.Columns[columnNames[strFields[i].Trim()]].Visible == false)
{
gvBase.Columns[columnNames[strFields[i].Trim()]].Visible = true;
gvBase.Columns[columnNames[strFields[i].Trim()]].BestFit();
}
}
}
}
if (temp.Count < 20)
{
for (int j = 0; j < temp.Count; j++)
{
if (columnNames.ContainsKey(temp[j].ToString().Trim()))
{
gvBase.Columns[columnNames[temp[j].ToString().Trim()]].Visible = false;
}
}
}
cmbFieldChooser.EditValue = repositoryItemCheckedComboBoxEdit1.GetCheckedItems();
if ((cmbFieldChooser.EditValue.ToString()).Split(',').Length > 5)
{
gvBase.OptionsView.ColumnAutoWidth = false;
gvBase.BestFitColumns();
gvBase.HorzScrollVisibility = ScrollVisibility.Always;
}
else
{
gvBase.OptionsView.ColumnAutoWidth = true;
gvBase.HorzScrollVisibility = ScrollVisibility.Never;
}
}
How to resolve this problem?
thanks.
How many columns do you have in your Grid?
I see you have code there to turn off the ColumnAutoWidth once you go past 5 columns (ie 6 columns or more). Have you debugged this condition to ensure the ColumnAutoWidth is indeed being turned off?
As per BestFitColumns Help Doc the BestFitColumns will only calculate for the first n rows as per the BestFitMaxRowCount property unless it it set to -1, could this be a cause?
The other thing that seems a little odd if that you are setting the EditValue of cmdFieldChooser within the cmdFieldChooser_EditValueChanged event... why so?

Categories