I have two stack panel, containing each, one datagrid.
I set the itemsSource of my datagrid when the source are loaded.
My panels are collapsed in the beginning, and then, must appears when I checked one RadioButton.
Here is the xaml of stackpanel :
<StackPanel Name="spListeList"
Grid.Row="0"
Grid.Column="2"
Orientation="Horizontal"
Visibility="Collapsed">
<sdk:DataGrid Name="dgListList"
VerticalAlignment="Top"
HorizontalAlignment="Left"
AutoGenerateColumns="False"
AlternatingRowBackground="Orange"
IsReadOnly="True">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding IdList, Mode=TwoWay}"
Visibility="Collapsed"
Width="10"/>
<sdk:DataGridTextColumn Header=" "
Width="85"
Binding="{Binding LibList, Mode=TwoWay}"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
<StackPanel Name="spListeJury"
Grid.Row="0"
Grid.Column="3"
Orientation="Horizontal"
Visibility="Collapsed">
<sdk:DataGrid Name="dgListeJury"
VerticalAlignment="Top"
HorizontalAlignment="Left"
AutoGenerateColumns="False"
AlternatingRowBackground="Orange"
IsReadOnly="True">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding IdJury, Mode=TwoWay}"
Visibility="Collapsed"
Width="10"/>
<sdk:DataGridTextColumn Header=" "
Width="85"
Binding="{Binding LibJury, Mode=TwoWay}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</StackPanel>
I got 10 radioButton, and 2 handler(similar except for names) for them.
void rbListeList_Checked(object sender, RoutedEventArgs e)
{
try
{
if (templateColumnListeList == null)
{
templateColumnListeList = new DataGridTemplateColumn();
}
dgListeList.Columns.Remove(templateColumnListeList);
templateColumnListeList.Header = "Select";
templateColumnListeList.CellTemplate = (DataTemplate)Resources["ItemTemplateSelect"];
dgListeList.Columns.Add(templateColumnListeList);
templateColumnListeList.DisplayIndex = 0;
spListeList.Visibility = Visibility.Visible;
spListeJury.Visibility = Visibility.Collapsed;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
When I comment the lines changing the visibility, nothing goes wrong. But when it's not, I got a ArgumentOutOfBound Exception
And when the two panels are visible on the beginning, they appears well, without bug. And the template colums appears too when I click on a radioButton and goes into the handler...
I tried another one :
when i star with both visible, application running well, and panels appears and desappears the way I want... So it's seems, there is a problem when I star with both collapsed.
Can't I change visibility on panels, containing Source when application is running?
Thank you.
When you set the Visibility="Collapsed" in XAML, that control is not Instantiated when the Window Loads. Try Visibility="Hidden" if using WPF. Silverlight Doesn't support Hidden visibility. or try setting the Collapsed property in Loaded event of the Window.
I would say there is an issue with the column code above but it is hard to tell without more code. I normally bind the visibility property of the control to a property on the datacontext for the page and set that value when needed. If you post a little more code I could be of more help.
Related
In the MyDatagrid_CellEditEnding(...) event (shown below) I am capturing the edited value of a cell whenever a cell of one of the three columns is edited by a user. After editing cell in second or third column, when I move out of that cell, I can see the CellEditEnding event getting called. But the same is not true for the first column that is a DataGridTemplateColumn column. That is, when I change a date in any cell in the first DataGridTemplateColumn, and move the cursor out of the cell, the CellEditEnding event is not called.
Question: What I may be missing here and how can we make it work? I have seen similar issues and their solutions online (such as this and this), so I'm not sure what I may be missing here.
Note: I'm using latest versions of VS2019 and .NET Core 3.1 on Windows 10 vs1903 - Pro
<Window x:Class="MyTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
.....
Title="MainWindow">
<Grid>
<DataGrid x:Name="MyDatagrid" AutoGenerateColumns="False" SelectionMode="Single" CellEditEnding="MyDatagrid_CellEditEnding">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Date Modified">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="btnTest" Content="Test" HorizontalAlignment="Left" VerticalAlignment="Top" Click="btnTest_Click"/>
</Grid>
</Window>
Code:
......
......
string _sDateModified;
string _sFirstName;
string _sLastName;
.....
.....
private void MyDatagrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
DataGridColumn c = e.Column;
if (c.Header.ToString() == "Date Modified")
_sDateModified = (e.EditingElement as TextBox).Text;
else if (c.Header.ToString() == "First Name")
_sFirstName = (e.EditingElement as TextBox).Text;
else if (c.Header.ToString() == "Last Name")
_sLastName = (e.EditingElement as TextBox).Text;
}
You are editing the DatePicker in the CellTemplate and this doesn't cause the CellEditEnding event to fire. The CellTemplate is not supposed to contain any input controls.
Replace the DatePicker in the CellTemplate with a TextBlock:
<DataGridTemplateColumn Header="Date Modified">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DateModified, StringFormat=yyyy-MM-dd}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified, UpdateSourceTrigger=LostFocus}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Or set the IsEnabled property of the DatePicker in the CellTemplate to false. Either way, you'll have to enter the edit mode by double clicking on the cell before you can expect the CellEditEnding event to fire.
Try this:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateModified, UpdateSourceTrigger=LostFocus}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
I have a community toolkit datagrid bound to an observable collection. I also have an "add" button bound to a command that adds a new element to the collection and thus adds a new row to the datagrid. Now I want to automatically start editing the first cell of the new row when the button is clicked.
I tried adding this to the end of my command:
MyDataGrid.Focus(FocusState.Programmatic);
MyDataGrid.SelectedIndex = MyCollection.Count;
MyDataGrid.CurrentColumn = MyDataGrid.Columns[0];
MyDataGrid.BeginEdit();
Though this only works when the focus was already on the datagrid before the button is clicked. Does anyone have any idea how to solve this ?
Thanks in advance
I did this in XAML Studio for the known namespaces in settings. It's an ObservableCollection bound to the ItemsSource of the DataGrid.
In addition to having a button for the Add action and putting code in its callback, you need to add an event handler on the DataGrid for the PreparingCellForEdit event.
So in your add method, you can create a new element in your collection and start editing the new item like so:
private void AddNamespaceButton_Click(object sender, RoutedEventArgs e)
{
// Add new Row and begin editing
KnownNamespaces.Insert(0, new XmlnsNamespace(string.Empty, string.Empty));
NamespaceDataGrid.SelectedIndex = 0;
NamespaceDataGrid.ScrollIntoView(NamespaceDataGrid.SelectedItem, null);
NamespaceDataGrid.Focus(FocusState.Keyboard);
NamespaceDataGrid.BeginEdit();
}
The next piece is the key for the DataGridTextColumn type to ensure the focus of the cell gets transferred to the focus of the TextBox inside when editing:
private void NamespaceDataGrid_PreparingCellForEdit(object sender, Microsoft.Toolkit.Uwp.UI.Controls.DataGridPreparingCellForEditEventArgs e)
{
if (e.EditingElement is TextBox t)
{
t.Focus(FocusState.Keyboard);
}
}
It's also important to note that the class that your ObservableCollection consists of should implement the IEditableObject interface to work properly with the DataGrid.
Here's my XAML for completeness:
<StackPanel Margin="{StaticResource SettingsSubheaderMargin}">
<StackPanel Orientation="Horizontal">
<TextBlock x:Uid="SettingsPanel_KnownNamespaces"
Margin="0,8,0,12"
Style="{StaticResource BodyTextStyle}" />
<Button x:Uid="SettingsPanel_KnownNamespaces_Button_Add" Click="AddNamespaceButton_Click" Style="{StaticResource VSCodeAppBarHeaderButtonStyle}">
<SymbolIcon Symbol="Add" />
</Button>
</StackPanel>
<controls:DataGrid x:Name="NamespaceDataGrid"
MaxHeight="450"
AutoGenerateColumns="False"
Background="{ThemeResource Brush-Blue-Dark-1}"
CanUserReorderColumns="False"
CanUserSortColumns="True"
IsReadOnly="False"
ItemsSource="{x:Bind KnownNamespaces, Mode=OneWay}"
PreparingCellForEdit="NamespaceDataGrid_PreparingCellForEdit"
RowEditEnded="DataGrid_RowEditEnded">
<controls:DataGrid.Columns>
<controls:DataGridTextColumn Width="SizeToCells"
Binding="{Binding Name}"
FontSize="20"
Header="Shortcut" />
<controls:DataGridTextColumn Width="SizeToCells"
Binding="{Binding Path}"
FontSize="20"
Header="Namespace" />
<controls:DataGridTemplateColumn>
<controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Uid="SettingsPanel_KnownNamespaces_Button_Remove"
Click="RemoveNamespaceButton_Click"
CommandParameter="{Binding}"
Style="{StaticResource VSCodeAppBarHeaderButtonStyle}">
<SymbolIcon Symbol="Delete" />
</Button>
</DataTemplate>
</controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>
</controls:DataGrid.Columns>
</controls:DataGrid>
</StackPanel>
I use the RowEditEnding event to save my data model back to disk.
I am using ComboBox inside a DataGrid which is in CellEditingTemplate.
I insert the selected item to the textblock in same cell, which is in CellTemplate. the insertion will happen only when I move to next cell.
what I want is when I select item from the ComboBox it should insert it in the TextBlock
without moving to the next cell.
here is my xaml.
<DataGrid.Columns>
<DataGridTextColumn Header="Hours" Binding="{Binding time}" FontSize="14" FontWeight="Bold" IsReadOnly="True" Width="100"/>
<DataGridTemplateColumn Header="Monday" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel >
<TextBlock x:Name="mon" Text="{Binding Path=SelectedSubject}"></TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<ComboBox x:Name="monday" Width="50" IsSynchronizedWithCurrentItem="true" Loaded="monday_Loaded" SelectionChanged="monday_SelectionChanged"></ComboBox>-->
<ComboBox x:Name="monday" Width="50" ItemsSource="{Binding Path=Subjects}" SelectedItem="{Binding Path=SelectedSubject}" IsSynchronizedWithCurrentItem="true" Loaded="monday_Loaded" SelectionChanged="monday_SelectionChanged"></ComboBox>
<ComboBox x:Name="staff" Width="50" Loaded="staff_Loaded"></ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
Is it possible to do this?
If any one have any idea about how to do it please help me.
Sorry i have use above code but it was not giving perfect answer.
Use mouse leave event of monday combo box and commit edit in that event it will work fine. :)
private void monday_MouseLeave(object sender, MouseEventArgs e)
{
this.myGrid.CommitEdit();
}
If you add a name to your DataGrid you can access it from monday_SelectionChanged and commit the edits:
<Grid x:Name="myGrid" ....>
in the handler of the ComboBox selection changed event
private void monday_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
myGrid.CommitEdit();
// Rest of your implementation ....
}
I have WPF app and having trouble with binding. My UI looks like the image on the link. (My apologies for not embedding the image since I'm a new user and need to gain points in order to post image)
http://i.stack.imgur.com/a1koN.jpg
Basically 1 Product can have many Pricing Details. The screen is for the Edit mode where the information is retrieved from the database (for the sake of this sample, I just hard coded the values). Selecting an item in the datagrid will load the information on its respective textboxes. This is currently working fine. The only thing that i would like to modify is the behavior when changing the value in the textbox because the datagrid gets immediately updated. Would it be possible to only update the datagrid once the EDIT button is clicked? Note that any changes made in this point is not yet persisted in the database, it would only be persisted when the UPDATE button(on the top) is clicked.
Here's the snippet of the XAML file:
DataGrid
<DataGrid AutoGenerateColumns="False" AlternationCount="2" Height="100" ItemsSource="{Binding ProductPrices, Mode=TwoWay}" SelectedItem="{Binding ProductPrice}" IsReadOnly="True" SelectionMode="Single" GridLinesVisibility="Horizontal">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding UnitPrice, StringFormat=\{0:N\}}" Header="Unit Price" Width="100" />
<DataGridTextColumn Binding="{Binding LowestPrice, StringFormat=\{0:N\}}" Header="Lowest Price" Width="100"/>
<DataGridTextColumn Binding="{Binding EffectiveDate, StringFormat=\{0:d\}}" Header="Effective Date" Width="150"/>
</DataGrid.Columns>
</DataGrid>
TextBoxes
<TextBox Grid.Column="1" Grid.Row="0" Text="{Binding Path=ProductPrice.UnitPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, StringFormat=\{0:N\}}" Width="100" />
<TextBox Grid.Column="3" Grid.Row="0" Text="{Binding Path=ProductPrice.LowestPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, StringFormat=\{0:N\}}" Width="100" />
<DatePicker Grid.Column="1" Grid.Row="1" Text="{Binding Path=ProductPrice.EffectiveDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Width="100" />
ViewModel
private Product _product;
public Product Product
{
get { return _product; }
set
{
_product = value;
NotifyPropertyChanged(m => m.Product);
}
}
private ProductPrice _productPrice;
public ProductPrice ProductPrice
{
get { return _productPrice; }
set
{
_productPrice = value;
NotifyPropertyChanged(m => m.ProductPrice);
}
}
private ObservableCollection<ProductPrice> _productPrices;
public ObservableCollection<ProductPrice> ProductPrices
{
get { return _productPrices; }
set
{
_productPrices = value;
NotifyPropertyChanged(m => m.ProductPrices);
}
}
UpdateSourceTrigger=PropertyChanged must be the culprit. But I still don't have an idea on how to solve this case. Is this achievable using MVVM approach?
I had uploaded the source code on SkyDrive
You could use an Explicit UpdateSourceTrigger in your binding and then invoke UpdateSource manually when the button is clicked:
XAML Binding.UpdateSourceTrigger when a Button.Click is fired?
If you want to make the process easier, define a BindingGroup for all your bindings and then just call UpdateSources on your BindingGroup when you click the button. You could implement the call to UpdateSources via a simple behavior or attached property.
Context: a C# 4.0 WPF application with a datagrid that has one TemplateColumn showing a progress bar.
How can one get the grid to only display the progress bar for certain items based on a condition?
Maybe listening to the events and hiding the cells / setting visibile to false would be an option.
This is how it looks right now (the progress bar is shown for all items):
<UserControl.Resources>
<DataTemplate x:Key="PotentialDataTemplate">
<Grid Width="70">
<ProgressBar
Height="12"
VerticalAlignment="Center"
Value="{Binding Path=Potential, Mode=OneWay}" />
</Grid>
</DataTemplate>
</UserControl.Resources>
<DataGrid x:Name="dataGrid"
ItemsSource="{Binding Path=Items}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn
Header="{Binding Source={x:Static text:TextBindingProvider.Instance}, Path=CompendiumHeaderPotential}"
Width="Auto"
MinWidth="80"
CellTemplate="{StaticResource PotentialDataTemplate}"
IsReadOnly="true"
SortMemberPath="Potential" />
</DataGrid.Columns>
</DataGrid>
You have a couple of options depending on what the conditions are for visibility. If you have a separate property such as "IsPotentialVisible" then you can bind this to the Visibility property of the progressbar using a BooleanToVisibilityConverter.
Next up, if it is a simple condition such as "hide when Potential == 0", then you could create a DataTrigger that handles this condition.
Otherwise you can also create a custom converter that spits out a visibility based on whatever input properties / parameters are required.
Just found an answer, I simply add the Visibility attribute and Bind it to some conditional Logic in the ViewModel.
Visibility = "{Binding Path=ShowPotentialBar, Mode=OneWay}
So:
<Grid Width="70">
<ProgressBar
Height="12"
VerticalAlignment="Center"
Value="{Binding Path=Potential, Mode=OneWay}"
Visibility = "{Binding Path=ShowPotentialBar, Mode=OneWay}" />
</Grid>