I have a WPF datagrid that is bound to a Realm backed object. The grid has an autocomplete box that allows the user to enter/select an account number which should then update the source object and the UI. Instead, when a selection is made, the UI box goes back to empty and the stored object is not updated. The Realm documentation states Modifying the collection (e.g. adding or removing items) must happen in a write transaction, so somehow, when the user makes a selection I need to trigger a write transaction on that specific row object. This is further confirmed by the error in the output window
System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=SAccount; DataItem='TransactionDetails' (HashCode=24381833); target element is 'DataGridRow' (Name=''); target property is 'NoTarget' (type 'Object') RealmInvalidTransactionException:'Realms.Exceptions.RealmInvalidTransactionException: Cannot modify managed objects outside of a write transaction.
I am trying to use an EventTrigger bound to a command in my VM but the trigger never fires. Can someone explain (or maybe even quickly demonstrate) how to make this work?
In my ViewModel I'm retreiving the object like this:
Transaction = realm.All<Transaction>().Where( t => t.ID == tid ).First();
and then binding it in my XAML view
<DataGrid x:Name="TransactionDataGrid"
DataGridCell.Selected="TransactionDataGrid_GotFocus"
AutoGenerateColumns="False"
CanUserSortColumns="True"
CanUserReorderColumns="False"
HorizontalAlignment="Left"
Margin="10,0,0,0"
VerticalAlignment="Top"
Height="556"
Width="1012"
CanUserAddRows="False"
ItemsSource="{Binding Transaction.Rows}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<DataGrid.Columns>
<DataGridTextColumn x:Name="Source" Header="Source Account" Width="Auto" Binding="{Binding Description}" IsReadOnly="True" />
<DataGridTemplateColumn x:Name="AccountNum" Header="Account Number" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBox BorderThickness="0" Text="{Binding SAccount.RawAccountNumber}"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<toolkit:AutoCompleteBox
Background="AliceBlue"
IsTextCompletionEnabled="True"
FilterMode="Contains"
MinimumPrefixLength="2"
ValueMemberPath="RawAccountNumber"
PreviewTextInput="AutoCompleteBox_PreviewTextInput"
SelectedItem="{Binding SAccount, Mode=TwoWay}"
Text="{Binding Path=SAccount.RawAccountNumber}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Accounts}" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding UpdateRowCommand}"
CommandParameter="{Binding Path=ID}"/><!-- the command parameter should be the ID of the row we are updating? -->
</i:EventTrigger>
</i:Interaction.Triggers>
<toolkit:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Path=RawAccountNumber}" FontWeight="Bold" Width="100"/>
<TextBlock Text="{Binding Path=Description}" />
</StackPanel>
</DataTemplate>
</toolkit:AutoCompleteBox.ItemTemplate>
</toolkit:AutoCompleteBox>
</StackPanel>
The command in my ViewModel
public ICommand UpdateRowCommand
{
set
{
MessageBox.Show( "Hello UpdateRowCommand" );
}
}
Related
i'm faily new in WPF and got a problem with a binding not refreshing the UI.
If i open the window, the datagrid fills as it should. I have an object with refences to 2 other that where compared beforehand, named "Original" and "Vergleicher".
The method "MenuItem_OnClick" copies the value vom "Vergleicher" to "Original". In the binded list this works, i can see the changed values in the debugger, but the UI ignores it.
Set the datacontext in window:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
The actual datagrid:
<TabItem Header="Unterschiede" Visibility="{Binding UiLeistungUnterschiedlich,
Converter={StaticResource EmptyListHiddenConverter}}" Selector.Selected="OnTabSelected">
<Border Style="{StaticResource DropBorderStyle}">
<DataGrid ItemsSource="{Binding UiLeistungUnterschiedlich}"
SelectionChanged="GridHalter_SelectionChanged" SelectedIndex="0"
AutoGenerateColumns="False" SelectionMode="Single" CanUserAddRows="False">
<DataGrid.Columns>
<other Datagridtextcolumns>
<DataGridTemplateColumn Header="Straße">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type abrechnungen:HalterVergleich}">
<StackPanel Background="{Binding BindsDirectlyToSource=True, ConverterParameter=Strasse,
UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BackgroundColorConverter}}">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="In Halter übernehmen" Click="MenuItem_OnClick" Tag="Strasse"/>
</ContextMenu>
</StackPanel.ContextMenu>
<TextBlock Text="{Binding Path=Original.Strasse, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Path=Vergleicher.Strasse, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Border>
</TabItem>
The Border is used to apply a Dropshadow.
The copy method:
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
{
if (!(sender is MenuItem {DataContext: HalterVergleich vergleich} item))
{
return;
}
if (!vergleich.Setzen(item.Tag?.ToString(), Setzen.ZuOriginal))
{
return;
}
OnPropertyChanged(nameof(UiLeistungUnterschiedlich));
}
Sidenote: If anyone knows a way to avoid the use of "Tag" (to call "MenuItem_OnClick") and "ConverterParameter" with explizit values, i would gladly hear it.
I have datagrid to show some data in xaml of UWP application.I use MVVM and a i have view model for the view. Items source of datagrid is observable collection. I have problem with refresh data on xaml view. If i us DataGridTextColumn as column data, data refreshed properly on view, but if i use DataGridTemplateColumn data on view not refresh.
This code work properly:
<mtc:DataGrid Name="ArticlesListView"
ItemsSource="{x:Bind ViewModel.Articles, Mode=OneWay}"
AutoGenerateColumns="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
SelectionMode="Single"
RowDetailsVisibilityMode="Collapsed"
IsReadOnly="True">
<mtc:DataGrid.Columns>
<mtc:DataGridTextColumn Header="Barcode" Binding="{Binding Barcode}"/>
<mtc:DataGridTextColumn Header="Name" Binding="{Binding Description}"/>
</mtc:DataGrid.Columns>
</mtc:DataGrid>
I clear and fill observable collection with new data and data on view is refresh properly.
This code not work properly:
<mtc:DataGrid Name="ArticlesListView"
ItemsSource="{x:Bind ViewModel.Articles, Mode=OneWay}"
AutoGenerateColumns="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
SelectionMode="Single"
RowDetailsVisibilityMode="Collapsed"
IsReadOnly="True">
<mtc:DataGrid.Columns>
<mtc:DataGridTemplateColumn Header="Barcode">
<mtc:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:DataGridCell Background="{Binding Active, Converter={StaticResource BoolToColorConverter}, ConverterParameter=true}"
Data="{Binding Barcode}"/>
</DataTemplate>
</mtc:DataGridTemplateColumn.CellTemplate>
</mtc:DataGridTemplateColumn>
<mtc:DataGridTemplateColumn Header="Name">
<mtc:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:DataGridCell Background="{Binding Active, Converter={StaticResource BoolToColorConverter}, ConverterParameter=true}"
Data="{Binding Description}"/>
</DataTemplate>
</mtc:DataGridTemplateColumn.CellTemplate>
</mtc:DataGridTemplateColumn>
</mtc:DataGrid.Columns>
</mtc:DataGrid>
I clear and fill observable collection with new data but on view stays old data.
Can anyone help me with this issue?
Thank you for help. I figured out the problem. The problem is that property change event does not reach the custom control that i made for DataTemplate and changes does not apply in it. I change this lines of code:
<mtc:DataGridTemplateColumn Header="Barcode" Tag="Barcode">
<mtc:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<controls:DataGridCell Background="{Binding Active, Converter={StaticResource BoolToColorConverter}, ConverterParameter=true}"
Data="{Binding Barcode}"/>
</DataTemplate>
</mtc:DataGridTemplateColumn.CellTemplate>
</mtc:DataGridTemplateColumn>
to this:
<mtc:DataGridTemplateColumn Header="Barcode" Tag="Barcode">
<mtc:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid Background="{Binding Active, Converter={StaticResource BoolToColorConverter}, ConverterParameter=true}">
<TextBlock Text="{Binding Barcode, Converter={StaticResource ObjectToStringConverter}}"
Style="{StaticResource DataGridCellContentStyle}"/>
</Grid>
</DataTemplate>
</mtc:DataGridTemplateColumn.CellTemplate>
</mtc:DataGridTemplateColumn>
and everything works fine. Its just have to define DataTemplate in datagrid not use external user control for DataTemplate because changes does not reach user control and does not apply to the view.
In WPF window, Data grid view will load from database.
This is the design code for Data grid view.(It contains 2 columns - Name, Action)
<DataGrid x:Name="dgrid" HorizontalAlignment="Left" Margin="0,65,0,0" VerticalAlignment="Top" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="160"></DataGridTextColumn>
<DataGridTemplateColumn Header="Action" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button Name="btnEdit" Content="Edit" />
<Button Name="btnDelete" Content="Delete" />
<Button Name="btnActivate" Content="Activate" />
<Button Name="btnDeactivate" Content="Deactivate" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Name column bind the value from data base value, and following column contain 4 buttons!
what I need to do this, based on another column value of database (for example Activation Status) , the btnActivate, btnDeactivate should set their
is Enable property!
how can I accomplish this?
Thanks in Advance
You need to initiate binding to appropriate property from your button:
<Button Name="btnEdit"
Content="Edit"
IsEnabled="{Binding DataContext.ActivationStatus, Converter={StaticResource MyStatusToBooleanConverter}, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}}" />
You should (providing your value in the DB is a boolean), use bindings to set the states.
For example:
<Button Name="btnActivate" Content="Activate" IsEnabled="{Binding ClassPropertyType}" />
And then when you set your ItemSource with a list of your class, it will bind to the set boolean.
I have a view model with a list of Invoices, these invoices are being displayed via a Telerik RadGridView This RadGridView has a RowDetailsTemplate. When I click on a row and expand to show the row details how can I pass the InvoiceViewModel of the selected RadGridViewRow so I can get those details from the database?
The purpose of not loading all of the information at once and waiting to load the details until after the row is selected is to reduce load time.
Here's some code for reference:
<telerik:RadGridView x:Name="InvoicesGridView"
ItemsSource="{Binding InvoicesForView}" DataContext="{Binding }"
RowDetailsVisibilityMode="VisibleWhenSelected"
// other stuff
telerik:GridViewVirtualizingPanel.IsVirtualizing="False" EnableRowVirtualization="False"
CanUserResizeColumns="False">
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowDetailsVisibilityChanged" SourceObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type telerik:GridViewRow}}}">
<i:InvokeCommandAction Command="{Binding DataContext.LoadInvoice, Source={StaticResource ViewContext}}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<telerik:RadGridView.Columns>
<-- Column definitions -->
</telerik:RadGridView.Columns>
<telerik:RadGridView.RowDetailsTemplate>
<-- Row details stuff -->
</telerik:RadGridView.RowDetailsTemplate>
</telerik:RadGridView>
I've tried passing through a selected InvoiceViewModel and all that I get back is null, What can I set the CommandParameter to too get the information I need?
<telerik:RadGridView x:Name="InvoicesGridView"
ItemsSource="{Binding InvoicesForView}" DataContext="{Binding }"
ShowGroupPanel="False" Style="{StaticResource TransparentScrollBarStyle}"
RowIndicatorVisibility="Collapsed"
TextElement.Foreground="White"
TextElement.FontSize="12"
FontWeight="Normal" RowDetailsVisibilityMode="VisibleWhenSelected"
AutoGenerateColumns="False" SelectionMode="Multiple"
ShowColumnHeaders="True" RowHeight="24"
CanUserSelect="True" GroupRenderMode="Flat"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.CanContentScroll="True" ColumnWidth="*"
VirtualizingStackPanel.VirtualizationMode="Standard"
telerik:GridViewVirtualizingPanel.IsVirtualizing="False" EnableRowVirtualization="False"
CanUserResizeColumns="False">
<telerik:RadGridView.Columns>
<telerik:GridViewToggleRowDetailsColumn />
<-- Other columns -->
</telerik:RadGridView.Columns>
<telerik:RadGridView.RowDetailsTemplate>
<DataTemplate>
<Grid Background="#f8f8f8" TextElement.Foreground="Black" TextElement.FontWeight="Normal" TextElement.FontStyle="Normal" Margin="-1,0" MinHeight="20">
<telerik:RadTabControl >
<telerik:RadTabItem DataContext="{Binding}"/>
<i:Interaction.Behaviors>
<behaviors:RadTabControlTabChangeCommandBehavior>
<behaviors:RadTabControlTabChangeCommandBehavior.TabChangeCommands>
<behaviors:TabChangeCommand TabIndex="0" Command="{Binding Path=DataContext.LoadInvoice, Source={StaticResource ViewContext}}"/>
</behaviors:RadTabControlTabChangeCommandBehavior.TabChangeCommands>
</behaviors:RadTabControlTabChangeCommandBehavior>
</i:Interaction.Behaviors>
</telerik:RadTabControl>
<-- Other stuff -->
</telerik:RadGridView.RowDetailsTemplate>
</telerik:RadGridView>
The above is a nice little work around that worked for me
I have a ObservableCollection<T> where T: INotifyDataErrorInfo.
Objects in this collection have validation errors, then I bind this collection to Silverlight 4 DataGrid, is there a way to show this validation error in DataGrid? (show red cell for invalid properties for each object). By default DataGrid show validation error only when I begin to edit row, and only for active row.
I haven't succeeded with a TextBlock control, so I used a disabled TextBox
You can change the template of the TextBox, I mean to remove border and to set its background really transparent.
<sdk:DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}" IsReadOnly="False" SelectionMode="Single">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Title" Binding="{Binding Title}"/>
<sdk:DataGridTemplateColumn Header="Link" Width="100">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Link, Mode=TwoWay}" Margin="2"
IsEnabled="False" BorderThickness="0" Background="Transparent"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Link, Mode=TwoWay}" Margin="2"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>