REACT, hiden element overlays parent element when displayed - reactjs

I have a react component A, that contains more B components generated in A component based on server response using map function. Every B component has a calendar component that needs to show/hide. When calendar component shows it overlays the parent component.
If I put a B component raw, it works perfectly, so I don't think that css is wrong.
When I exam the rendered HTML, the appened calendar is at right place in DOM.
Whad did I wrong.
My A component:
class OffersDesktop extends OffersBase<WithStyles<typeof styles>>
{
render()
{
const css = this.props.classes;
const offers:BookingOffersResponse[] = this.state.offers;
const selectionPalens = offers.map
(
(offer: BookingOffersResponse, index: number) =>
{
return <SelectedPanel offer={offer} key={index + 1} />
}
);
const canContinue: boolean = this.store.state.selectedOffer.OfferID !== '';
const continueButon: JSX.Element = <BlueButton enable={!canContinue} text="Continue" onClick={this.continue}/>;
const Body = () =>
<StackPanel className={css.root} orientation="vertical" centerHorizontally centerVertically>
<Header />
<StackPanel className={css.container} orientation="vertical">
<StackPanel {...dockLeft}>
<HorizontalLinearStepper step={this.props.step} />
</StackPanel>
<StackPanel {...dockLeft} centerVertically className={css.titleContainer}>
<LocalOffer fontSize="large" className={css.icon} />
<span className={css.title}>Offers</span>
</StackPanel>
<StackPanel orientation="horizontal" centerHorizontally>
<StackPanel orientation="vertical" {...dockLeft}>
<StackPanel centerHorizontally centerVertically orientation="vertical">
<SelectedPanel offer={{} as any} key={0} />
<CircleLoader css={css.spinner}
sizeUnit={'px'}
size={100}
color={'#123abc'}
loading={this.state.isDataLoaded}
/>
</StackPanel>
{!this.state.isDataLoaded && selectionPalens}
<StackPanel centerHorizontally centerVertically>
<YearRoundPanel onClick={ this.yearRoundHandler } />
</StackPanel>
</StackPanel>
<StackPanel orientation="vertical" className={css.rightContainer}>
<StackPanel className={css.continueContainer} orientation="vertical" centerHorizontally centerVertically>
<StackPanel className={css.continueButton}>{continueButon}</StackPanel>
<Typography className={css.continueContainerText} variant="subtitle1">Book now with $25 deposit</Typography>
</StackPanel>
<SearchParameters searchParameters={this.state.appState.searchParameters}/>
</StackPanel>
</StackPanel>
</StackPanel>
<StackPanel className={css.footer} {...dockBottom} centerHorizontally><Footer /></StackPanel>
</StackPanel>
return Body();
}
B component
class SelectedPanel extends Connected<typeof React.Component, IProps & WithStyles<typeof styles>, IState, AppStore>(React.Component)
{
constructor(props: IProps & WithStyles<typeof styles>)
{
super(props);
this.state =
{
showCalendar: false,
appState: this.store.state
}
}
showCalnedarHandler = (event: React.MouseEvent<HTMLElement, MouseEvent>) : void =>
{
event.preventDefault();
this.setState
({
...this.state,
showCalendar: !this.state.showCalendar
})
}
render()
{
const css = this.props.classes;
const offer = this.props.offer;
const Body = () =>
<StackPanel className={css.root} centerHorizontally centerVertically orientation="vertical">
<StackPanel className={css.container} orientation="horizontal">
<StackPanel className={css.left} orientation="vertical">
<Typography className={css.typeText} variant="h6" gutterBottom>{this.state.appState.bookingTypeName} Dockage</Typography>
<Typography variant="h6" gutterBottom>
<span className={css.priceText}>$100.00</span><span className={css.priceTextExcluding}> per night excluding texes and add-ons</span>
</Typography>
<Typography className={css.offText} variant="h6">50% of (was $200)</Typography>
<StackPanel centerHorizontally centerVertically orientation="vertical" className={css.buttonContainer}>
<StackPanel {...dockTop} centerHorizontally centerVertically className={css.button} >Arrivals on 04/19/19 have a 3 night minimum stay</StackPanel>
<StackPanel {...dockBottom} centerHorizontally centerVertically className={css.button}>Space is aviable but the requestet shore power is not awiable</StackPanel>
</StackPanel>
<Typography onClick={event => this.showCalnedarHandler(event)} className={css.showCalendarText} variant="subtitle1">
Show pricing calendar
<KeyboardArrowDown className={css.selectionArrow}/>
</Typography>
</StackPanel>
<StackPanel className={css.right} orientation="vertical" centerHorizontally>
<StackPanel {...dockTop} centerHorizontally centerVertically className={css.whiteButton}>
<InformationButton text="Only 2 spaces left"/>
</StackPanel>
<StackPanel {...dockBottom} centerHorizontally centerVertically className={css.selectedButton}>
<SelectedButton text="Selected" />
</StackPanel>
</StackPanel>
</StackPanel>
{
this.state.showCalendar &&
<StackPanel className={css.calendarPanelContainer} {...dockBottom}>
<CalendarPanel searchParameters={this.state.appState.searchParameters}/>
</StackPanel>
}
</StackPanel>
return Body();
}
}
Calendar component
class CalendaPranel extends React.Component<IProps & WithStyles<typeof styles>, IState>
{
render()
{
const css = this.props.classes;
const Body = () =>
<StackPanel className={css.root} centerVertically orientation="vertical">
<StackPanel className={css.calendarContainer} centerHorizontally centerVertically>
<Calendar searchParameters={this.props.searchParameters}/>
</StackPanel>
<StackPanel className={css.legend} centerVertically orientation="horizontal">
<span className={css.unavailable}></span>Unavailable
<span className={css.available}></span>Available
<span className={css.selectedStartDay}></span>Selected Start Day
<span className={css.dateRange}></span>Date Range
</StackPanel>
<Typography className={css.legendText} variant="subtitle1">Above is the price for each night of dockage excluding taxes and add-ons</Typography>
</StackPanel>
return Body();
}
}
thnx

Related

Creation of controls dynamically on a separate thread

I am developing a WPF app, to generate folders dynamically
Right now I have an issue with what happens if the user puts 10000 folders? I am trying to run my for loop in another thread
By the way, how can I limit the user to create x number of folders?
Code Behind:
public MainWindowVM() {
SaveCommand = new Command(SaveAction);
FoldersCollection = new ObservableCollection<FolderData>();
CreateCommand = new Command(CreateAction);
CreateFoldersCommand = new Command(CreateFolderAction);
}
private void SaveAction() {
}
private void CreateFolderAction() {
var dirrName = "Assets";
var workingDirectory = Environment.CurrentDirectory;
// This will get the current PROJECT directory
var projectDirectories = Directory.GetParent(workingDirectory).Parent.Parent.GetDirectories(dirrName)
.ToList();
var path = Path.GetFullPath(projectDirectories.First().FullName);
foreach (var item in FoldersCollection) {
Directory.CreateDirectory($"{path}\\{item.FolderName}");
}
}
private void CreateAction() {
for (int i = 0; i < Value; i++) {
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate {
FoldersCollection.Add(new FolderData() { FolderID = i, FolderName = string.Empty, Extenion = new List<string>() });
}));
XAML:
<WrapPanel>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="600" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition Width="400" />
</Grid.ColumnDefinitions>
<Label Content="Number of folders: " />
<TextBox
Grid.Column="1"
VerticalAlignment="Center"
PreviewTextInput="FolderNames_count"
Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" />
<Button
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
BorderBrush="Transparent"
Command="{Binding CreateCommand}"
Content="Create"
Focusable="False" />
<ScrollViewer
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="10"
BorderBrush="Transparent"
Focusable="False"
HorizontalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding FoldersCollection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="0,10,0,0"
VerticalAlignment="Center"
FontStyle="Oblique"
Text="{Binding FolderID}" />
<syncfusion:SfTextBoxExt
Width="300"
Margin="10,10,0,0"
VerticalAlignment="Center"
Text="{Binding FolderName, UpdateSourceTrigger=PropertyChanged}"
Watermark="Folder Name" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Button
Grid.Row="2"
VerticalAlignment="Center"
Command="{Binding CreateFoldersCommand}"
Content="Create structure"
Style="{StaticResource MenuItem}" />
<Button
Grid.Row="2"
Grid.Column="1"
Margin="5,0,0,0"
VerticalAlignment="Center"
Command="{Binding SaveCommand}"
Content="Save structure"
Style="{StaticResource MenuItem}" />
</Grid>
</WrapPanel>
The app works fine, but when I exit, I get this error
btw I am doing this to allow numbers in my textbox
private void FolderNames_count(object sender, TextCompositionEventArgs e) {
if (!char.IsDigit(e.Text, e.Text.Length - 1))
e.Handled = true;
}
If you commands run on separate thread, then it looks like the bg thread still running during GUI thread is finished.
My recommendation is to put the handling of this case to the Window.Closing handler, i.e. do notify thread to break the loop, e.g. set cancellation token.
The brutal option would be to call Enviroment.Exit(0) method in the Window.Closing or Window.Closed handler, to terminate all threads. See Environment.Exit(Int32) Method
It's the loop should be executed on a background thread:
private void CreateAction()
{
Task.Run(() =>
{
for (int i = 0; i < Value; i++)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
FoldersCollection.Add(new FolderData() { FolderID = i })));
}
});
}

