removing empty space of listview in xamarin forms - xamarin.forms.listview

I am using xamarin.forms listview for my project. The design is below:
<ContentView x:Name="Overlay" IsVisible="False"
VerticalOptions="Center" HorizontalOptions="Center" Margin="10,20,10,30"
AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All" BackgroundColor="LightGray">
<StackLayout Spacing="0">
<StackLayout Padding="20" BackgroundColor="#9C6114" Spacing="0">
<Label Text="Country Name" TextColor="White" FontAttributes="Bold" HorizontalTextAlignment="Center" VerticalTextAlignment="Center"></Label>
</StackLayout>
<StackLayout Spacing="0">
<ListView x:Name="CountryList" HasUnevenRows="True" Margin="10,0,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Switch IsToggled="{Binding IsToggle}"></Switch>
<Label Text="{Binding CountryName}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Footer>
<StackLayout Orientation="Horizontal">
<Button x:Name="btncancel" Text="Cancel" TextColor="White" BackgroundColor="#9C6114" HorizontalOptions="CenterAndExpand" Clicked="btncancel_Clicked"></Button>
<Button x:Name="btnsubmit" Text="Submit" TextColor="White" BackgroundColor="#9C6114" HorizontalOptions="CenterAndExpand" Clicked="btnsubmit_Clicked"></Button>
</StackLayout>
</ListView.Footer>
</ListView>
</StackLayout>
</StackLayout>
</ContentView>
For this listview, there is emplty space below the listview. I cannot remove the extra spaces in listview. Please see the attached image.enter image description here
Please help me to resolve this issues.

I had a problem that was similar to that. I followed this link: https://xamarinsharp.com/2017/05/20/xamarin-forms-listview-height-change-dynamically-using-mvvm-and-also-solve-empty-space-issue/
Basically, if you didn't already, you'll need to set up your project with MVVM. In your XAML you'll have to give a HeighRequest property to your listview and set it's value as: HeighRequest="{Binding Height}". In your viewmodel, add this:
int _height;
public int Height
{
get { return _height; }
set
{
_height = value;
OnPropertyChanged("Height");
}
}
Then, in your viewModel's constructor (or wherever you set up your listview's objects), add this:
Height = (**object**.Count * 60) + (**object**.Count * 10);
This worked just fine for me!

