In my program i create dynamically TabItems, and i can create a few the same items. Problem is when i am switching from one to second the same items. In this moment event:
private void TabCards_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.Source is TabControl)
{
...
}
}
run 2 times. I could give Stopwatch and block run this event twice time in a short period of time. But i dont think it is good solution.
Maybe have someone idea what can i do?
Edit
This is how i add item:
private void AddTabItemForCard(string cardName)
{
var style = (Style)resources.FindResource("Style" + cardName);
var tabItem = new TabItem
{
Style = style,
Header = cardName
};
TabCards.Items.Add(tabItem);
}
This is TabControl in xaml:
<TabControl x:Name="TabCards" Grid.Column="1" SelectionChanged="TabCards_SelectionChanged" >
</TabControl>
And style:
<Style x:Key="StyleWej" TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="AllowDrop" Value="True"/>
<EventSetter Event="PreviewMouseMove" Handler="TabItem_PreviewMouseMove"/>
<EventSetter Event="Drop" Handler="TabItem_Drop"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<TextBlock TextWrapping="Wrap" Text="Adres(hex)" FontSize="15" Margin="10,10,396,444"/>
<ComboBox x:Name="AddressWej" HorizontalAlignment="Left" Margin="134,11,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem>30</ComboBoxItem>
<ComboBoxItem>31</ComboBoxItem>
<ComboBoxItem>32</ComboBoxItem>
</ComboBox>
<TextBlock TextWrapping="Wrap" Text="Wejscie 1:" FontSize="15" Margin="10,126,396,337"/>
<TextBlock TextWrapping="Wrap" Text="Wejscie 2:" FontSize="15" Margin="10,156,396,307"/>
<TextBox TextWrapping="Wrap" Text="Wejscie1" Width="120" Margin="134,129,231,331"/>
<TextBox TextWrapping="Wrap" Text="Wejscie2" Width="120" Margin="134,157,231,302"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Events:
private void TabItem_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (!(e.Source is TabItem tabItem))
return;
if (Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop(tabItem, tabItem, DragDropEffects.All);
}
}
private void TabItem_Drop(object sender, DragEventArgs e)
{
var tabItemTarget = e.Source as TabItem;
var tabItemSource = e.Data.GetData(typeof(TabItem)) as TabItem;
if (!tabItemTarget.Equals(tabItemSource))
{
var tabControl = tabItemTarget.Parent as TabControl;
int sourceIndex = tabControl.Items.IndexOf(tabItemSource);
int targetIndex = tabControl.Items.IndexOf(tabItemTarget);
tabControl.Items.Remove(tabItemSource);
tabControl.Items.Insert(targetIndex, tabItemSource);
tabControl.Items.Remove(tabItemTarget);
tabControl.Items.Insert(sourceIndex, tabItemTarget);
}
}
And in TabCards_SelectionChanged i check with TabItem is it and run:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject rootObject) where T : DependencyObject
{
if (rootObject != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(rootObject); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(rootObject, i);
if (child != null && child is T)
yield return (T)child;
foreach (T childOfChild in FindVisualChildren<T>(child))
yield return childOfChild;
}
}
}
to find all TextBox from TabItem
enter image description here
Related
I would like to create an horizontal dynamic listbox:
A button is visible when the mouse is between two items.
<ListBox
MinHeight="32"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
SelectionMode="Extended"
HorizontalAlignment="Stretch">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>
<TextBlock><Run Text="C1" /></TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock><Run Text="C2" /></TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock><Run Text="C3" /></TextBlock>
</ListBoxItem>
<ListBoxItem>
<TextBlock><Run Text="C4" /></TextBlock>
</ListBoxItem>
</ListBox>
</ListBox>
Any suggestions, please?
Thank you
EDIT
private void myElement_MouseEnter(object sender, MouseEventArgs e)
{
//change button visibility
if (sender is Grid item)
{
if (item.DataContext is DataModel data)
{
System.Diagnostics.Debug.WriteLine("myElement_MouseEnter: " + data.TextValue);
}
var border1 = (Border)item.FindName("HitTestBorder1");
var border2 = (Border)item.FindName("HitTestBorder2");
if (border1 is Border)
{
var margin = border1.Margin;
margin.Left = -item.ActualWidth;
border1.Margin = margin;
}
if (border2 is Border)
{
var margin = border2.Margin;
margin.Left = item.ActualWidth;
border2.Margin = margin;
}
}
}
The problem is that the grid width is resized after mouse_enter... So, I don't get the overlay "effect".
Here is the solution.
I created a canvas. It contains 2 borders with button inside and ZPanel is setted very high (=1000) to be on top of everything.
I change the position of these borders on MouseEnter and MouseLeave events of ListBoxItem (see ItemTemplate).
XAML
<Border Padding="10">
<Canvas x:Name="supergrid" MouseLeave="supergrid_MouseLeave">
<Border x:Name="HitTestBorder1"
Panel.ZIndex="1000"
Background="Transparent"
BorderBrush="Transparent"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderThickness="0,0,0,0" >
<Button x:Name="button1"
Visibility="Hidden"
Content="+"
Height="18" Width="18" FontSize="6" Background="Red"
Click="button1_Click"
/>
</Border>
<Border x:Name="HitTestBorder2"
Panel.ZIndex="1000"
Background="Transparent"
BorderBrush="Transparent"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderThickness="1,1,1,1" >
<Button x:Name="button2"
Visibility="Hidden"
Content="+"
Height="18" Width="18" FontSize="6" Background="Green"
Click="button2_Click"
/>
</Border>
<ListBox x:Name="HorizontalListBox"
ItemsSource="{Binding DataModels}"
Margin="0,0,0,0"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="Yellow" MouseLeave="HorizontalListBox_MouseLeave">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<!--<Setter Property="MinWidth" Value="60" />
<Setter Property="MinHeight" Value="40" />-->
<Setter Property="Background" Value="Blue" />
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="myElement"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
MouseEnter="myElement_MouseEnter"
MouseLeave="myElement_MouseLeave"
Background="White">
<TextBlock x:Name="myText"
Margin="10"
Text="{Binding TextValue}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Canvas>
</Border>
C#
public partial class MainWindow : Window
{
private DataModel currentDataModel;
public ObservableCollection<DataModel> DataModels { get; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
this.DataModels = new ObservableCollection<DataModel>();
this.DataModels.Add(new DataModel("Item1"));
this.DataModels.Add(new DataModel("Item2"));
this.DataModels.Add(new DataModel("SuperMegaHyperLong"));
this.DataModels.Add(new DataModel("Item3"));
this.DataModels.Add(new DataModel("Item4"));
this.DataModels.Add(new DataModel("123"));
this.DataModels.Add(new DataModel("Item5"));
}
private void myElement_MouseEnter(object sender, MouseEventArgs e)
{
updateOverlay((Grid)sender);
}
private void updateOverlay(Grid lbi)
{
if (lbi is Grid item) //the grid of listboxitem
{
if (item.DataContext is DataModel data)
{
Debug.WriteLine("myElement_MouseEnter: " + data.TextValue);
}
var myText = (TextBlock)item.FindName("myText");
if (myText is TextBlock)
{
Point relativePoint = myText.TransformToAncestor(supergrid)
.Transform(new Point(0, 0));
Debug.WriteLine("relativePoint: " + relativePoint.ToString());
//update left button position
double w = button1.ActualWidth;
double h = button1.ActualHeight;
double x = relativePoint.X - w / 2.0 - myText.Margin.Left;
double y = relativePoint.Y;
updateMargin(HitTestBorder1,
x,
x + w,
y + h,
y);
//update right button position
w = button2.ActualWidth;
h = button2.ActualHeight;
x = relativePoint.X - w / 2.0 - myText.Margin.Left;
x += item.ActualWidth;
y = relativePoint.Y;
updateMargin(HitTestBorder2,
x,
x + w,
y + h,
y);
//show the button
button1.Visibility = button2.Visibility = Visibility.Visible;
//the current item
if (myText.DataContext is DataModel dm)
{
this.currentDataModel = dm;
}
}
}
}
private void updateMargin(Border border, double left, double right, double bottom, double top)
{
//border = HitTestBorder2;
var margin = border.Margin;
margin.Left = left;
margin.Right = right;
margin.Top = top;
margin.Bottom = bottom;
border.Margin = margin;
Debug.WriteLine("updateMargin Left: " + left.ToString() + "Right: " + right.ToString());
}
private void myElement_MouseLeave(object sender, MouseEventArgs e)
{
//change button visibility
if (sender is Grid item)
{
if (item.DataContext is DataModel data)
{
System.Diagnostics.Debug.WriteLine("myElement_MouseLeave: " + data.TextValue);
}
//button1.Visibility = button2.Visibility = Visibility.Hidden;
}
}
private void HorizontalListBox_MouseLeave(object sender, MouseEventArgs e)
{
Debug.WriteLine("HorizontalListBox_MouseLeave");
//button1.Visibility = button2.Visibility = Visibility.Hidden;
}
private void supergrid_MouseLeave(object sender, MouseEventArgs e)
{
Debug.WriteLine("supergrid_MouseLeave: ");
button1.Visibility = button2.Visibility = Visibility.Hidden;
// => :D
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("LEFT INSERT");
int idx = this.DataModels.IndexOf(currentDataModel);
DataModel newDataModel = new DataModel($"Item{this.DataModels.Count}");
this.DataModels.Insert(idx, newDataModel);
button1.Visibility = button2.Visibility = Visibility.Hidden;
}
private void button2_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("RIGHT INSERT");
int idx = this.DataModels.IndexOf(currentDataModel);
this.DataModels.Insert(idx+1, new DataModel($"Item{this.DataModels.Count}"));
button1.Visibility = button2.Visibility = Visibility.Hidden;
}
}
public class DataModel
{
public string TextValue { get; set; }
public DataModel(string textValue)
{
this.TextValue = textValue;
}
}
As you can see, there is place for improvements (like select the new ListBoxItem). Disable the buttons when we drag, animation, delay, etc.
I have the following WPF DataGrid with GroupStyle. I need to now which rows are expanded when I have expanded/collapsed event.
I add:
Expanded="Expander_Process" Collapsed="Expander_Process"
but in the event function Expander_Process when I try to get the row
var row = DataGridRow.GetRowContainingElement(expander);
if (row == null)
then the row is null. So my question is: how can I know which rows are expanded in the datagrid?
<DataGrid x:Name="gvOptionChain" AutoGenerateColumns="False" FontWeight="Bold" Background="#FF262626" Foreground="White" Width="1509"
ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto"
Margin="53,120,89,4.333" HorizontalContentAlignment="Right" SelectionChanged="gvOptionChain_SelectionChanged" VirtualizingPanel.IsVirtualizingWhenGrouping="True"
VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.ScrollUnit ="Item" VirtualizingPanel.VirtualizationMode="Recycling" EnableRowVirtualization="True" EnableColumnVirtualization = "True"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectionUnit="Cell" SelectedItem="{Binding SelectedItem, Mode=OneWay}" >
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="False" Foreground="#FFEEEEEE" Expanded="Expander_Process" Collapsed="Expander_Process" >
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock FontWeight="Bold" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GroupItem}}, Converter={StaticResource ResourceKey=groupToTitleConverter}}" />
</StackPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
private void Expander_Process(object sender, RoutedEventArgs e)
{
if (sender is Expander expander)
{
var row = DataGridRow.GetRowContainingElement(expander);
if (row == null)
{
}
}
}
on the expander event - get the rows that expanded throu
CollectionViewGroup Items1 = ((CollectionViewGroup)(expander.DataContext));
and update a flag about the IsExpanded status of the row . this event happens many times for each expand - so I add timer to process the rows only once
private System.Timers.Timer ExpandTimer;
private bool bIsTimerOn = false;
private void Expander_Process(object sender, RoutedEventArgs e)
{
if (sender is Expander expander)
{
CollectionViewGroup Items1 = ((CollectionViewGroup)(expander.DataContext));
for(int i = 0; i < Items1.Items.Count; i++)
{
OptScrtyData ScrtyData1 = (OptScrtyData)Items1.Items[i];
ScrtyData1.IsExpanded = expander.IsExpanded;
}
if (bIsTimerOn == false)
{
ExpandTimer.Start();
bIsTimerOn = true;
}
}
}
a better answer - activate the timer only if there is new expand status :
private void Expander_Process(object sender, RoutedEventArgs e)
{
if (sender is Expander expander)
{
CollectionViewGroup Items1 = ((CollectionViewGroup)(expander.DataContext));
bool bNewStatus = false;
for(int i = 0; i < Items1.Items.Count; i++)
{
OptScrtyData ScrtyData1 = (OptScrtyData)Items1.Items[i];
if (bNewStatus == false)
{
bNewStatus = ScrtyData1.IsExpanded != expander.IsExpanded;
}
ScrtyData1.IsExpanded = expander.IsExpanded;
}
if (bNewStatus == true)
{
ExpandTimer.Start();
}
}
}
Expander button is not working properly in my wpf datagrid. I am using the following template for expander button.
<!-- MouseOver, Pressed behaviours-->
<Trigger Property="IsMouseOver"
Value="true">
<Setter Property="Stroke"
Value="#FF3C7FB1"
TargetName="Circle"/>
<Setter Property="Stroke"
Value="#222"
TargetName="Sign"/>
</Trigger>
<Trigger Property="IsPressed"
Value="true">
<Setter Property="Stroke"
Value="#FF526C7B"
TargetName="Circle"/>
<Setter Property="StrokeThickness"
Value="1.5"
TargetName="Circle"/>
<Setter Property="Stroke"
Value="#FF003366"
TargetName="Sign"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- Simple Expander Template-->
<ControlTemplate x:Key="SimpleExpanderTemp" TargetType="{x:Type Expander}">
<DockPanel>
<ToggleButton x:Name="ExpanderButton"
DockPanel.Dock="Top"
Template="{StaticResource SimpleExpanderButtonTemp}"
Content="{TemplateBinding Header}"
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
OverridesDefaultStyle="True"
Padding="1.5,0">
</ToggleButton>
<ContentPresenter x:Name="ExpanderContent"
Grid.Row="1"
Visibility="Collapsed"
DockPanel.Dock="Bottom"/>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ExpanderContent" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Also i am adding the following code for datagridtemplatecolumn.
<DataGridTemplateColumn Width="27">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Expander Template="{StaticResource SimpleExpanderTemp}" Expanded="Expander_Expanded" Collapsed="Expander_Collapsed"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
But if i am trying to expand one expander button in my wpf datagrid, some of the other expander buttons are also expanding(not every time) and some of the expander buttons are collapsing.
What is the error in this xaml code?
The expander events are,
private void Expander_Expanded(object sender, RoutedEventArgs e)
{
ContentControl cc = sender as ContentControl;
Expander exp = cc as Expander;
var itemsSource = objDatagrid.ItemsSource as IEnumerable;
if (itemsSource != null)
{
foreach (var item in itemsSource)
{
var row = objDatagrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (row != null)
{
row.IsSelected = false;
}
}
}
for (var vis = sender as Visual; vis != null; vis = VisualTreeHelper.GetParent(vis) as Visual)
if (vis is DataGridRow)
{
var row = (DataGridRow)vis;
row.IsSelected = true;
if (exp.IsExpanded)
{
row.DetailsVisibility = Visibility.Visible;
exp.ExpandDirection = ExpandDirection.Down;
}
break;
}
}
private void Expander_Collapsed(object sender, RoutedEventArgs e)
{
var itemsSource = objDatagrid.ItemsSource as IEnumerable;
if (itemsSource != null)
{
foreach (var item in itemsSource)
{
var row = objDatagrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (row != null)
{
row.IsSelected = false;
}
}
}
for (var vis = sender as Visual; vis != null; vis = VisualTreeHelper.GetParent(vis) as Visual)
if (vis is DataGridRow)
{
var row = (DataGridRow)vis;
row.IsSelected = true;
row.DetailsVisibility = row.DetailsVisibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
break;
}
}
You could try RowDetailsTemplate for the dataGrid. Also set the RowDetailsVisibilityMode="VisibleWhenSelected"
<DataGrid SelectionMode="Extended" ItemsSource="{Binding}" RowDetailsVisibilityMode="VisibleWhenSelected">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="5">
<!-- Content -->
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
<DataGrid.Columns>
<!-- Columns -->
</DataGrid.Columns>
</DataGrid>
</Grid>
I am having an expander than bind in the listview.
And I have another button to collapse/ expand all expander.
In code behind, I couldn’t locate the expander by using the code: Expander exp = (Expander)listViewResult.FindResource("MyExpander");
Any idea to do so?
<ListView Name="listViewResult" Margin="0,172,-10,-491" BorderBrush="Gray" BorderThickness="1"
TextElement.FontFamily="Segoe UI" TextElement.FontSize="12"
Background="White"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler" >
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource GridViewColumnHeaderStyle}" >
……
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Name="MyExpander" IsExpanded="False">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<ItemsPresenter Margin="20,0,0,0" />
<!--<ItemsPresenter />-->
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
In order to expand/ collapse all expander, you could locate all the expanders by finding all child in the collection
Calling the method:
Collection<Expander> collection = FindVisualChild<Expander>(listViewResult);
foreach (Expander expander in collection)
{
expander.IsExpanded = true;
}
The Method:
private static Collection<T> FindVisualChild<T>(DependencyObject current) where T : DependencyObject
{
if (current == null)
{
return null;
}
var children = new Collection<T>();
FindVisualChild (current, children);
return children;
}
private static void FindVisualChild<T>(DependencyObject current, Collection<T> children) where T : DependencyObject
{
if (current != null)
{
if (current.GetType() == typeof(T))
{ children.Add((T)current); }
for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(current); i++)
{
FindVisualChild (System.Windows.Media.VisualTreeHelper.GetChild(current, i), children);
}
}
}
Use following method to find the controls within your Visual tree.
public static Visual GetDescendantByName (Visual element, string name)
{
if (element == null) return null;
if (element is FrameworkElement
&& (element as FrameworkElement).Name == name) return element;
Visual result = null;
if (element is FrameworkElement)
(element as FrameworkElement).ApplyTemplate();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
result = GetDescendantByName(visual, name);
if (result != null)
break;
}
return result;
}
where element will be your ListView and name will be name of the FrameworkElement you are looking for.
Try using x:Name property to define name for your expander and below code can help:
Expander exp = (Expander)listViewResult.FindName("MyExpander");
i have four classes
public class BoolToCol : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool v = (bool)value;
if (v == true)
{
return new SolidColorBrush(Colors.Red);
}
else
{
return new SolidColorBrush(Colors.Blue);
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class Cell : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public bool _ItsAlive;
public int _CellIndex;
public bool ItsAlive {
get {return _ItsAlive;}
set{
_ItsAlive = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("ItsAlive"));
}
}
}
public int CellIndex
{
get { return _CellIndex; }
set
{
_CellIndex = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("CellIndex"));
}
}
}
}
<Window x:Class="Pucketts_ConWaysGameOfLife.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Game of Life" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40*"/>
<ColumnDefinition Width="58*"/>
</Grid.ColumnDefinitions>
<Grid Background="Black"
Grid.Column="0">
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Width"
Value="80"/>
<Setter Property="Height"
Value="20"/>
<Setter Property="HorizontalAlignment"
Value="Left"/>
<Setter Property="VerticalAlignment"
Value="Top"/>
<Setter Property="BorderThickness"
Value="0"/>
<Setter Property="Foreground"
Value="Red"/>
<Setter Property="Background"
Value="Black"/>
<Setter Property="Grid.Row"
Value="3"/>
</Style>
<Style TargetType="Slider">
<Setter Property="TickFrequency"
Value="1"/>
<Setter Property="SmallChange"
Value="1"/>
<Setter Property="IsSnapToTickEnabled"
Value="True"/>
<Setter Property="LargeChange"
Value="10"/>
<Setter Property="Minimum"
Value="0"/>
<Setter Property="Width"
Value="80"/>
</Style>
<SolidColorBrush x:Key="foregroundBrush"
Color="Red"/>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="68"/>
<ColumnDefinition Width="76"/>
<ColumnDefinition Width="68"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Grid.Row="2"
Content="GenSlide"
Foreground="{StaticResource foregroundBrush}"/>
<Label Grid.Column="0"
Grid.Row="1"
Content="Width"
Foreground="{StaticResource foregroundBrush}"/>
<Label Grid.Column="0"
Grid.Row="0"
Content="Height"
Foreground="{StaticResource foregroundBrush}"/>
<Slider Grid.Column="1"
Grid.Row="2"
LargeChange="2"
x:Name="GenSlide"
Maximum="15"/>
<Slider Grid.Column="1"
Grid.Row="1"
x:Name="WidthSlide"
Maximum="100"/>
<Slider Grid.Column="1"
Grid.Row="0"
x:Name="HeightSlide"
Maximum="100"/>
<Button Grid.Column="2"
Click="SetGrid"
Content="Set Grid"/>
<Button Grid.Column="0"
Click="Random"
Content="Random"/>
<Label HorizontalAlignment="Left"
Grid.Column="2"
Grid.Row="2"
x:Name="GenNum"
Content="{Binding ElementName=GenSlide, Path= Value}"
Foreground="{StaticResource foregroundBrush}"/>
<Label HorizontalAlignment="Left"
Grid.Column="2"
Grid.Row="1"
x:Name="WidthNum"
Content="{Binding ElementName=WidthSlide, Path= Value}"
Foreground="{StaticResource foregroundBrush}"/>
<Label HorizontalAlignment="Left"
Grid.Column="2"
Grid.Row="0"
x:Name="HeightNum"
Content="{Binding ElementName=HeightSlide, Path= Value}"
Foreground="{StaticResource foregroundBrush}"/>
<Button Grid.Column="1"
Click="Play"
Content="Play"/>
<Button Grid.Column="1"
VerticalAlignment="Bottom"
Click="Next"
Margin="0,0,0,-10"
Content="Next"/>
</Grid>
<UniformGrid x:Name="Board"
Grid.Column="1">
</UniformGrid>
</Grid>
</Window>
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
Cell[] CellA;
int _NumOfColumns;
int CellIndex;
public event PropertyChangedEventHandler PropertyChanged;
public MainWindow()
{
this.InitializeComponent();
}
public int NumOfColumns
{
get { return _NumOfColumns; }
set
{
_NumOfColumns = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("NumOfColumns"));
}
}
}
private void Initializeboard()
{
NumOfColumns = (int) (this.HeightSlide.Value);
CellA = new Cell[NumOfColumns * (int) (this.WidthSlide.Value)];
for (int i = 0; i < this.HeightSlide.Value * this.WidthSlide.Value; i++)
{
Rectangle rec = new Rectangle();
rec.Stroke = Brushes.Green;
rec.MouseLeftButtonDown += new MouseButtonEventHandler(rec_MouseLeftButtonDown);
this.Board.Children.Add(rec);
Cell c = new Cell();
c.CellIndex = i;
Binding newB = new Binding("ItsAlive");
newB.Source = c;
newB.Converter = new BoolToCol();
rec.SetBinding(Rectangle.FillProperty, newB);
CellA[i] = c;
}
}
public void rec_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
foreach (UIElement item in this.Board.Children)
{
if (item.IsMouseOver)
{
Cell c = (item as Rectangle).GetBindingExpression(Rectangle.FillProperty).ResolvedSource as Cell;
c.ItsAlive = !c.ItsAlive;
//c.CellIndex = this.Board.Children.IndexOf((Rectangle) sender);
CellIndex = c.CellIndex;
Console.WriteLine(CellIndex + " " + CellA[CellIndex].ItsAlive);
}
}
}
public List<Cell> CheckNeighbours(Cell c)
{
//NumOfColumns
//c.CellIndex
// 3 secations the ones above below and next to
List<Cell> NebourCell = new List<Cell> { };
NebourCell.Clear();
for (int i = -1; i < 2; i++)
{
try
{
NebourCell.Add(CellA[c.CellIndex - NumOfColumns - i]);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Ignore");
}
}
for (int i = -1; i < 2; i += 2)
{
try
{
NebourCell.Add(CellA[c.CellIndex -i]);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Ignore for middle index out of bounds");
}
}
for (int i = -1; i < 2; i++)
{
try
{
NebourCell.Add(CellA[c.CellIndex + NumOfColumns - i]);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Ignore");
}
}
return NebourCell;
}
private void SetGrid(object sender, RoutedEventArgs e)
{
this.Board.Children.Clear();
this.Initializeboard();
}
private void Random(object sender, RoutedEventArgs e)
{
Random rand = new Random();
foreach (UIElement item in this.Board.Children)
{
Cell c = (item as Rectangle).GetBindingExpression(Rectangle.FillProperty).ResolvedSource as Cell;
if (rand.Next(0, 2) == 1)
{
c.ItsAlive = !c.ItsAlive;
}
}
}
private void Play(object sender, RoutedEventArgs e)
{
foreach (UIElement item in this.Board.Children)
{
}
}
private void Next(object sender, RoutedEventArgs e)
{
int Alive = 0;
foreach (Cell AllCell in CellA)
{
List<Cell> NebourCells = CheckNeighbours(CellA[AllCell.CellIndex]);
foreach ( Cell AllBebourCells in NebourCells)
{
Console.WriteLine(CellA[AllBebourCells.CellIndex].ItsAlive);
if (CellA[AllBebourCells.CellIndex].ItsAlive)
Alive++;
}
Console.WriteLine(Alive);
if (Alive < 2 || Alive > 3)
{
Console.WriteLine("It dies");
CellA[CellIndex].ItsAlive = false;
}
if (Alive == 2 || Alive == 3)
{
Console.WriteLine("Its lives on");
}
if (Alive == 3)
{
Console.WriteLine("Its alive");
CellA[CellIndex].ItsAlive = true;
}
//foreach (Cell item in NebourCell)
//{
// Rectangle ind = this.Board.Children[item.CellIndex] as Rectangle;
// ind.Fill = new SolidColorBrush(Colors.LightCyan);
//}
}
}
}
My problem i believe is in the Main Window cs and when you put three squares in a row and you go to next gen it is suppose to go vertical but mine just deletes the farthest one to the right i have been working on this for a while now i have been doing a lot of Debugging i have also debugged with break points i think it also is in the Next Button event Method but i could not find the problem and was wondering if anyone could assist me.
You have two problems with your Next method that I can see. First, you are not resetting your 'Alive' value between each cell that you process. So if the first cell you process has two alive neighbors, you Alive variable gets set to 2, and then if the next cell also has two alive neighbors, Alive is now set to 4!
Secondly, you are currently modifying the cells in place. This will lead to incorrect results, as if a certain cell dies, it will no longer be counted as alive for the processing of the cells next to it when it should be. You will need to create a temporary cell array that is a copy of CellA, and use the alive status of the cell in CellA but modify the status in the copy. Then at the end, set CellA to the copy.
Your new function should flow like this, in pseudocode
private void Next(object sender, RoutedEventArgs e)
{
Cell[] copy = copy of CellA
Loop over cells in copy
{
Alive = number of living neighbors of cell in CellA array
// apply Life logic here
copy[cell index].IsAlive = new status based on logic
}
CellA = copy
}
When you evolve your population (your CellA variable), you have to work on a copy of it. That is, you generate the new generation of cells into a newly allocated variable that you then assign to CellA only when you are done.