Navigating from one screen to another in Caliburn

I am using a sample from http://www.mindscapehq.com/blog/index.php/2013/09/11/caliburn-micro-part-6-introduction-to-screens-and-conductors/
There is an AppViewModel in which other ViewModels are activated by calling ActivateItem.
The sample is working for me: I can see the corresponding View.
I now want to activate a ViewModel from another ViewModel. It gets instantiated but the corresponding View is not displayed.
How can I activate "GreenScreenViewModel" from "RedScreenViewModel"?
AppView:
<UserControl x:Class="CaliburnMicroApp_Navigation.AppView"
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">
<DockPanel Background="LightBlue" MinHeight="400" MinWidth="400">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" HorizontalAlignment="Center">
<Button x:Name="ShowRedScreen" Content="Red" Width="50" />
<Button x:Name="ShowGreenScreen" Content="Green" Width="50" Margin="12,0,0,0" />
<Button x:Name="ShowBlueScreen" Content="Blue" Width="50" Margin="12,0,0,0" />
</StackPanel>
<ContentControl x:Name="ActiveItem" />
</DockPanel>
</UserControl>
AppViewModel
public class AppViewModel : Conductor<object>
{
public void ShowRedScreen()
{
ActivateItem(new RedViewModel());
}
public void ShowGreenScreen()
{
ActivateItem(new GreenViewModel());
}
public void ShowBlueScreen()
{
ActivateItem(new BlueViewModel());
}
}
RedViewModel - this does not display GreenView ()
public class RedViewModel : Conductor<object>
{
public void DisplayGreen()
{
ActivateItem(new GrenViewModel());
}
}
RedView
<Grid Background="Red">
<StackPanel>
<TextBlock Text="red" FontSize="48" FontWeight="Bold" Foreground="#3CA527" />
<Button Name="DisplayGreen">
<TextBlock >Next Screen</TextBlock>
</Button>
</StackPanel>
</Grid>
If you want the ActiveItem displayed in the ContentControl of your AppView to change when you press your Button in RedViewModel, you will need to use the EventAggregator to pass a message from your RedViewModel to your AppViewModel.
Mindscape EventAggregator tutorial