After much searching, I found the following worked for me: I have a list view template with a Frame that contains a Grid. In my XAML file I added a SizeChanged event and BindingContext for the Grid:
...
<ListView x:Name="worksiteList"
ItemsSource="{Binding WorksiteList}"
SelectionMode="Single"
SeparatorVisibility="None"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Margin="0" Padding="0">
<Frame ...>
<Grid
SizeChanged="worksiteGrid_SizeChanged"
BindingContext="{Binding .}"
RowDefinitions="Auto,Auto"
ColumnDefinitions="50*,40*">
Then in code behind, I added the SizeChanged event handler and an override of OnAppearing, as follows:
private Dictionary<int, double> _worksiteFrameSizeMap = new Dictionary<int, double>();
public void worksiteGrid_SizeChanged(object sender, EventArgs e)
{
var grid = sender as Grid;
if (grid != null)
{
var frame = grid.Parent as Frame;
if (frame != null)
{
var worksite = grid.BindingContext as Worksite;
if (worksite != null)
{
var frameHeight = 0.0;
frameHeight += frame.Height;
frameHeight += frame.Margin.Top;
frameHeight += frame.Margin.Bottom;
_worksiteFrameSizeMap[worksite.WorksiteId] = frameHeight;
}
}
}
}
protected override void OnAppearing()
{
base.OnAppearing();
var worksiteListViewHeight = 0.0;
foreach (var item in _worksiteFrameSizeMap)
{
worksiteListViewHeight += item.Value;
}
worksiteList.HeightRequest = worksiteListViewHeight;
}
This is the only way I could get the list height so there is no blank space below the last list item (and I tried many others that didn't work). Unfortunately there is a slight blink as the page appears. I am inclined to think the ListView control has a bug because the ListView ought to do this automatically (does anyone ever want blank space below a list?) and there is no simple way to access the item sizes in a list.

Related

WPF How to find a specific control in an ItemsControl with data binding

I have an ItemsControl which is bound to a list:
<ItemsControl x:Name="icFiles" ItemsSource="{Binding Path=files}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
<TextBlock x:Name="ThisTextBlock" Text="{Binding FileName}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
private readonly List<FileModel> files = new();
icFiles.ItemsSource = files;
I want to highlight certain text in the TextBlock in the ItemsControl. For this, I thought about using a TextPointer:
string? highlightText = "blue";
int highlightTextIndex = ThisTextBlock.Text.IndexOf(highlightText);
if(highlightTextIndex >= 0)
{
TextPointer textStartPointer = ThisTextBlock.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
TextRange? highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Blue);
}
}
How do I find this ThisTextBlock?
You need to access the item container's content template (which is the item's DataTemplate).
In case of the ItemsControl, you can use the following example to obtain a named element from the DataTemplate:
for (int itemIndex = 0; itemIndex < this.ItemsControl.Items.Count; itemIndex++)
{
var itemContainer = this.ItemsControl.ItemContainerGenerator.ContainerFromIndex(itemIndex) as ContentPresenter;
var textBlock = itemContainer.ContentTemplate.FindName("ThisTextBlock", itemContainer) as TextBlock;
HighlightText(textBlock);
}
A simple implementation that searches an element in the visual tree can be found at How to: Microsoft Docs: How to: Find DataTemplate-Generated Elements. You can copy and use the example's helper method FindVisualChild to search for elements by type rather than by name. The method is part of an example that shows how to get the content of the DataTemplate in case you use a ListBox or ListView.
In case you didn't modified the ListBoxItem template or don't expect it to change, you can use this simplified and faster version (to find named elements):
for (int itemIndex = 0; itemIndex < this.ListBox.Items.Count; itemIndex++)
{
var listBoxItemContainer = this.ListBox.ItemContainerGenerator.ContainerFromIndex(itemIndex) as ListBoxItem;
var templateRootBorder = VisualTreeHelper.GetChild(listBoxItemContainer, 0) as Border;
var contentHost = templateRootBorder.Child as ContentPresenter;
var textBlock = contentHost.ContentTemplate.FindName("TD", contentHost) as TextBlock;
}
Except for special use cases, it is highly recommended to use the ListBox instead of the ItemsControl. ListBox and ListView are both an extended ItemsControl. They both provide scrolling and a significantly improved performance.
First of all, you need to delete the Binding from code behind.
You can do this using Loaded event as follows:
<ItemsControl x:Name="icFiles" ItemsSource="{Binding Path=files}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
<TextBlock Loaded="ThisTextBlock_OnLoaded" x:Name="ThisTextBlock" Text="{Binding FileName}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
private void ThisTextBlock_OnLoaded(object sender, RoutedEventArgs e)
{
if (sender is TextBlock tb)
{
string? highlightText = "blue";
int highlightTextIndex = tb.Text.IndexOf(highlightText);
if (highlightTextIndex >= 0)
{
TextPointer textStartPointer = tb.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
TextRange? highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Blue);
}
}
}

ListBox throws ItemControl Text Visualizer error when scrolling

I have a listbox, code below, that I'm populating with 900 items. When I scroll down the list quickly I get an exception of 'An ItemsControl is inconsistent with its items source'. Any ideas as to what is causing the issue?
<ListBox x:Name="FileList" ItemsSource="{Binding Files}" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True"
MaxHeight="520" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox x:Name="FileChecked" IsChecked="{Binding Checked}" Grid.Column="0" BorderThickness="1"/>
<Label Content="{Binding Name}" Grid.Column="1" />
<Label Content="{Binding Source}" Grid.Column="2" Style="{StaticResource FileProperties}" />
<Label Content="{Binding Destination}" Grid.Column="3" Style="{StaticResource FileProperties}"/>
<Label Content="{Binding ArchiveLocation}" Grid.Column="4" Style="{StaticResource FileProperties}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
enter image description here
Here is a video of the issue. https://www.screencast.com/t/YUlp24zoXiG
I believe I've found the problem. I've pasted the problematic code below, so that other visitors can benefit from this answer.
// Your code from GitHub unchanged
private async void Preview_Click(object sender, System.Windows.RoutedEventArgs e)
{
vm.Files = new List<InstrumentFile>();
try
{
for (int i = 0; i < InstrumentList.Items.Count; i++)
{
ListBoxItem lbi = (InstrumentList.ItemContainerGenerator.ContainerFromIndex(i)) as ListBoxItem;
ContentPresenter cp = GetFrameworkElementByName<ContentPresenter>(lbi);
DataTemplate dt = InstrumentList.ItemTemplate;
CheckBox cb = (dt.FindName("InstrumentChecked", cp)) as CheckBox;
if (cb.IsChecked == true)
{
List<InstrumentFile> instrumentFiles = new List<InstrumentFile>();
Instrument instrument = ((Instrument)(InstrumentList.Items[i]));
string[] files = Directory.GetFiles(instrument.FileSource);
foreach (string file in files)
{
FileInfo fi = new FileInfo(file);
instrumentFiles.Add(new InstrumentFile()
{
Name = fi.Name,
Source = instrument.FileSource,
Destination = instrument.Destination,
ArchiveLocation = instrument.ArchiveLocation
});
}
if (string.IsNullOrEmpty(instrument.FileExt) == false)
{
IEnumerable<InstrumentFile> filteredFiles = instrumentFiles.Where(f => f.Name.ToUpper().EndsWith(instrument.FileExt.ToUpper()));
if (filteredFiles.Count() > 0)
vm.Files.AddRange(filteredFiles);
}
else
{
if (instrumentFiles.Count > 0)
vm.Files.AddRange(instrumentFiles);
}
}
}
}
catch (Exception ex)
{
await metroWindow.ShowMessageAsync("Exception Encountered", ex.Message, MessageDialogStyle.Affirmative, Helpers.DialogSettings());
}
FileCount.Content = vm.Files.Count.ToString() + " files";
}
Here, you're initializing the Files property in the view model. This causes the data-binding to be updated to an empty list. There's no problem so far. However, you then add things to Files, but these changes are not propagated to the data-binding system because the list in the view model is not an ObservableCollection.
You can fix this problem in a couple of ways. One type of fix is to set the Files property in the view model after you've created and filled the list. The new code would look like this (abbreviated):
private async void Preview_Click(object sender, System.Windows.RoutedEventArgs e)
{
// Create new variable to store the list
var files = new List<InstrumentFile>();
// You do a bunch of things, but you now add items to files, not to vm.Files
files.AddRange(filteredFiles);
// Finally, change Files
vm.Files = files
}
That last line will raise the PropertyChanged event in the view model to update the data-binding, but will do so with the full list of items.
The second kind of fix is to change the type of Files in your view model to ObservableCollection<InstrumentFile>. Any time you make a change to Files, the correct event will be raised to update the data-binding.

WPF Combobox is blank (data binding)

I followed a simple tutorial for comboboxes (http://www.wpf-tutorial.com/list-controls/combobox-control/).
Here is my XAML for the combobox :
<ComboBox Name="CoursesTeach" Grid.Row="7" Grid.Column="1" Width="150" Height="Auto" Margin="0,24">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Foreground="Black" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code behind :
public AddTrainer()
{
InitializeComponent();
using (Model1Container context = new Model1Container())
{
foreach (var row in context.CourseSet)
{
if (row.Discipline != null)
{
CoursesTeach.ItemsSource = row.Discipline;
}
MetroCustomBox.ShowOK(row.Discipline); // i can see right values
}
}
}
But the results are just NOT in the combobox, although I can perfectly can print them.
Thanks a lot for your responses.
To add items in your Combobox by code behind you may use Items property.
With your previous code :
foreach (var row in context.CourseSet)
{
if (row.Discipline != null)
{
CoursesTeach.Items.Add(row.Discipline);
}
}
But a better way, is use ItemsSource property, with binding, or set by a List.
With your previous code :
CoursesTeach.ItemsSource = context.CourseSet.Where(row => row.Dicipline != null).Select(row => row.Dicipline).ToList();

WPF / Silverlight Binding when setting DataTemplate programmatically

I have my little designer tool (my program).
On the left side I have TreeView and on the right site I have Accordion.
When I select a node I want to dynamically build Accordion Items based on Properties from DataContext of selected node.
Selecting nodes works fine, and when I use this sample code for testing it works also.
XAML code:
<layoutToolkit:Accordion x:Name="accPanel"
SelectionMode="ZeroOrMore"
SelectionSequence="Simultaneous">
<layoutToolkit:AccordionItem Header="Controller Info">
<StackPanel Orientation="Horizontal" DataContext="{Binding}">
<TextBlock Text="Content:" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</layoutToolkit:AccordionItem>
</layoutToolkit:Accordion>
C# code:
private void treeSceneNode_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (e.NewValue != e.OldValue)
{
if (e.NewValue is SceneNode)
{
accPanel.DataContext = e.NewValue; //e.NewValue is a class that contains Name property
}
}
}
But the problem occurs when I'm trying to achive this using DateTemplate and dynamically build AccordingItem, the Binding is not working:
<layoutToolkit:Accordion x:Name="accPanel"
SelectionMode="ZeroOrMore"
SelectionSequence="Simultaneous" />
and DataTemplate in my ResourceDictionary
<DataTemplate x:Key="dtSceneNodeContent">
<StackPanel Orientation="Horizontal" DataContext="{Binding}">
<TextBlock Text="Content:" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
and C# code:
private void treeSceneNode_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (e.NewValue != e.OldValue)
{
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri("/SilverGL.GUI;component/SilverGLDesignerResourceDictionary.xaml", UriKind.RelativeOrAbsolute);
if (e.NewValue is SceneNode)
{
accPanel.DataContext = e.NewValue;
AccordionItem accController = new AccordionItem();
accController.Header = "Controller Info";
accController.ContentTemplate = rd["dtSceneNodeContent"] as DataTemplate;
accPanel.Items.Add(accController);
}
else
{
// Other type of node
}
}
}
Are you missing this?
accController.Content = e.NewValue;
Also, I don't think you need to use DataContext="{Binding}"; the DataContext will inherit anyway.

