My autogenerated columns do not show in Datagrid - mvvm

Most posts regarding DataGrid AutoGenerateColumns seem to deal with how to circumvent default behavior. Unfortunately the default is what I am struggling with.
I have several database tables created with Entity Framework 6.0, and would like to display them in my View using one and the same Datagrid for all tables, and AutoGenerating the Columns. Desired outcome: for the class-specific Viewmodel bound at run-time, display the columns with headers and at least one row.
XAML of the View's user control:
<UserControl.Resources>
<DataTemplate x:Key="TableDataTemplate">
<DataGrid
AutoGenerateColumns="True"
GridLinesVisibility="All"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible">
</DataGrid>
</DataTemplate>
</UserControl.Resources>
<StackPanel Height="720" Width="980">
<!-- shows user which menu item was chosen -->
<TextBlock Text="{Binding DisplayName}"/>
<!-- defines the Input data grid for adding to DB table -->
<Grid Height="80" MaxHeight="200">
<ItemsControl
ItemsSource="{Binding CurrentDataTable}"
ItemTemplate="{StaticResource TableDataTemplate}">
</ItemsControl>
</Grid>
The user control is bound to a class-specific 'Class'TableViewModel, implemented for all Database Tables. One example:
class ClientsAdminTableViewModel : TableViewModel
{
// the Property the view binds to
private IList<Client> currentDataTable;
public ObservableCollection<Client> CurrentDataTable
{
get { return CollectionExtensions.ToObservableCollection<Client>(currentDataTable); }
set { currentDataTable = value; OnPropertyChanged("CurrentDataTable")}
}
public ClientsAdminTableViewModel()
{
DisplayName = Strings.ClientAdminDisplayName;
currentDataTable = context.Clients.ToList<Client>();
}
When bound to {Binding CurrentDataTable} this code produces a UI, where I can see a grey body (probably the rows) surrounded by horizontal and vertical scrollbars, on top of which one long line (which must be the header line), but no columns.
Any help is appreciated.

your datagrid needs to have its itemsource set
try adding
ItemsSource="{Binding CurrentDataTable}"
to the datagrid declaration. Also, do you get any binding errors in the output window?

This code now works (Thank you J. King!) The trick was to get rid of the data template, create the data grid right in the grid with the exact same binding statements.
<StackPanel Height="720" Width="980">
<!-- shows user which menu item was chosen -->
<TextBlock Text="{Binding DisplayName}"/>
<!-- defines the Input data grid for adding to DB table -->
<Grid Height="200" MaxHeight="400">
<DataGrid
ItemsSource="{Binding CurrentDataTableNew}"
AutoGenerateColumns="True"
GridLinesVisibility="All"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible" >
</DataGrid>
</Grid>
</userControl>

Related

.net maui Listview ItemSelected not selected when inner elements focused

I have a ListView with one button and one entry on it's ItemTemplate
<ListView
x:Name="LstMedios"
Grid.Row="2"
ItemsSource="{Binding MediosDePago}"
SelectedItem="{Binding MedioPagoSeleccionado,Mode=TwoWay}"
SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid ColumnDefinitions="2*,*" >
<Button
Text="My button"
HeightRequest="40"
HorizontalOptions="FillAndExpand" Margin="5,5" />
<Entry
Text="{Binding NumValor,StringFormat='{0:c}'}"
Keyboard="Numeric"
Grid.Column="1"
HorizontalTextAlignment="End" Margin="0,5,5,5">
</Entry>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I expect when my Entry is focused then my listview SelectedItem must be set, but it remains null.
What is the proper way to force my listview to automatically set SelectedItem when any of its controls on ItemTemplate is focused?
Full sample
To begin with, what you expect is that when directly hitting on the Button or the Entry(get focused), the SelectedItem below should be triggered.
public TestItem SelectedItem
{
get => _SelectedItem;
set => SetProperty(ref _SelectedItem, value);
}
However, the SelectedItem will only be set if clicking on the frame border or outside of it and the background color of the selected item will be Orange. And this potential issue happens both in ListView and CollectionView.
In conclusion, this potential issue is related or similar to CollectionView's SelectionChanged method cannot be triggered when tapping the item directly #9567. You can try this workaround provided by PhoenixWyllow or follow up on it. Besides, you can also raise a new issue on Github if you are willing to.
Update:
For now, Juan implemented a transparent button over the Entry element this way can get access to selected item posting it from CommandParameter.

Xamarin Forms: How to make each Carousel Page a different Color

I created Carousel view that contains a Collection of Slides. Each slide contains and image, message, and Color. It is stored in an ObservableCollection. I have three colors in the collection. The first slide/page should be yellow, second should be Red, and third should be blue. The issue I have is, when the app initiates all of the slides are blue in the carousel. I need each slide/page to have different colors.
Carousel.ItemsSource = slides = new ObservableCollection<Slides>(new[]
{
new Slides("money", "Some Description", BackgroundColor = Color.Yellow),
new Slides("money", "Some Description2", BackgroundColor = Color.Red),
new Slides("money", "Some Description3",BackgroundColor = Color.Blue)});
<Control:CarouselViewControl x:Name="Carousel"
ShowIndicators="True"
BackgroundColor="{Binding Color}"
CurrentPageIndicatorTintColor="Black">
<Control:CarouselViewControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentView Grid.Row="0" Padding="60,30,60,0">
<Image Source="{Binding Image}" Aspect="AspectFit"/>
</ContentView>
<ContentView Grid.Row="1" Padding="20,50,20,0">
<Label Text="{Binding Message}" TextColor="black"
HorizontalOptions="CenterAndExpand"
FontSize="Large"/>
</ContentView>
</Grid>
</DataTemplate>
</Control:CarouselViewControl.ItemTemplate>
</Control:CarouselViewControl>
I expect each page to have different colors.
You are binding the BackgroundColor for the CarouselViewControl, which will set it for the whole view, not the distinct slides.
Furthermore, the items stored in ItemsSource do not represent any views in the CarouselViewControl, but rather data objects. Just because an object in the ItemsSource collection has a value BackgroundColor, the BackgroundColor of the respective view in the CarouselViewControl ain't set automagically.
To set the background of the pages you'll have to operate from within the DataTemplate and bind the BackgroundColor property of the Grid to the respective property of Slide.
<DataTemplate>
<Grid BackgroundColor="{Binding BackgroundColor}"> <!-- Bind the grids BackgroundColor to the one of the Slide -->
<!-- the grids content -->
</Grid>
</DataTemplate>

SilverLight 4.0 C# - DomainDataSource DataGrid with CheckBox Column (UI only - not a data field) to allow user to select multiple records/rows

New to SilverLight and to posting here. Please have mercy and be specific :)
Using RIA services with DomainDataSource and DataGrid control to display data rows from SQL server query
Goal: Have checkbox column (UI only - not a data field) to allow user to select multiple records/rows
BackGround:
1) Created new SilverLight 4, C# solution with RIA services
2) in ProjectName.Web
Created Entity Framework (EF) model referencing SQL server table/view (built solution).
Created Domain Sevice using EF model (built solution).
3) in SilverLightProjectName
From Data Sources window, dragged table onto a design surface to create DomainDataSource and DataGrid (this works great to bind DataGrid to data source)
4) in MainPage.XAML added checkbox column
What's Happening: checkboxes are selected/checked by user, scroll down, scroll back up, all checkboxes reset and ONLY Datagrid.SelectedItem is still checked. I have read this behavior is 'by design' due to paging.
<sdk:DataGrid RowStyle="{StaticResource newDataGridStyle}" AutoGenerateColumns="False" ItemsSource="{Binding ElementName=ddsPagerApp, Path=Data}" Name="vwPagerAppDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected" MouseLeftButtonDown="vwPagerAppDataGrid_MouseLeftButtonDown" VerticalGridLinesBrush="#FFB9B9B9" FontSize="10" Grid.Row="3" SelectionChanged="vwPagerAppDataGrid_SelectionChanged" KeyDown="vwPagerAppDataGrid_KeyDown" MouseLeftButtonUp="vwPagerAppDataGrid_MouseLeftButtonUp" MouseRightButtonUp="vwPagerAppDataGrid_MouseRightButtonUp" DataContext="{Binding}" SelectionMode="Single" IsEnabled="True" IsReadOnly="False" TabIndex="2" Grid.Column="1" Margin="0,10,9,9">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn IsReadOnly="False">
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<CheckBox Name="ChkSelected" IsThreeState="False" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" Unchecked="IndividualCheckBox_Unchecked" Checked="IndividualCheckBox_Checked" Width="Auto" Height="Auto" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTextColumn x:Name="fullNameColumn" Binding="{Binding Path=FullName}" Header="Full Name" IsReadOnly="True" />
<sdk:DataGridTextColumn x:Name="departmentColumn" Binding="{Binding Path=department}" Header="Department" IsReadOnly="True" />
<sdk:DataGridTextColumn x:Name="pager_number_displayColumn" Binding="{Binding Path=pager_number_display}" Header="Pager Number" IsReadOnly="True" />
<sdk:DataGridTextColumn x:Name="PageTo" Binding="{Binding Path=PageTo}" Header="Page To" IsReadOnly="True" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<riaControls:DomainDataSource AutoLoad="True" d:DesignData="{d:DesignInstance my:vwPagerApp, CreateList=true}" Height="0" LoadedData="ddsPagerApp_LoadedData" Name="ddsPagerApp" QueryName="GetVwPagerAppsQuery" Width="0" Margin="10,0,25,45" Background="#FF7D0000" Foreground="#FF7D0000" Visibility="Visible">
<riaControls:DomainDataSource.DomainContext>
<my:NotifyDomainContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
Attempt 1:
in EFModel.edmx, added Boolean Scalar Property 'IsChecked'
in DomainService.metadata.cs, added public bool IsChecked { get; set; }
in MainPage.XAML. added (above) IsChecked="{Binding Path=IsChecked, Mode=TwoWay}"
Getting error: Error 11009: Property ' ' is not mapped
UPDATE: Reversed Attempt 1:
Attempt 2:
Researching possibility of defining a partial class for the entity, wiring to DataGrid, and using that to track CheckBox values. Any advice on if this will work/how to?
Trying my best to absorb this. Please enlighten me...and thank you in advance :)
This is what I implemented and it worked beautifully. I hope it helps someone else in the future :)
1) SilverLight Project C#: Extend entity class using partial class (in separate file, but within same namespace – compiles into 1 class but keeps generated code separate)
namespace Pager.Web
{
public partial class pager_grp
{
bool _IsChecked = false;
public bool IsChecked
{
get
{return this._IsChecked;}
set
{this._IsChecked = !IsChecked;}
}
}
}
2) SilverLight Project GUI: Create Column in DataGrid of type DataGridTemplateColumn named chkSelected
3) SilverLight Project XAML: use template and bind to new property declared in partial class
<sdk:DataGridTemplateColumn IsReadOnly="False">
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<CheckBox Name="ChkSelected" IsThreeState="False" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" HorizontalAlignment="Center" VerticalAlignment="Center" Unchecked="IndividualCheckBox_Unchecked" Checked="IndividualCheckBox_Checked" Width="Auto" Height="Auto" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>

