I'm trying to implement in WPF tab that behaves like the one in IE9.
When you open in the last many tabs, they are getting smaller and also to buttons are showen in the left and in the right, for scrolling between the tabs.
Any help would be very appritiated.
create two main tab (main tabs are these two tab in answer) like this
<TabItem Header="«" Name="LeftTab"/>
<TabItem Header="»" Name="RightTab"/>
set the visible of them to hiden. now add all tabs you want(with c# code or xaml) but dont forget set tag for all tab you add like below
<TabItem Header="new" Name="tiNew" Tag="1"/>
<TabItem Header="edit" Name="tiEdit" Tag="2"/>
...
now when tabs count go more than normal and you cant show all in 1 page Do Under :
1.change visible of two main tab..
bool is_Left_Right_tabVisible = false;
if (tabControl1.Items.Count > 8)
{
LeftTab.Visibility = System.Windows.Visibility.Visible;
RightTab.Visibility = System.Windows.Visibility.Visible;
is_Left_Right_tabVisible = true;
}
else
{
LeftTab.Visibility = System.Windows.Visibility.Hidden;
RightTab.Visibility = System.Windows.Visibility.Hidden;
is_Left_Right_tabVisible = false;
}
2.hidden all extra tab and only show some of them (example : show two main tab And show tab with tag 1-8)
3.if user click on main tabs (left or right tab) hidden one tab and visible another tab (example: you have lefttab-1-2-3-4-righttab when user click on right hidden NO 1 and vsible No 5 And focus on No 5)
private void RightTab_MouseUp(object sender, MouseButtonEventArgs e)
{
if (is_Left_Right_tabVisible)
{
TabItem ti = sender as TabItem;
if (ti.Name == "RightTab")
{
//find right tab must set to visible
int Showtabindex = 0;
var t1 = tabControl1.Items.OfType<TabItem>().Where(x => x.Visibility == System.Windows.Visibility.Hidden);
foreach (var item in t)
{
if (((int)item.Tag) > Showtabindex)
Showtabindex = (int)item.Tag;
}
//find left tab must go invisible
int Hiddentabindex = Showtabindex;
var t2 = tabControl1.Items.OfType<TabItem>().Where(x => x.Visibility == System.Windows.Visibility.Visible);
foreach (var item in t2)
{
if (((int)item.Tag) < Hiddentabindex)
Hiddentabindex = (int)item.Tag;
}
(tabControl1.Items[Hiddentabindex] as TabItem).Visibility = System.Windows.Visibility.Hidden;
(tabControl1.Items[Showtabindex] as TabItem).Visibility = System.Windows.Visibility.Visible;
//you can create drag and drop for tabs then user can change tab TAG
}
else if (ti.Name == "LeftTab")
{
//.....
}
}
}
i know it was abit hard but when i create a good user control i feel good .
but dont forget in this usercontrol we use tabcontrol we can create a custom tab control from first and dont use this tabcontrol.
you also can create animation for tabs when those change opacity and move animation would be good check this post
Related
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.
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 have several radio buttons that are dynamically populated on a form and I have set a click event on the dynamically created radio buttons. On click i get a returned value as follows through debugging (eg) "sender { Text = "this is answer one" + Checked = "True"} using code as follows:
//Radio button click:
void Form1_Click(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
string radioButtonValue = rb.Text;
if (radioButtonValue != String.Empty)
{
}
}
The debug values are returned via "RadioButton rb = sender as RadioButton;" - the diffrent radio buttons text is set via a dataset that I call in a local dataset that loops through the dataset and and sets the radio button text accordingly (eg):
for (int i = 0; i < _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count; i++)
{
radioButtons[i] = new RadioButton();
radioButtons[i].AutoCheck = true;
radioButtons[i].Text = _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[i]["tbl_QuestionnaireAnswer_Description"].ToString();
radioButtons[i].Location = new System.Drawing.Point(60, 20 + i * 20);
radioButtons[i].Click += new EventHandler(Form1_Click);
panel.Controls.Add(radioButtons[i]);
}
So: wat id like to know is on the radio button click (Form1_Click) event is it possible to return the primary key of the of the selected radio button that I choose and not just the sender { Text = "this is answer one" + Checked = "True"} as I would like to use the primarykey in that dataset to write back to my Database.
Thanks in advance.
Kind regards
geo
Most winforms controls contain the Tag property that is used to contain custom user data in the control. You can read more at: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.tag.aspx
So, your solution should be simpler and more concise like this:
for (int i = 0; i < _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count; i++)
{
radioButtons[i] = new RadioButton();
radioButtons[i].AutoCheck = true;
radioButtons[i].Location = new System.Drawing.Point(60, 20 + i * 20);
radioButtons[i].Tag = _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[i];
radioButtons[i].Click += new EventHandler(Form1_Click);
panel.Controls.Add(radioButtons[i]);
}
This includes a relevant datarow in the radiobutton. The next thing is to get any data from it you need:
//Radio button click:
void Form1_Click(object sender, EventArgs e)
{
RadioButton radioButton = sender as RadioButton;
if (radioButton == null)
return;
DataRow row = radioButton.Tag as DataRow;
if (row == null)
return;
/* Post any processing here. e.g.
MessageBox.Show(row["ID"].ToString());
*/
}
This way you have all the data and it's strongly typed, which is a good thing.
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
If have a WPF DataGrid on the left of a Window with an area to the right for displaying the selected record. The selected record consists of Textboxes and ComboBoxes that are disabled until the edit button is clicked. All works as expected.
However, it seems a bit clumsy to be populating ComboBoxes when the SelectedItem of the DataGrid being changed. A much lighter control such as a TextBlock could be used until the Edit button is clicked, then the TextBlocks could be switched out for ComboBoxes.
I'm sure this can be done with some sort of templating but when I tried to experiment with this, all of the events that are associated with the ComboBoxes report an error as they're no longer present as they have been replace with TextBlocks in "View mode".
I'm probably going about this wrong so some guidance would be appreciated.
here is excelent article
To apply single-click editing to all cells in the DataGrid
Paste the style below into the Resources of your DataGrid
Paste the method into the code behind
To apply single-click editing to only certain cells in the DataGrid
Set an x:Key on the Style (ex. )
Paste the style into the Resources of your DataGrid
Apply the style to the CellStyle property of the columns which you'd like to have single click editing (ex. )
Paste the method into the code behind
//
// SINGLE CLICK EDITING
//
private void DataGridCell_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
{
if (!cell.IsFocused)
{
cell.Focus();
}
DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
if (dataGrid != null)
{
if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
{
if (!cell.IsSelected)
cell.IsSelected = true;
}
else
{
DataGridRow row = FindVisualParent<DataGridRow>(cell);
if (row != null && !row.IsSelected)
{
row.IsSelected = true;
}
}
}
}
}
static T FindVisualParent<T>(UIElement element) where T : UIElement
{
UIElement parent = element;
while (parent != null)
{
T correctlyTyped = parent as T;
if (correctlyTyped != null)
{
return correctlyTyped;
}
parent = VisualTreeHelper.GetParent(parent) as UIElement;
}
return null;
}
The ContentTemplateSelector property should allow you to select one template or another depending on the current mode (view/edit)
The marked answer link is dead.
This may help instead:
http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing