For certain reasons I need to add elements to my form with codebehind.
There is a main panel. By clicking a button - I am adding some content to it as below:
private void AddCodeKlantFieldButtonOnClick(object sender, RoutedEventArgs routedEventArgs)
{
var button = sender as Button;
if (button != null)
{
var panel = (StackPanel)button.Tag;
var stackPanel = new StackPanel { Orientation = Orientation.Horizontal };
AddLabel(stackPanel, "Klant van:", 135);
opzoekenLandVan = new OpzoekenCode(OpzoekenCodeTable.Klant, "");
opzoekenLandTot = new OpzoekenCode(OpzoekenCodeTable.Klant, "");
stackPanel.Children.Add(opzoekenLandVan);
AddLabel(stackPanel, "tot en met:", 100);
stackPanel.Children.Add(opzoekenLandTot);
var count = panel.Children.Count;
panel.Children.Insert(8, stackPanel);
}
}
That works fine! But if I add too much items, there is not enough space on the form - so a scrollviewer would be needed. I am quite new and can not figure out how to handle it. I tried this:
var scrollViewer = new ScrollViewer();
scrollViewer.Content = panel;
scrollViewer.Visibility = Visibility.Visible;
scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollViewer.CanContentScroll = true;
But the scrollbar does not appear. If I try to add it to the form
panel.Children.Add(scrollViewer);
I am getting an error:
An exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll but was not handled in user code
Additional information: Logical tree depth exceeded while traversing the tree. This could indicate a cycle in the tree.
In the code below, you did not add the scrollViewer to the visual tree so it's not displaying
var scrollViewer = new ScrollViewer();
scrollViewer.Content = panel; //this does not add to visualtree
scrollViewer.Visibility = Visibility.Visible;
scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollViewer.CanContentScroll = true;
one of the lines above is
scrollViewer.Content = panel;
so you will get an error on trying to add it to panel's children.
panel.Children.Add(scrollViewer);
You see the circular issue? First line, you put panel inside scrollViewer, next line you put the same scrollViewer in the panel.
Try commenting out scrollViewer.Content = panel but leave panel.Children.Add(scrollViwer) in, this should add the scrollViewer to the visualtree. But it'll probably be invisible due to 0 width or height since it has no content and is in a stackpanel.
Related
When my datagrid loads up I am able to get the focus of the first row by providing selected index=0 in the xaml but when I perform searching the focus gets lost so I want focus to be retain at the first row no matter I do sorting and searching on the datagrid.
Here is my code that searches particular thing in the datagrid.
private void TextBox_TextChanged(object sender, RoutedEventArgs e)
{
TextBox STB = (TextBox)sender;
this.SearchValue = STB.Text;
//ContentPresenter CP = (ContentPresenter)STB.TemplatedParent;
//DataGridColumnHeader DGCH = (DataGridColumnHeader)CP.TemplatedParent;
//DataGridColumn DGC = DGCH.Column;
//this.ColumnName = DGC.Header.ToString();
this.Datalist.Filter = this.CustomeFilter;
DataGrid dataGrid = this as DataGrid;
dataGrid.CurrentCell = new DataGridCellInfo(
dataGrid.Items[0], dataGrid.Columns[0]);
dataGrid.BeginEdit();
}
In above code I am trying to get the focus of the current cell but all in vain.
private bool CustomeFilter(object item)
{
SymbolData ltpObj = item as SymbolData;
//WpfApplication1.Model.LtpMessage ltpObj = item as WpfApplication1.Model.LtpMessage;
string values = (string)ltpObj.Symbol.ToString();
values = values.ToUpper();
//return values.StartsWith(this.SearchValue.ToString().ToUpper());
if (values.StartsWith(this.SearchValue.ToString().ToUpper()))
{ return true; }
else
return false;
}
You should read this:
How to programmatically select and focus a row or cell in a DataGrid in WPF: https://blog.magnusmontin.net/2013/11/08/how-to-programmatically-select-and-focus-a-row-or-cell-in-a-datagrid-in-wpf/
You can select and focus a row or cell of a DataGrid programmatically and get the same behaviour as when using the mouse by accessing the visual user interface elements of the DataGrid control and calling the UIElement.Focus() method on a particular DataGridCell object as described in the blog post above. There are code samples included.
You cannot simply set the SelectedItem or SelectedIndex property of the DataGrid to focus the row or cell though.
I have a datagrid, this is loaded by a xml file... no problem.
I need allow scroll when user drag over all datagrid, or select row and drag up or down to scroll content.
I have de scrollbar but, this app is for touch screen so is more easy drag on datagrid to scroll.
Thanks...
This should do the trick. Handle the Drag event of datagrid and scroll the datagrid programmatically.
// hook up the row events during the loading row event for the datagrid
private void MyDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.DragOver += new DragEventHandler(MyRow_DragOver);
e.Row.Drop += new DragEventHandler(MyRow_Drop);
}
private void MyRow_DragOver(object sender, DragEventArgs e)
{
DataGridRow r = (DataGridRow)sender;
MyDataGrid.SelectedItem = r.Item;
// Scroll while dragging...
DependencyObject d = MyDataGrid;
while (!(d is ScrollViewer))
{
d = VisualTreeHelper.GetChild(d, 0);
}
ScrollViewer scroll = d as ScrollViewer;
Point position = MyDataGrid.PointToScreen(Mouse.GetPosition(r));
// create this textbox to test in real time the value of gridOrigin
textBox1.Text = position.ToString();
double topMargin = scroll.ActualHeight * .15;
double bottomMargin = scroll.ActualHeight * .80;
if (position.Y * -1 < topMargin)
scroll.LineUp(); // <-- needs a mechanism to control the speed of the scroll.
if (position.Y * -1 > bottomMargin)
scroll.LineDown(); // <-- needs a mechanism to control the speed of the scroll.
}
I have a ComboBox (ToolStripCombobox, to be more precise) filled with items of type KeyValuePair<Int32, FontFamily>. I managed to have the Items beeing painted manually by using the DrawItem event. So every Item is painted with the FontFamily of the corresponding KeyValuePair. This works fine for the DropDownList, but when I select an Item out of the List and the list closes, the text in the ComboBox says something like "[21, [FontFamily: Name=Arial]]" which is most likely the result of SelectedItem.ToString().
Any ideas how to solve this problem?
here is the code of my custom DrawItem method:
private void fontComboBoxDrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
if ((e.State & DrawItemState.Focus) != 0)
{
e.DrawFocusRectangle();
}
Brush objBrush = null;
var itemToDraw = this.fontComboBox.Items[e.Index];
KeyValuePair<Int32, FontFamily> windowsFontItem = (KeyValuePair<Int32, FontFamily>)itemToDraw;
objBrush = new SolidBrush(e.ForeColor);
e.Graphics.DrawString(windowsFontItem.Value.Name, new Font(windowsFontItem.Value, e.Font.Size), objBrush, e.Bounds);
if (objBrush != null)
{
objBrush.Dispose();
}
objBrush = null;
}
Update:
It works as expected, when I set the DropDownStyle of the ComboBox to ComboBoxStyle.DropDownList
But I´d rather use ComboBoxStyle.DropDown, so you can edit the Text to search for Fonts.
I am having some trouble animating the items in my ListBox. Animations on the OpacityProperty work great but when i try to animate the position of my ListBoxItem it simply does not move an inch (No exceptions are thrown, not even a log message indicating error).
Here is the code i am using:
private void deletAnimation()
{
Todo todoToDelete = App.ViewModel.Todos[1];
Storyboard storyboard = new Storyboard();
DoubleAnimation alphaAnim = new DoubleAnimation();
alphaAnim.From = 1;
alphaAnim.To = 0;
alphaAnim.Duration = new Duration(TimeSpan.FromMilliseconds(500));
ListBoxItem target = TodoList.ItemContainerGenerator.ContainerFromItem(todoToDelete) as ListBoxItem;
Storyboard.SetTarget(alphaAnim, target);
Storyboard.SetTargetProperty(alphaAnim, new PropertyPath(UIElement.OpacityProperty));
storyboard.Children.Add(alphaAnim);
for (int i = App.ViewModel.Todos.IndexOf(todoToDelete) + 1; i < App.ViewModel.Todos.Count; i++)
{
Todo todo = App.ViewModel.Todos[i];
target = TodoList.ItemContainerGenerator.ContainerFromItem(todo) as ListBoxItem;
DoubleAnimation translateAnim = new DoubleAnimation();
translateAnim.From = target.RenderTransformOrigin.Y;
translateAnim.To = target.RenderTransformOrigin.Y - target.ActualHeight;
translateAnim.Duration = new Duration(TimeSpan.FromMilliseconds(500));
translateAnim.BeginTime = TimeSpan.FromMilliseconds(500);
Storyboard.SetTarget(translateAnim, target);
Storyboard.SetTargetProperty(translateAnim, new PropertyPath(TranslateTransform.YProperty));
storyboard.Children.Add(translateAnim);
}
storyboard.Begin();
}
Some things i have noticed while debugging:
The RenderTransformOrigin.Y property is always 0 no matter which ListBoxItem is referenced.
The Height property is NaN though the ActualHeight property is 67
The parent property of the ListBoxItem is null
These two things make me wonder if i am given a reference to a ListBoxItem that is not rendered of the screen? But as the Opacity animation works perfectly and all of my list is visible(only contains 3 items at the moment) i do not see how this could be the case.
I have also tried using a PointAnimation and animating the RenderTransformOrigin property directly but this gave the same result (nothing that is).
Any help is appreciated, thanks!
Please check out this link:
http://blogs.msdn.com/b/jasongin/archive/2011/01/03/wp7-reorderlistbox-improvements-rearrange-animations-and-more.aspx
Someone has created a class that you can easily incorporate into your app. This has animations for adding/removing items from your list.
This should save you a lot of time and frustration.
I have a WPF Datagrid and I'm implementing drag and drop functionality.
The datagrid has a list of "files" and the user can drag them and copy the file to the desktop.
This is done like this:
string[] files = new String[myDataGrid.SelectedItems.Count];
int ix = 0;
foreach (object nextSel in myDataGrid.SelectedItems)
{
files[ix] = ((Song)nextSel).FileLocation;
++ix;
}
string dataFormat = DataFormats.FileDrop;
DataObject dataObject = new DataObject(dataFormat, files);
DragDrop.DoDragDrop(this.myDataGrid, dataObject, DragDropEffects.Copy);
I have two questions:
1. When I want to drag multiple items- this is a problem because after I select a couple and start clicking on one to start dragging- only that gets selected and the other items get deselected. I tried the solution that is given here but for some reason it doesn't work.
2. I want to remove the dragged item from the datagrid after it is copied. The problem is that I don't know how to check if the file was copied or whether the user just dragged it on the screen without copying it.
I hope you can help me solve these problems.
Thanks!
I think this i what you are looking for:
add this code to the DataGrid__PreviewMouseLeftButtonDown event handler:
private void DataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.startingPosition = e.GetPosition(null);
DependencyObject dep = (DependencyObject)e.OriginalSource;
// iteratively traverse the visual tree until get a row or null
while ((dep != null) && !(dep is DataGridRow))
{
dep = VisualTreeHelper.GetParent(dep);
}
//if this is a row (item)
if (dep is DataGridRow)
{
//if the pointed item is already selected do not reselect it, so the previous multi-selection will remain
if (songListDB.SelectedItems.Contains((dep as DataGridRow).Item))
{
// now the drag will drag all selected files
e.Handled = true;
}
}
}
and now the draging won't change you selection.
Have a good luck!
I used that article to write my answer
Improved on finding the row.
Also selecting the clicked row when not dragging is added.
This now behaves exactly as other Microsoft selectors (eg Outlook)
public TreeDataGrid()
{
Loaded += TreeDataGrid_Loaded;
LoadingRow += new EventHandler<DataGridRowEventArgs>(TreeDataGrid_LoadingRow);
}
#region MultiSelect Drag
object toSelectItemOnMouseLeftButtonUp;
void TreeDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(Row_PreviewMouseLeftButtonDown);
e.Row.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(Row_PreviewMouseLeftButtonUp);
}
void Row_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridRow row = (DataGridRow)sender;
toSelectItemOnMouseLeftButtonUp = null; // always clear selecteditem
if (SelectedItems.Contains(row.Item)) //if the pointed item is already selected do not reselect it, so the previous multi-selection will remain
{
e.Handled = true; // this prevents the multiselection from disappearing, BUT datagridcell still gets the event and sets DataGrid's private member _selectionAnchor
toSelectItemOnMouseLeftButtonUp = row.Item; // store our item to select on MouseLeftButtonUp
}
}
void Row_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DataGridRow row = (DataGridRow)sender;
if (row.Item == toSelectItemOnMouseLeftButtonUp) // check if it's set and concerning the same row
{
if (SelectedItem == toSelectItemOnMouseLeftButtonUp) SelectedItem = null; // if the item is already selected whe need to trigger a change
SelectedItem = toSelectItemOnMouseLeftButtonUp; // this will clear the multi selection, and only select the item we pressed down on
typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, new DataGridCellInfo(row.Item, ColumnFromDisplayIndex(0))); // we need to set this anchor for when we select by pressing shift key
toSelectItemOnMouseLeftButtonUp = null; // handled
}
}
#endregion