Datagrid selecteditem is set back to null after EventToCommand is called

I have a Silverlight 4 app created in MVVMLight.
In a view I have a DataGrid that is bound to my ViewModel, which has SeletedItem bound to SelectedItem again in my ViwModel :
<sdk:DataGrid Name="MyGrid" AutoGenerateColumns="False" Grid.Row="3" MaxHeight="200" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" RowHeight="35"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, ValidatesOnNotifyDataErrors=False}" ItemsSource="{Binding Items}" >
This all works just as it should as in when I click on an item in the grid the SelectedItem in my ViewModel is set correctly.
Now I have added a button to the rows in the Datagrid and added an EventToCommand to the button which is bound to the same ViewModel:
<Button Content="Update" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Command:EventToCommand Command="{Binding Source={StaticResource Locator}, Path=MainDialog.ButtonCommand, Mode=TwoWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
This command fires and works correctly The Problem Is the SelectedItem property that was set earlier, that I now want to use is set to null!!
Why is this EventToCommand resetting the SelecteedItem property and how do I stop it so I can use it???
you should shar your code to let us see what the problem is. But maybe problem is that you set selected item as object that isn't in your itemsource collection of datagrid. Try to set selecteditem like this
SelectedItem = Items.Where(x => x.Id == someId).First();
And see if this is the problem.. Ofcourse change condition in Where.. :)