WPF DataGrid: Blank Row Missing

I am creating a WPF window with a DataGrid, and I want to show the blank "new item" row at the bottom of the grid that allows me to add a new item to the grid. For some reason, the blank row is not shown on the grid on my window. Here is the markup I used to create the DataGrid:
<toolkit:DataGrid x:Name="ProjectTasksDataGrid"
DockPanel.Dock="Top"
Style="{DynamicResource {x:Static res:SharedResources.FsBlueGridKey}}"
AutoGenerateColumns="False"
ItemsSource="{Binding SelectedProject.Tasks}"
RowHeaderWidth="0"
MouseMove="OnStartDrag"
DragEnter="OnCheckDropTarget"
DragOver="OnCheckDropTarget"
DragLeave="OnCheckDropTarget"
Drop="OnDrop"
InitializingNewItem="ProjectTasksDataGrid_InitializingNewItem">
<toolkit:DataGrid.Columns>
<toolkit:DataGridCheckBoxColumn HeaderTemplate="{DynamicResource {x:Static res:SharedResources.CheckmarkHeaderKey}}" Width="25" Binding="{Binding Completed}" IsReadOnly="false"/>
<toolkit:DataGridTextColumn Header="Days" Width="75" Binding="{Binding NumDays}" IsReadOnly="false"/>
<toolkit:DataGridTextColumn Header="Due Date" Width="75" Binding="{Binding DueDate, Converter={StaticResource standardDateConverter}}" IsReadOnly="false"/>
<toolkit:DataGridTextColumn Header="Description" Width="*" Binding="{Binding Description}" IsReadOnly="false"/>
</toolkit:DataGrid.Columns>
</toolkit:DataGrid>
I can't figure out why the blank row isn't showing. I have tried the obvious stuff (IsReadOnly="false", CanUserAddRows="True"), with no luck. Any idea why the blank row is disabled? Thanks for your help.
You must also have to have a default constructor on the type in the collection.
Finally got back to this one. I am not going to change the accepted answer (green checkmark), but here is the cause of the problem:
My View Model wraps domain classes to provide infrastructure needed by WPF. I wrote a CodeProject article on the wrap method I use, which includes a collection class that has two type parameters:
VmCollection<VM, DM>
where DM is a wrapped domain class, and DM is the WPF class that wraps it.
It truns out that, for some weird reason, having the second type parameter in the collection class causes the WPF DataGrid to become uneditable. The fix is to eliminate the second type parameter.
Can't say why this works, only that it does. Hope it helps somebody else down the road.
Vincent Sibal posted an article describing what is required for adding new rows to a DataGrid. There are quite a few possibilities, and most of this depends on the type of collection you're using for SelectedProject.Tasks.
I would recommend making sure that "Tasks" is not a read only collection, and that it supports one of the required interfaces (mentioned in the previous link) to allow new items to be added correctly with DataGrid.
In my opinion this is a bug in the DataGrid. Mike Blandford's link helped me to finally realize what the problem is: The DataGrid does not recognize the type of the rows until it has a real object bound. The edit row does not appear b/c the data grid doesn't know the column types. You would think that binding a strongly typed collection would work, but it does not.
To expand upon Mike Blandford's answer, you must first assign the empty collection and then add and remove a row. For example,
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// data binding
dataGridUsers.ItemsSource = GetMembershipUsers();
EntRefUserDataSet.EntRefUserDataTable dt = (EntRefUserDataSet.EntRefUserDataTable)dataGridUsers.ItemsSource;
// hack to force edit row to appear for empty collections
if (dt.Rows.Count == 0)
{
dt.AddEntRefUserRow("", "", false, false);
dt.Rows[0].Delete();
}
}
Add an empty item to your ItemsSource and then remove it. You may have to set CanUserAddRows back to true after doing this. I read this solution here: (Posts by Jarrey and Rick Roen)
I had this problem when I set the ItemsSource to a DataTable's DefaultView and the view was empty. The columns were defined though so it should have been able to get them. Heh.
This happned to me , i forgot to new up the instance and it was nightmare for me . once i created an instance of the collection in onviewloaded it was solved.
`observablecollection<T> _newvariable = new observablecollection<T>();`
this solved my problem. hope it may help others
For me the best way to implement editable asynchronous DataGrid looks like that:
View Model:
public class UserTextMainViewModel : ViewModelBase
{
private bool _isBusy;
public bool IsBusy
{
get { return _isBusy; }
set
{
this._isBusy = value;
OnPropertyChanged();
}
}
private bool _isSearchActive;
private bool _isLoading;
private string _searchInput;
public string SearchInput
{
get { return _searchInput; }
set
{
_searchInput = value;
OnPropertyChanged();
_isSearchActive = !string.IsNullOrEmpty(value);
ApplySearch();
}
}
private ListCollectionView _translationsView;
public ListCollectionView TranslationsView
{
get
{
if (_translationsView == null)
{
OnRefreshRequired();
}
return _translationsView;
}
set
{
_translationsView = value;
OnPropertyChanged();
}
}
private void ApplySearch()
{
var view = TranslationsView;
if (view == null) return;
if (!_isSearchActive)
{
view.Filter = null;
}
else if (view.Filter == null)
{
view.Filter = FilterUserText;
}
else
{
view.Refresh();
}
}
private bool FilterUserText(object o)
{
if (!_isSearchActive) return true;
var item = (UserTextViewModel)o;
return item.Key.Contains(_searchInput, StringComparison.InvariantCultureIgnoreCase) ||
item.Value.Contains(_searchInput, StringComparison.InvariantCultureIgnoreCase);
}
private ICommand _clearSearchCommand;
public ICommand ClearSearchCommand
{
get
{
return _clearSearchCommand ??
(_clearSearchCommand =
new DelegateCommand((param) =>
{
this.SearchInput = string.Empty;
}, (p) => !string.IsNullOrEmpty(this.SearchInput)));
}
}
private async void OnRefreshRequired()
{
if (_isLoading) return;
_isLoading = true;
IsBusy = true;
try
{
var result = await LoadDefinitions();
TranslationsView = new ListCollectionView(result);
}
catch (Exception ex)
{
//ex.HandleError();//TODO: Needs to create properly error handling
}
_isLoading = false;
IsBusy = false;
}
private async Task<IList> LoadDefinitions()
{
var translatioViewModels = await Task.Run(() => TranslationRepository.Instance.AllTranslationsCache
.Select(model => new UserTextViewModel(model)).ToList());
return translatioViewModels;
}
}
XAML:
<UserControl x:Class="UCM.WFDesigner.Views.UserTextMainView"
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:model="clr-namespace:Cellebrite.Diagnostics.Model.Entities;assembly=Cellebrite.Diagnostics.Model"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:converters1="clr-namespace:UCM.Infra.Converters;assembly=UCM.Infra"
xmlns:core="clr-namespace:UCM.WFDesigner.Core"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<DockPanel>
<StackPanel Orientation="Horizontal"
DockPanel.Dock="Top"
HorizontalAlignment="Left">
<DockPanel>
<TextBlock Text="Search:"
DockPanel.Dock="Left"
VerticalAlignment="Center"
FontWeight="Bold"
Margin="0,0,5,0" />
<Button Style="{StaticResource StyleButtonDeleteCommon}"
Height="20"
Width="20"
DockPanel.Dock="Right"
ToolTip="Clear Filter"
Command="{Binding ClearSearchCommand}" />
<TextBox Text="{Binding SearchInput, UpdateSourceTrigger=PropertyChanged}"
Width="500"
VerticalContentAlignment="Center"
Margin="0,0,2,0"
FontSize="13" />
</DockPanel>
</StackPanel>
<Grid>
<DataGrid ItemsSource="{Binding Path=TranslationsView}"
AutoGenerateColumns="False"
SelectionMode="Single"
CanUserAddRows="True">
<DataGrid.Columns>
<!-- your columns definition is here-->
</DataGrid.Columns>
</DataGrid>
<!-- your "busy indicator", that shows to user a message instead of stuck data grid-->
<Border Visibility="{Binding IsBusy,Converter={converters1:BooleanToSomethingConverter TrueValue='Visible', FalseValue='Collapsed'}}"
Background="#50000000">
<TextBlock Foreground="White"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text="Loading. . ."
FontSize="16" />
</Border>
</Grid>
</DockPanel>
This pattern allows to work with data grid in a quite simple way and code is very simple either.
Do not forget to create default constructor for class that represents your data source.

Resources