I am trying to programatically select an entire column in a WPF DataGrid. My code seems to work but it is REALLY slow! I'm guessing it is because it is continually having to call ScrollIntoView. Can someone help me with a solution to speed it up or an alternative to select the entire column?
public static void SelectColumn(DataGrid grid, int column)
{
for (int i = 0; i < grid.Items.Count; i++)
{
// Select each cell in this column
var cell = DataGridHelper.GetCell(grid, i, column);
if (cell != null)
{
cell.IsSelected = true;
}
}
DataGridHelper.GetCell(grid, 0, column).Focus();
}
public static DataGridCell GetCell(DataGrid grid, int row, int column)
{
DataGridRow rowContainer = GetRow(grid, row);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = TreeHelper.GetVisualChild<DataGridCellsPresenter>(rowContainer);
if (presenter == null)
{
// may be virtualized, bring into view and try again
grid.ScrollIntoView(rowContainer, grid.Columns[column]);
presenter = TreeHelper.GetVisualChild<DataGridCellsPresenter>(rowContainer);
}
if (presenter != null)
{
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
// may be virtualized, bring into view and try again
grid.ScrollIntoView(rowContainer, grid.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
}
return null;
}
public static DataGridRow GetRow(DataGrid grid, int index)
{
DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// may be virtualized, bring into view and try again
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
UPDATE:
I'm trying out the solution suggested by #ianschol. Here is what I have (I bind in code behind b/c I don't know how many columns I need until runtime):
for (int i = 0; i < this.CurrentData.Data[0].Length; i++)
{
TheGrid.Columns.Add(
new DataGridTextColumn
{
Header = (this.CurrentData.Rank > 1) ? string.Format(this.culture, headerFormatString, i + 1) : string.Empty,
Binding = new Binding(string.Format("[{0}].DataValue", i)) { ValidatesOnDataErrors = true, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged },
Width = DataGridLength.Auto,
ElementStyle = new Style
{
TargetType = typeof(TextBlock),
Triggers = { this.errorTrigger }
},
EditingElementStyle = new Style
{
TargetType = typeof(TextBox),
Triggers = { this.errorTrigger }
},
CellStyle = new Style
{
TargetType = typeof(DataGridCell),
Setters =
{
new Setter
{
Property = DataGridCell.IsSelectedProperty,
Value = new Binding(string.Format("[{0}].IsSelected", i)) { Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged },
}
},
}
});
}
and my IsSelected property:
private bool isSelected = false;
public bool IsSelected
{
get
{
return this.isSelected;
}
set
{
this.isSelected = value;
OnPropertyChanged("IsSelected");
}
}
And the new SelectColumn code:
public static void SelectColumn(DataGrid grid, int column)
{
for (int i = 0; i < grid.Items.Count; i++)
{
// Select each cell in this column
((DataItem[])(grid.Items[i]))[column].IsSelected = true;
}
}
The problem is that if I update the IsSelected property in code, it updates the GUI (kinda, its quirky) but not vice versa. I.e. if I select a cell/row in the GUI, it doesn't call the property setter in the code. As you can see the binding is TwoWay so I'm not sure the issue.
Another UPDATE: The issue definitely seems to be with virtualization. If i turn off virtualization (VirtualizingStackPanel.IsVirtualizing="False" ) it works fine.
A more effective approach would probably be to have IsSelected properties on the DataSource's class, such that each column has a corresponding "IsSelected" property.
public class MyData : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
Notify("Name");
}
}
private bool nameSelected = false;
public bool NameSelected
{
get { return nameSelected; }
set
{
nameSelected = value;
Notify("NameSelected");
}
}
//... etc ...
}
Next, you can alter the CellStyle for each Column to bind the cells' IsSelected property to the related IsSelected property on the class.
<DataGrid ItemsSource="{Binding Users}" AutoGenerateColumns="False" HorizontalAlignment="Left" Name="scratchGrid" CanUserAddRows="False"
VerticalScrollBarVisibility="Auto" SelectionUnit="Cell">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="User Name" Width="200">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsSelected" Value="{Binding NameSelected}" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Age}" Header="User Age" Width="80">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsSelected" Value="{Binding AgeSelected}" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Finally, implement your select-all code like so (this does select-all on Age, you may want to make a more generic/elegant implementation ;) ) :
foreach (MyData user in Users)
{
user.AgeSelected = true;
}
You'll have to take care to make sure all your NotifyPropertyChanged behavior is lined up, since you're expecting the grid to recognize that properties inside its bound collection are being updated.
Related
I have created simple mechanism for data table xaml would looks simply:
<DataGrid ItemsSource="{Binding CurrentsFlagValuesView}" AutoGenerateColumns="True" />
And MVVM code behind is based on data tables, and as well fairly simple:
private void GenerateDataView()
{
CurrentsFlagValuesView = new DataTable();
CurrentsFlagValuesView.Columns.Add("Bits");
var bitLength = 0;
foreach (CurrentsFlagAnalysis flag in CurrentsFlagValues)
{
CurrentsFlagValuesView.Columns.Add(flag.DailyCurrentsTimestampInterval.ToString("yyyy-MM-dd"));
bitLength = flag.CurrentFlagsLength;
}
for (var bit = 0; bit < bitLength; bit++)
{
List<CurrentFlagEventEnum> flags = CurrentsFlagValues
.Select(value => value.CurrentFlags.ElementAt(bit))
.Select(value => value ? (CurrentFlagEventEnum)bit + 1 : CurrentFlagEventEnum.None)
.ToList();
var dataRowValues = new List<object> { bit };
dataRowValues.AddRange(flags.Cast<object>());
CurrentsFlagValuesView.Rows.Add(dataRowValues.ToArray());
}
}
But I came upon a problem, or two I want to get data of the cell when I click the cell, like Column title, and value of the cell. I managed to do this without MVVM like:
void EditingDataGrid_CurrentCellChanged(object sender, EventArgs e)
{
DataGridCell Cell = EditingDataGrid.GetCurrentDataGridCell();
var Position = Cell.PointToScreen(new Point(0, 0));
TextBlock text = (TextBlock)Cell.Content;
MessageBox.Show("Value=" + text.Text, "Position" );
}
public static DataGridCell GetCurrentDataGridCell(this DataGrid dataGrid)
{
DataGridCellInfo cellInfo = dataGrid.CurrentCell;
if (cellInfo.IsValid == false)
{
return null;
}
var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent == null)
{
return null;
}
return cellContent.Parent as DataGridCell;
}
But now I want to remodel that to that pattern, but I do not know how. Any Ideas how to bind command to that?
You could bind the CurrentCell property of the DataGrid to a DataGridCellInfo (not DataGridCell) source property provided that you set the Mode of the Binding two TwoWay:
<DataGrid ItemsSource="{Binding CurrentsFlagValuesView}"
CurrentCell="{Binding CurrentCell, Mode=TwoWay}"
AutoGenerateColumns="True" />
Then the source property of the view model will be set whenever you select a cell in the view and you could simply move your current logic to the view model:
private DataGridCellInfo _currentCell;
public DataGridCellInfo CurrentCell
{
get { return _currentCell; }
set { _currentCell = value; OnCurrentCellChanged(); }
}
void OnCurrentCellChanged()
{
DataGridCell Cell = GetCurrentDataGridCell(_currentCell);
var Position = Cell.PointToScreen(new Point(0, 0));
TextBlock text = (TextBlock)Cell.Content;
MessageBox.Show("Value=" + text.Text, "Position");
}
public static DataGridCell GetCurrentDataGridCell(DataGridCellInfo cellInfo)
{
if (cellInfo == null || cellInfo.IsValid == false)
{
return null;
}
var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent == null)
{
return null;
}
return cellContent.Parent as DataGridCell;
}
You could also wrap this functionality in a behaviour that sets the source property of the view model to the actuall cell value:
https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF
https://blog.magnusmontin.net/2014/01/30/wpf-using-behaviours-to-bind-to-readonly-properties-in-mvvm/
You can simply bind the current cell property in the view model and you will have the current cell with you all the time:
<DataGrid AutoGenerateColumns="True"
SelectionUnit="Cell"
CanUserDeleteRows="True"
ItemsSource="{Binding Results}"
CurrentCell="{Binding CellInfo}"
SelectionMode="Single">
In the view model:
private DataGridCell cellInfo;
public DataGridCell CellInfo
{
get { return cellInfo; }
}
I have a MainWindow. It has a stackpanel myStack and some other things.
In stackPanel, there is a usercontrol (TaskGrid(_TG)) added programmatically.
In this UserControl, there is a DataGrid(dgEmployee), which have 4 template columns. the last column contains a button.
I am trying to assign the button click event from the mainwindow constructor and handle the event here.
Here are the codes:
in MainWindow.xaml
<Grid Grid.Row="2">
<StackPanel Name="myStack"/>
</Grid>
in MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
_TG = new TaskGrid();
_TD = new _1.TaskDetails();
_TM = new _1.TaskMaster();
myStack.Children.Add(_TG);
_AUC = ActiveUserControl.Grid;
foreach (object child in myStack.Children)
{
string childname = "";
if (child is FrameworkElement)
{
childname = (child as FrameworkElement).Name;
if (childname == "TaskGrid")
{
Grid dg = ((Grid)((UserControl)child).Content);
foreach (var item in dg.Children)
{
DataGridColumn b = ((DataGrid)item).Columns[3] as DataGridColumn;
}
}
}
}
}
And in TaskGrid.xaml, the only template column is given here
<DataGridTemplateColumn Width="30">
<DataGridTemplateColumn.CellTemplate>
<ItemContainerTemplate>
<Button Name="btnMaster" Background="Transparent">
<Button.Template>
<ControlTemplate>
<Image Source="ArrowRight.png"/>
</ControlTemplate>
</Button.Template>
</Button>
</ItemContainerTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I have to assign the click event like
button.click += new RoutedEvent(button_click);
And later use button_click event in the MainWindow.xaml.cs
Wait until the UserControl has been loaded. You could then get a reference to the DataGrid using the following helper method that searches for an element of a specific type recursively in the visual tree.
private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null)
return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
The same way you can get a reference to a specific cell:
public static DataGridCell GetCell(DataGrid dataGrid, DataGridRow rowContainer, int column)
{
if (rowContainer != null)
{
System.Windows.Controls.Primitives.DataGridCellsPresenter presenter =
GetChildOfType<System.Windows.Controls.Primitives.DataGridCellsPresenter>(rowContainer);
if (presenter != null)
return presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
}
return null;
}
Please refer to the following blog post for more information about this: https://blog.magnusmontin.net/2013/11/08/how-to-programmatically-select-and-focus-a-row-or-cell-in-a-datagrid-in-wpf/
Below is a full example for you. Note that the DataGrid may contain several rows and some of the rows may have been virtualized away. You will find more information about this on the link above.
public MainWindow()
{
InitializeComponent();
_TG = new TaskGrid();
_TD = new _1.TaskDetails();
_TM = new _1.TaskMaster();
myStack.Children.Add(_TG);
_AUC = ActiveUserControl.Grid;
_TG.Loaded += (s, e) =>
{
DataGrid dataGrid = GetChildOfType<DataGrid>(_TG);
if (dataGrid != null)
{
foreach (var item in dataGrid.Items)
{
DataGridRow dgr = dataGrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (dgr != null)
{
DataGridCell cell = GetCell(dataGrid, dgr, 3); //<-- column index
if (cell != null)
{
Button button = GetChildOfType<Button>(cell);
if (button != null)
{
button.Click += new RoutedEvent(button_click);
}
}
}
}
}
};
}
Consider the following DataGrid having three columns:
When ever the age is -1 the corresponding cell gets disabled.
Ideally it shall not be possbile for the user to change the disabled cell value. However consider the user is in row 1 and the keyboard focus is in the corresponding cell of column Age, and presses enter, now the user types any number and the disabled cell get that value! Is this a desired behaviour? How can I avoid this behaviour?
To replicate issue:
Select cell in row 1 of Age column
Press enter
Type a number
Reproducible code:
XAML:
<Window x:Class="wpf_behaviour.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataGridDetailsSample" Height="200" Width="400">
<Grid Margin="10">
<DataGrid Name="dgUsers" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Id}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Age" Binding="{Binding Age}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Age}" Value="-1">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="ToolTip" Value="This filed is diabled."/>
<Setter Property="Background" Value="LightGray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Correspoinding cs:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
namespace wpf_behaviour
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<User> users = new List<User>();
users.Add(new User() { Id = 1, Name = "Kumar", Age = 10 });
users.Add(new User() { Id = 2, Name = "Sameer", Age = -1 });
users.Add(new User() { Id = 3, Name = "Danny", Age= 16 });
dgUsers.ItemsSource = users;
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}
}
I got the solution (added a PreviewKeyDown event handler) and here it is and I would like to know any better solution as well:
private void DataGridCell_PreviewKeyDown(object sender, KeyEventArgs e)
{
try
{
DataGridCell cl = (DataGridCell)sender;
//Get the Cell's parent row
//using System.Windows.Media; for VisaualTreeHelper
var DataGridRowParent = VisualTreeHelper.GetParent(cl);
while (DataGridRowParent != null && DataGridRowParent.GetType() != typeof(DataGridRow))
{
DataGridRowParent = VisualTreeHelper.GetParent(DataGridRowParent);
}
//Get the Row's parent DataGrid
var DataGridParent = VisualTreeHelper.GetParent(DataGridRowParent);
while (DataGridParent != null && DataGridParent.GetType() != typeof(DataGrid))
{
DataGridParent = VisualTreeHelper.GetParent(DataGridParent);
}
DataGrid dp = DataGridParent as DataGrid;
//Get the CurrentCell value of DataGrid
DataGridCellInfo cli = dp.CurrentCell;
var CellContent = cli.Column.GetCellContent(cli.Item);
if (CellContent != null)
{
//Get DataGridCell of DataGridCellInfo
DataGridCell dgc = (DataGridCell)CellContent.Parent;
if (dgc.IsEnabled == false)
{
//If the key pressed is Enter or Tab allow
if (e.Key == Key.Enter || e.Key == Key.Tab)
{
e.Handled = false;
return;
}
//If any other key is pressed don't allow.
e.Handled = true;
return;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
I'm not sure why this happaning but you can catch the Enter Event and cancel the Edit:
C#
private void MyDataGrid_OnKeyDown(object sender, KeyEventArgs e)
{
var dg = sender as DataGrid;
// alter this condition for whatever valid keys you want - avoid arrows/tab, etc.
if (dg != null && !dg.IsReadOnly && e.Key == Key.Enter)
{
dg.CancelEdit();
e.Handled = true;
}
}
XAML
<DataGrid Grid.Column="1" Name="dgUsers" AutoGenerateColumns="False" PreviewKeyDown="MyDataGrid_OnKeyDown">
I want to hide a grid view column when a menu-item is clicked.
Xaml:
<MenuItem Header="View">
<MenuItem Header="Columns" Name="menuView" ItemsSource="{Binding Path= MyMenuItems}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="IsChecked" Value="{Binding IsChecked,Mode=TwoWay}"/>
<Setter Property="IsCheckable" Value="{Binding IsCheckable}"/>
<Setter Property="Icon" Value= "{Binding ImageIcon}"/>
<Setter Property="IsEnabled" Value= "{Binding Path =IsEnabled}"/>
<Setter Property="ItemsSource" Value="{Binding Path= MyMenuItems}"/>
<Setter Property= "Command" Value= "{Binding DataContext.CheckedViewMenuItemsCmd, RelativeSource ={RelativeSource AncestorType={x:Type MenuItem}}}"/>
<Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="StaysOpenOnClick" Value="{Binding StaysOpenOnClick}"/>
</Style> </MenuItem.ItemContainerStyle>
</MenuItem>
<ListView Name="MyListView" Grid.Row="1" SelectedItem ="{Binding SelectedFeature}" ItemsSource="{Binding Path= MyListItems}">
<ListView.View>
<GridView util:GridViewColumnClass.HeaderTextMember="HeaderText"
util:GridViewColumnClass.DisplayMemberMember="DisplayMember"
util:GridViewColumnClass.ColumnsSource=" {Binding Columns}"/>
</ListView.View>
The menu items header is the same as Grid view column header . When a menu item is checked or unchecked, I would like the grid view column to be shown or hidden.
I do have a GidViewColumnVisibilityManager similar to this one here .
WPF: How to hide GridViewColumn using XAML?
ViewModel:
public MyViewModel()
{
MyListItems = SomeClass.instance.messages;
_MenuItems = new ObservableCollection<MenuClass>();
//populates the view menu
PopulateViewMenu();
this.Columns = new ObservableCollection<ColumnDescriptor>
{
new ColumnDescriptor{ Width = 40, HeaderText ="column1", DisplayMember= "column1"},
new ColumnDescriptor{ Width = 40, HeaderText="column2" , DisplayMember= "column2"},
new ColumnDescriptor{ Width = 70, HeaderText="column3" , DisplayMember="column3"},
};
//event to command
CheckedViewMenuItemsCmd = new RelayCommand<MenuClass>(CheckedViewMenuItems);
}
public ObservableCollection<ColumnDescriptor> Columns { get; private set; }
private ICommand _addColumnCommand;
public ICommand AddColumnCommand
{
get
{
if (_addColumnCommand == null)
{
_addColumnCommand = new RelayCommand<string>(
s =>
{
this.Columns.Add(new ColumnDescriptor { HeaderText = s, DisplayMember = s });
});
}
return _addColumnCommand;
}
}
private ICommand _removeColumnCommand;
public ICommand RemoveColumnCommand
{
get
{
if (_removeColumnCommand == null)
{
_removeColumnCommand = new RelayCommand<string>(
s =>
{
this.Columns.Remove(this.Columns.FirstOrDefault(d => d.DisplayMember == s));
});
}
return _removeColumnCommand;
}
}
private void CheckedViewMenuItems(MenuClass m)
{
try
{
bool IsChecked = m.IsChecked;
if (IsChecked)
{
ColumnDescriptor cl1 = new ColumnDescriptor{ Width = 40, HeaderText =m.Header, DisplayMember= "Revision"};
int idx = Convert.ToInt32(m.Tag);
int insertidx = Math.Min(idx, this.Columns.Count);
this.Columns.Insert(insertidx, cl1);
}
else
{
foreach (var item in this.Columns)
{
if (item.HeaderText == m.Header)
{
// item.DisplayMember = "";
this.Columns.Remove(item);
break;
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(String.Format("{0}{1}{2}{1}{3}", ex.GetType().ToString(), Environment.NewLine, ex.Message, ex.StackTrace));
}
}
I am a bit confused about how to use the booleon to visible converter and implement the functionality. Your help is appreciated. Please ask me questions if you have any. Thank you folks.
I tried insert and remove instead of show and hide, the Remove works like a charm but the insert needs a display member binding to bind to the collection every time which is obvious. I tried for one column, it works fine, i need it to work for all. Any thoughts?
I found a workaround. I have a new function GetdisplayMember which returns a string, depending on which menuitem was clicked. Here is workaround. Works nicely. Cheers!
private string GetDisplayMember(int tag)
{
string displayMember = string.Empty;
if (tag != null)
{
switch (tag)
{
case 0:
displayMember = "Revision";
break;
case 1:
displayMember = "Class";
break;
case 2:
displayMember = "Errordate";
break;
}
}
return displayMember;
}
private void CheckedViewMenuItems(MenuClass m)
{
try
{
if (m!=null)
{
bool IsChecked = m.IsChecked;
if (IsChecked)
{
ColumnDescriptor cl1 =new ColumnDescriptor
{
HeaderText =m.Header,
DisplayMember= GetDisplayMember(m.Tag)
};
int idx = Convert.ToInt32(m.Tag);
int insertidx = Math.Min(idx,
this.Columns.Count);
this.Columns.Insert(insertidx, cl1);
}
else
{
foreach (var item in this.Columns)
{
if (item.HeaderText == m.Header)
{
// item.DisplayMember = "";
this.Columns.Remove(item);
break;
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(String.Format("{0}{1}{2}{1}{3}", ex.GetType().ToString(), Environment.NewLine, ex.Message, ex.StackTrace));
ErrorLogger.Log(LogLevel.Error, ex.ToString());
}
i've defined an initial Table with three rows and 9 Column in Datagrid. right now button should be visible only if i select a row and then press another button that i defined in my Ribbon-Tab after that my Button will be Visible. sofar everything works well, but the Problem is after saving my Table, closing it and open the Table again the button is not there anymore. I set the Visibility based on if the DataGridCell.IsSelected, also a BooleanToVisibilityConverter to convert the boolean value to a Visibility one.
can anyone help!
XAML:
<DataGrid.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</DataGrid.Resources>
<DataGridTemplateColumn x:Name="subgraphtyp" Header="H." Width="50">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="btnTable" Visibility="{Binding Path=Hinterlegung, Converter=
{StaticResource BoolToVisConverter}}" Height="20" Width="25"
Click="Button_Table_Click">
<Image Height="16" Source="Subgraph.png" Stretch="Fill" Width="16"/>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
C#:
public bool Hinterlegung { get; set; }
private void Button_StartTableModus(object sender, RoutedEventArgs e)
{
if (DataGrid1.SelectedItem != null && tabItem1.IsSelected)
{
TableDataRowStringItem item = (TableDataRowStringItem)DataGrid1.CurrentItem;
string wert = item.ObjectType;
string rowName = item.Name;
if (wert == "Function" || wert == "Process")
{
item.Hinterlegung = true;
if (!tabControl.Items.Contains(tabItem2))
{
tabControl.Items.Add(tabItem2);
tabItem2.Focus();
tabItem2.IsSelected = true;
tabItem2.Header = rowName;
TableTab.Visibility = Visibility.Visible;
openTabs++;
DataGrid2.IsReadOnly = false;
starting_Table_Mod_at_start2V();
}
}
}
}
//this my initial Table
private ObservableCollection<TableDataRowStringItem> tableobject = new
ObservableCollection<TableDataRowStringItem>();
private void starting_Table_Mod_at_start2V()
{
List<TableDataRowStringItem> rowstringList = new List<TableDataRowStringItem>();
TableDataRowStringItem item = new TableDataRowStringItem();
item.RowNumber = 1; item.saveFlag = true; item.ObjectType = "E"; item.Name = "E";
item.PredecessorRowNumber = "0"; rowstringList.Add(item);
item = new TableDataRowStringItem();
item.RowNumber = 2; item.ObjectType = "Function"; item.Name = "Function";
item.PredecessorRowNumber = "1"; rowstringList.Add(item);
item = new TableDataRowStringItem();
item.RowNumber = 3; item.ObjectType = "E"; item.Name = "E";
item.PredecessorRowNumber = "2"; rowstringList.Add(item);
for (int i = 0; i < rowstringList.Count; i++)
{
tableobject.Add(rowstringList[i]);
}
DataGrid2.ItemsSource = tableobject;
}
Your button's visibility is bound to your Hinterlegung variable which has a default value of false. So as best as I can tell, you change it to true in this method - Button_StartTableModus. But, when you reinitialize, the value reverts to false, so you need to set it to true.