Collapse/Visible UserControls on ButtonClick with MVVM - no swap mechanism -

In my scenario I have a MainView + MainViewModel, UserControl1 + UserControl 2.
In the MainView I have 2 buttons labeled: Button_ShowUserControl1 + Button_ShowUserControl2.
At the lower part of the MainView I have a "ContentGrid" which takes/should_take... every UserControl.
My goal:
When Button_ShowUserControl1 is clicked UserControl1 is Visible and UserControl2 OR any other UserControl must be set to Collapsed. Same is valid for Button_ShowUserControl2.
My problem:
1.) As the UserControls shall be loaded at application start how can I put them all together in the one "ContentGrid"? Thats actually not possible... so how can I make one UserControl visible while the other is in the same place/"ContentGrid" just collapsed ?
2.) As 1.) seems not possible how can I instantiate all UserControls at start of the application and make them only Visible/Collapsed when respective Button is clicked?
3.) As a UserControl has a property Visibility = Visible/Hidden/Collapsed, how can I bind to a property in a ViewModel return such a value like Collapsed? I only could get a boolean value like Visibility = false/true ?
My testcode:
<Grid x:Name="LayoutRoot" Background="#FFBDF5BD" ShowGridLines="False">
<Grid.RowDefinitions>
<RowDefinition Height="96*" />
<RowDefinition Height="289*" />
</Grid.RowDefinitions>
<Grid HorizontalAlignment="Stretch" Name="MenuGrid" VerticalAlignment="Stretch" Background="#FFCECEFF">
<StackPanel Name="stackPanel1" Background="#FFEDFF00" Orientation="Horizontal">
<Button Content="User Data 1" Height="35" Name="button1" Command="{Binding Path=ShowUserControl1Command}" Width="150" Margin="100,0,0,0" />
<Button Content="User Data 2" Height="35" Name="button2" Width="150" Margin="100,0,0,0" />
</StackPanel>
</Grid>
<Grid Grid.Row="1" HorizontalAlignment="Stretch" Name="ContentGrid" VerticalAlignment="Stretch" Background="#FFB15454" />
</Grid>
<UserControl x:Class="SwapUserControls.MVVM.UserControl2"
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:vm="clr-namespace:SwapUserControls.MVVM.ViewModel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Visibility="{Binding IsUserControl1Collapsed, Path=Value}">
<UserControl.Resources>
<vm:MainViewModel x:Key="MainViewModelID" />
</UserControl.Resources>
<UserControl.DataContext>
<Binding Source="{StaticResource MainViewModelID}" />
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="228*" />
<RowDefinition Height="72*" />
</Grid.RowDefinitions>
<Button Content="UserControl2" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="112,27,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
<DataGrid HorizontalAlignment="Stretch" Name="dataGrid1" VerticalAlignment="Stretch" Background="#FFC046F8" />
</Grid>
public class MainViewModel : ViewModelBase
{
RelayCommand _ShowUserControl1Command;
private bool _IsUserControl1Collapsed;
public RelayCommand ShowUserControl1Command
{
get
{
if (_ShowUserControl1Command == null)
{
_ShowUserControl1Command = new RelayCommand( () => ShowUserControl1() );
}
return _ShowUserControl1Command;
}
}
public void ShowUserControl1()
{
_IsUserControl1Collapsed = true;
}
public bool IsUserControl1Collapsed
{
get
{
return _IsUserControl1Collapsed;
}
}
}
Yes the code is wrong, therefore I ask here :)
You only have 2 things wrong with this code.
1) You can't set the visibility of a usercontrol directly... you have to set it on a container:
<Grid Visibility="Collapsed">
<myControls:MyUserControl />
</Grid>
2) Visibility is not a boolean value, it is an enum. As such, you will need to use a converter to convert from boolean to Visibility. Observe:
<Window ...>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</Window.Resources>
<Grid Visibility="{Binding ShouldShowUsercontrol1, Converter={StaticResource BoolToVis}}">
<myControls:MyUserControl />
</Grid>
</Window>
That should be it. Hope this helps.
There are other things that you are leaving clues about that might affect the ability of this to work. For example, you don't show the biggest container element... are you wrapping everything in a StackPanel? If you are wrapping everything in a Grid, for example, the controls will overlay everything in layers.
Try these changes I suggest... it should get you closer.
Edit: Another idea using data templates
Another thing you could do is make sure you have a unique ViewModel for each of these views you want to show and hide:
public class MyFirstViewModel : ViewModel
{
}
public class MySecondViewModel : ViewModel
{
}
Then from your "parent" or "main" ViewModel, you show or hide the views you want by virtue of having them in a collection of ViewModels:
public MyMainViewModel : ViewModel
{
public ObservableCollection<ViewModel> ViewsToShow
{
...
}
public void ShowFirstViewModel()
{
ViewsToShow.Add(new MyFirstViewModel());
}
}
To wire everything up in your view, you would then datatemplate these types with their user controls (but this would not cause those views to be instantiated unless they were needed:
<Window ...>
<Window.Resources>
<DataTemplate DataType="{x:Type myViewModels:MyFirstViewModel}">
<myViews:MyFirstView />
</DataTemplate>
<DataTemplate DataType="{x:Type myViewModels:MySecondViewModel}">
<myViews:MySecondView />
</DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding ViewsToShow}" />
</Window>
And for any ViewModels you put in "ViewsToShow", the view will automatically see that and template in the appropriate view. Again, without instantiating it before it's needed.
This is probably a little cleaner than putting everything single thing in the View and setting visibility, but it would be dependent on you have a unique view model type for every view, which might not be the case.
The question of saving state comes up when using the DataTemplated approach. The solution here is to tread your ViewModel as the state of the control and design both your ViewModels and your Views accordingly. Here is an example that allows you to swap out your Views using DataTemplating, but switching back and forth saves state.
Assume you have the setup from the last section w/ 2 viewmodels that have datatemplates defined. Let's change up the MainViewModel a little:
public MyMainViewModel : ViewModel
{
public RelayCommand SwapViewsCommand
{
...
}
public ViewModel View
{
...
}
private ViewModel _hiddenView;
public MyMainViewModel()
{
View = new MyFirstViewModel();
_hiddenView = new MySecondViewModel();
SwapViewsCommand = new RelayCommand(SwapViewModels);
}
public void SwapViewModels()
{
var hidden = _hiddenView;
_hiddenView = View;
View = hidden;
}
}
And a few changes to the main view. I've omitted the DataTemplates for brevity.
<Window ...>
<!-- DataTemplates Here -->
<Button Command="{Binding SwapViewsCommand}">Swap!</Button>
<ContentControl Content="{Binding View}" />
</Window>
That's it. The secret here is I'm saving the reference to the original view model. This way, let's say there is a string property in a viewmodel and an associated textbox in the DataTemplated usercontrol with a two-way binding then the state will essentially be saved.