Fixed Wrap panel wpf

i am working on wpf window that show list of items next each other with wrapping, i have tried to use WrapPanel in this way:
<Grid>
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Items>
<Button Content="01" Height="30" Width="70"/>
<Button Content="02" Height="35" Width="72"/>
<Button Content="03" Height="20" Width="74"/>
<Button Content="04" Height="25" Width="76"/>
<Button Content="05" Height="18" Width="78"/>
<Button Content="06" Height="50" Width="70"/>
<Button Content="07" Height="40" Width="72"/>
<Button Content="08" Height="55" Width="74"/>
<Button Content="09" Height="45" Width="76"/>
<Button Content="10" Height="25" Width="78"/>
<Button Content="11" Height="20" Width="80"/>
<Button Content="12" Height="30" Width="70"/>
<Button Content="13" Height="45" Width="72"/>
<Button Content="14" Height="30" Width="74"/>
<Button Content="15" Height="20" Width="76"/>
<Button Content="16" Height="25" Width="78"/>
<Button Content="17" Height="35" Width="80"/>
<Button Content="18" Height="50" Width="70"/>
<Button Content="19" Height="55" Width="72"/>
<Button Content="20" Height="45" Width="74"/>
<Button Content="21" Height="20" Width="76"/>
<Button Content="22" Height="60" Width="78"/>
<Button Content="23" Height="20" Width="80"/>
<Button Content="24" Height="25" Width="70"/>
<Button Content="25" Height="30" Width="72"/>
</ItemsControl.Items>
</ItemsControl>
</Grid>
and this is the result:
Actually this result is unsatisfactory for me because if you imagine the WrapPanel as grid(rows and columns) you will find that there is no columns, but there are fixed size rows. i need to make WarpPanel or some control else without columns too, look at this imaginary image:
notice that there is no rows and no columns. this is what i wanna make.
anybody have ideas to solve this issue?
You could write your own custom Panel class. There are some tutorials on the web, simply google "wpf custom panel".
It boils down to overriding the MeasureOverride and ArrangeOverride methods.
public class CustomPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
Size panelDesiredSize = new Size();
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
// Use child.DesiredSize, availableSize.Width and the positions
// and sizes of the previous children to calculate the position of
// the current child. Then determine the resulting Panel height.
panelDesiredSize = ...
}
return panelDesiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
foreach (UIElement child in InternalChildren)
{
// Arrange each child according to the position calculations
// done in MeasureOverride
Point position = ...
child.Arrange(new Rect(position, child.DesiredSize));
}
return finalSize;
}
}
UPDATE: The following simple custom Panel might more or less do what you want.
public class PackPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
}
var positions = new Point[InternalChildren.Count];
var desiredHeight = ArrangeChildren(positions, availableSize.Width);
return new Size(availableSize.Width, desiredHeight);
}
protected override Size ArrangeOverride(Size finalSize)
{
var positions = new Point[InternalChildren.Count];
ArrangeChildren(positions, finalSize.Width);
for (int i = 0; i < InternalChildren.Count; i++)
{
var child = InternalChildren[i];
child.Arrange(new Rect(positions[i], child.DesiredSize));
}
return finalSize;
}
private double ArrangeChildren(Point[] positions, double availableWidth)
{
var lastRowStartIndex = -1;
var lastRowEndIndex = 0;
var currentWidth = 0d;
var desiredHeight = 0d;
for (int childIndex = 0; childIndex < InternalChildren.Count; childIndex++)
{
var child = InternalChildren[childIndex];
var x = 0d;
var y = 0d;
if (currentWidth == 0d || currentWidth + child.DesiredSize.Width <= availableWidth)
{
x = currentWidth;
currentWidth += child.DesiredSize.Width;
}
else
{
currentWidth = child.DesiredSize.Width;
lastRowStartIndex = lastRowEndIndex;
lastRowEndIndex = childIndex;
}
if (lastRowStartIndex >= 0)
{
int i = lastRowStartIndex;
while (i < lastRowEndIndex - 1 && positions[i + 1].X < x)
{
i++;
}
while (i < lastRowEndIndex && positions[i].X < x + child.DesiredSize.Width)
{
y = Math.Max(y, positions[i].Y + InternalChildren[i].DesiredSize.Height);
i++;
}
}
positions[childIndex] = new Point(x, y);
desiredHeight = Math.Max(desiredHeight, y + child.DesiredSize.Height);
}
return desiredHeight;
}
}
You Can Either use Canvas:
Or Use Grid and set the Margin of each Buttons according to requirenment
<Canvas >
<Button Content="s" Width="50" Canvas.Left="17" Canvas.Top="20" />
<Button Canvas.Left="73" Canvas.Top="32" Content="s" Width="60" Height="42" />
<Button Canvas.Left="139" Canvas.Top="10" Content="s" Height="42" Width="60" />
</Canvas>
<Grid >
<Button Content="01" Height="30" Width="70" Margin="20,12,414,268" />
<Button Content="02" Height="35" Width="72" Margin="426,148,6,128" />
<Button Content="03" Height="20" Width="74" Margin="190,122,240,170" />
<Button Content="04" Height="25" Width="76" Margin="386,26,40,260" />
<Button Content="05" Height="18" Width="78" Margin="376,202,48,92" />
<Button Content="06" Height="50" Width="70" Margin="385,64,48,196" />
<Button Content="07" Height="40" Width="72" Margin="162,202,269,68" />
<Button Content="08" Height="55" Width="74" Margin="20,154,408,102" />
<Button Content="09" Height="45" Width="76" Margin="21,95,406,171" />
<Button Content="10" Height="25" Width="78" Margin="44,47,382,239" />
<Button Content="11" Height="20" Width="80" Margin="386,120,38,170" />
<Button Content="12" Height="30" Width="70" Margin="95,13,338,268" />
<Button Content="13" Height="45" Width="72" Margin="290,6,140,260" />
<Button Content="14" Height="30" Width="74" Margin="210,38,220,244" />
<Button Content="15" Height="20" Width="76" Margin="128,48,299,242" />
<Button Content="16" Height="25" Width="78" Margin="265,189,160,97" />
<Button Content="17" Height="35" Width="80" Margin="176,154,246,122" />
<Button Content="18" Height="50" Width="70" Margin="100,146,333,116" />
<Button Content="19" Height="55" Width="72" Margin="270,121,160,135" />
<Button Content="20" Height="45" Width="74" Margin="348,148,81,118" />
<Button Content="21" Height="20" Width="76" Margin="94,78,332,212" />
<Button Content="22" Height="60" Width="78" Margin="270,60,155,192" />
<Button Content="23" Height="20" Width="80" Margin="176,74,247,216" />
<Button Content="24" Height="25" Width="70" Margin="194,95,238,191" />
<Button Content="25" Height="30" Width="72" Margin="117,104,314,177" />
</Grid>

Bind listbox to ObservableCollection

I cannot find an answer I can work with for this problem.
I have an ObservableCollection
this is myClass:
public class myClass
{
public string name;
public int[] dimensions = new int[2];
}
This is the code that sets ObservableCollection:
public class roomBuilder
{
private ObservableCollection<myClass> rooms;
public roomBuilder() //constructor
{
string roomName;
int[] dimensions = new int[2];
myClass newRoom = new myClass();
rooms = new ObservableCollection<room>();
roomName = "Hall";
dimensions[0] = 10;
dimensions[1] = 12;
newRoom.name = roomName;
newRoom.dimensions = dimensions;
rooms.Add(newRoom);
roomListBox.DataContext = rooms;
}
the XAML for this is:
<ListBox Canvas.Left="-1" Canvas.Top="47" Height="419" Name="roomListBox" Width="481" BorderThickness="1" BorderBrush="GhostWhite" ItemsSource="{Binding}" DataContext="{Binding}">
<ListBox.ItemTemplate >
<DataTemplate >
<StackPanel Orientation="Vertical" Margin="1" Name="verstack" >
<StackPanel Orientation="Horizontal" Margin="1" KeyDown="StackPanel_KeyDown" >
<TextBox Text="{Binding Path=name}" IsReadOnly="False" FontFamily="Courier New" FontSize="22" Height="65" VerticalAlignment="Top" TextAlignment="Center"/>
<TextBox Name="xDimension" Text="{Binding Mode=TwoWay, Path=dimensions[0] }" Width="70" Height="65" VerticalAlignment="Top" IsReadOnly="False" FontFamily="Courier New" Margin="2,0,1,0" FontSize="22" MaxLength="3" InputScope="TelephoneNumber" TextAlignment="Center" />
<TextBlock Name="separator" Text=":" FontSize="32" FontWeight="ExtraBold" Margin="1,4,1,0" />
<TextBox Name="yDimension" Text="{Binding Mode=TwoWay, Path=dimensions[1] }" Width="70" Height="65" VerticalAlignment="Top" IsReadOnly="False" FontFamily="Courier New" Margin="1,0,2,0" FontSize="22" MaxLength="3" InputScope="TelephoneNumber" TextAlignment="Center"/>
I havent closed the Xaml off here , there's a load more underneath it, when I run this nothing is displayed and I just don't know what the problem is, I've been hammering away at it for 2 days, please someone help
Rooms needs to be a public property that you bind to.
public ObservableCollection<myClass> rooms
{
get { return ........

refresh datagrid on view from viewmodel

I have a datagrid on a view that is bound to a viewmodel. When I initialze the view, the datagrid is populated with data from the viewmodel (ObservableCollection) as it should. However, with I try to do a search against the data, the datagrid does not get refreshed from the viewmodel. When I breakpoint the code in my viewmodel, I can see the results in the ObservableCollection has changed per my search, but somehow that is not getting communicated back to the view. Here is my view and viewmodel (BTW, I am using VS2010 RTM):
namespace Attendance.ViewModels
{
public class EmployeeSelectViewModel : ViewModel, INotifyPropertyChanged
{
#region Entity list and constructor
public EmployeeSelectViewModel()
{
{
Initialize();
}
}
private void Initialize()
{
if (employeeRpository == null)
employeeRpository = new EmployeeRepository();
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
}
private EmployeeRepository employeeRpository;
private ObservableCollection<EmployeeDto> listOfEmployees;
public ObservableCollection<EmployeeDto> ListOfEmployees
{
get { return listOfEmployees; }
set
{
if (listOfEmployees != value)
{
listOfEmployees = value;
NotifyPropertyChanged("ListOfEmployee");
}
}
}
private EmployeeDto selectedEmployee;
public EmployeeDto SelectedEmployee
{
get { return selectedEmployee; }
set
{
if (selectedEmployee != value)
{
selectedEmployee = value;
NotifyPropertyChanged("SelectedEmployee");
}
}
}
#endregion
#region UI control references
/// <summary>
/// search text property
/// </summary>
private string searchText;
public string SearchText
{
get { return searchText; }
set
{
if (searchText != value)
{
searchText = value;
NotifyPropertyChanged("SearchText");
}
}
}
public string Location { get; set; }
#endregion
#region Relay Commands
/// <summary>
/// new command
/// </summary>
private ViewCommand newCommand;
public ViewCommand NewCommand
{
get
{
if (newCommand == null)
newCommand = new ViewCommand(param => this.NewEmployee());
return newCommand;
}
}
private void NewEmployee()
{
NavigationActions.NewEmployeeView();
}
/// <summary>
/// edit command
/// </summary>
private ViewCommand editCommand;
public ViewCommand EditCommand
{
get
{
if (editCommand == null)
{
editCommand = new ViewCommand(param => this.EditEmployee());
}
return editCommand;
}
}
private void EditEmployee()
{
NavigationActions.OpenEmployeeView(SelectedEmployee);
}
/// <summary>
/// save command
/// </summary>
private ViewCommand saveCommand;
public ViewCommand SaveCommand
{
get
{
if (saveCommand == null)
{
saveCommand = new ViewCommand(
param => this.SaveEmployee(),
param => this.CanSaveEmployee
);
}
return saveCommand;
}
}
public void SaveEmployee()
{
employeeRpository.SaveChanges();
}
private bool CanSaveEmployee
{
get { return true; }
}
/// <summary>
/// clear search command
/// </summary>
private ViewCommand clearSearchCommand;
public ViewCommand ClearSearchCommand
{
get
{
if (clearSearchCommand == null)
clearSearchCommand = new ViewCommand(param => this.ClearSearch());
return clearSearchCommand;
}
}
private void ClearSearch()
{
this.SearchText = string.Empty;
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployees(true));
}
/// <summary>
/// search command
/// </summary>
private ViewCommand searchCommand;
public ViewCommand SearchCommand
{
get
{
if (searchCommand == null)
searchCommand = new ViewCommand(param => this.SearchEmployee());
return searchCommand;
}
}
private void SearchEmployee()
{
if (this.SearchText == string.Empty || this.SearchText == null)
{
NavigationActions.ShowError("Search Employees.", "Please enter your search text ...");
return;
}
ListOfEmployees = new ObservableCollection<EmployeeDto>(employeeRpository.GetEmployeesByQuery(SearchText, Location));
}
/// <summary>
/// exit command
/// </summary>
private ViewCommand exitCommand;
public ViewCommand ExitCommand
{
get
{
if (exitCommand == null)
{
exitCommand = new ViewCommand(param => this.ExitWindow());
}
return exitCommand;
}
}
private void ExitWindow()
{
NavigationActions.CloseCurrentView();
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
<Window x:Class="Attendance.Views.EmployeeSelectView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Attendance.ViewModels"
Title="Employee Maintenance" FocusManager.FocusedElement="{Binding ElementName=txtSearchCriteria}"
Height="525" Width="800" WindowStartupLocation="CenterScreen" WindowState="Normal"
WindowStyle="SingleBorderWindow" Icon="Images/gb_icon.png">
<Window.DataContext>
<vm:EmployeeSelectViewModel />
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/DataGrid.Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--xml data start-->
<XmlDataProvider x:Key="LocationData" XPath="LocationList/LocationItem" Source="XMLData/Location.xml"/>
<!--xml data end-->
</ResourceDictionary>
</Window.Resources>
<Grid Width="775">
<DockPanel HorizontalAlignment="Left" Width="770">
<!-- TOOLBAR -->
<DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="5">
<ToolBar FontWeight="Bold">
<!-- NEW -->
<Button Name="btnNew" Command="{Binding Path=NewCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Create a new Customer
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Create a new customer in a new Window tab.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/new.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/new.png" Width="22" Height="22" Margin="2"/>
<Label VerticalAlignment="Center">_New</Label>
</StackPanel>
</Button>
<!-- EDIT -->
<Button Name="btnEdit" Command="{Binding Path=EditCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Edit the current record
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Edit the current selected Customer.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/dialog-information.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/edit.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Edit</Label>
</StackPanel>
</Button>
<!-- SEARCH -->
<Separator />
<TextBox Name="txtSearchCriteria"
MinWidth="300" Margin="5"
BorderThickness="1" BorderBrush="LightGray"
FontWeight="Normal" Foreground="Gray" Text="{Binding Path=SearchText}">
</TextBox>
<Button Name="btnSearch" Command="{Binding Path=SearchCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Search
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Search a specific Customer.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/find.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/find.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Find</Label>
</StackPanel>
</Button>
<Button Name="btnClearSearch" Command="{Binding Path=ClearSearchCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Search
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Clear search results.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/find.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Label VerticalAlignment="Center">_Clear Search</Label>
</StackPanel>
</Button>
<!-- EXIT -->
<Separator />
<Button Name="btnExit" Command="{Binding Path=ExitCommand}">
<Button.ToolTip>
<StackPanel>
<Label FontWeight="Bold" Background="SteelBlue" Foreground="White">
Start the application
</Label>
<TextBlock Padding="10" TextWrapping="WrapWithOverflow" Width="200">
Start the main application with the M-V-MV pattern.
</TextBlock>
<Line Stroke="SteelBlue" StrokeThickness="1" X2="200" />
<StackPanel Orientation="Horizontal">
<Image Margin="2" Source="Images/dialog-information.png"/>
<Label>Press F1 for more help</Label>
</StackPanel>
</StackPanel>
</Button.ToolTip>
<StackPanel Orientation="Horizontal">
<Image Source="Images/exit.png" Width="22" Height="22" Margin="2" />
<Label VerticalAlignment="Center">_Exit</Label>
</StackPanel>
</Button>
</ToolBar>
</DockPanel>
<!-- LIST -->
<DockPanel DockPanel.Dock="Top" MinHeight="30" Margin="0,0,0,5">
<Label>Location:</Label>
<ComboBox Name="cboLocation" Grid.Column="1" Grid.Row="4"
ItemsSource="{Binding Source={StaticResource LocationData}}"
DisplayMemberPath="location_text" SelectedValuePath="location_value"
SelectedValue="{Binding Path=Location}"
HorizontalAlignment="Left" Width="175" Margin="4" />
</DockPanel>
<DockPanel Margin="5">
<DataGrid ItemsSource="{Binding Path=ListOfEmployees}" AutoGenerateColumns="False" IsReadOnly="True"
Name="dgEmployee" SelectionMode="Single" SelectionUnit="FullRow" CanUserResizeColumns="True"
SelectedItem="{Binding Path=SelectedEmployee}" GridLinesVisibility="Horizontal">
<DataGrid.Columns>
<DataGridTextColumn Header="Employee ID" Width="SizeToCells" MinWidth="125" Binding="{Binding EmployeeID}" />
<DataGridTextColumn Header="First Name" Width="SizeToCells" MinWidth="200" Binding="{Binding FirstName}" />
<DataGridTextColumn Header="Last Name" Width="SizeToCells" MinWidth="200" Binding="{Binding LastName}" />
<DataGridTextColumn Header="Location" Width="SizeToCells" MinWidth="125" Binding="{Binding Location}" />
<DataGridCheckBoxColumn x:Name="Active" Header="Active" Binding="{Binding active}" MinWidth="75" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</DockPanel>
</Grid>
This was my solution:
<DataGrid Name="dgrid" ItemsSource="{Binding UserSettings, IsAsync=True}" AutoGenerateColumns="False">
The key being the setting of IsAsync=True, allows the screen paint to occur
I found 2 ways to refresh DataGrid:
One was posted by VariableLost, it works with INotifyPropertyChanged but have one drawback. Whole DataGrid is refreshed with blink effect (disappears for a split second). Doesn't look natural.
Other solution is to refresh ObservableCollection in ViewModel or Code Behind (if you're not using MVVM):
CollectionViewSource.GetDefaultView(collectionName).Refresh();
Looks more natural because only changes cells affected by edition.
Your previous code should have also worked, but 'magic strings' got in the way.
Property name is ListOfEmployees and in its setter you raise PropertyChanged event with property name ListOfEmployee. 's' is missing.
Beware of your new code. It will raise CollectionChanged event on ListOfEmployees for every insertion, and that might make your app slower if you are doing many insertions.
For many insertions, it would be better to derive from ObservableCollection and implement Reset method that clears underlying Items, adds new items and raises CollectionChanged event of type Reset.
My question was answered in a post on another site. Instead of creating a new instance of the ListOfEmployees in my view model, I just cleared the existing one and added the results from my repository:
private void SearchEmployee()
{
if (String.IsNullOrEmpty(this.SearchText) || String.IsNullOrEmpty(this.Location))
{
NavigationActions.ShowError("Search Employees.", "Please enter your search text and select a location...");
return;
}
// clear the list and repopulate based on the search criteria
if (ListOfEmployees != null)
{
ListOfEmployees.Clear();
IList<EmployeeDto> iList = employeeRpository.GetEmployeesByQuery(SearchText, Location, IsActive);
foreach (EmployeeDto value in iList)
ListOfEmployees.Add(value);
}
}
That did the trick.

Resources