DataGridComboboxColumn - Get cell value - wpf

The task is the following: there is a DataGrid with ComboboxColumns. If user changes cell[2,3] and selected value!=0 then disable cell[3,2]. I wrote the following Handler:
private void grAssessment_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
int x = e.Column.DisplayIndex;
int y = e.Row.GetIndex();
grAssessment.GetCell(x, y).IsEnabled = false;
grAssessment.GetCell(x, y).Background = Brushes.LightGray;
}
But it disables appropriate cell in anyway. How to add selected value!=0 condition to this code?
Thanks in advance.

Try to check this out:
1. DataGridComboBoxColumn ItemsSource (for current version only, use your own):
private ObservableCollection<ScoreData> _scores = new ObservableCollection<ScoreData>(
new List<ScoreData>
{
new ScoreData{Score = 1, ScoreVerbal = "the same"},
new ScoreData{Score = 3, ScoreVerbal = "moderate superiority"},
new ScoreData{Score = 5, ScoreVerbal = "strong superiority"},
new ScoreData{Score = 7, ScoreVerbal = "the samvery strong superioritye"},
new ScoreData{Score = 9, ScoreVerbal = "extremely superiority"},
} );
2. Handler code (the handler defined on the data grid):
private void SelectDataGrid_OnCellEditEnding(object sender,
DataGridCellEditEndingEventArgs e)
{
var editingElement = e.EditingElement as Selector;
if(editingElement == null) return;
var selectedData = editingElement.SelectedItem as ScoreData;
if(selectedData == null || selectedData.Score > 1) return;
var dataGridCell = editingElement.GetVisualParentOfType<DataGridCell>();
if(dataGridCell == null) return;
dataGridCell.IsEnabled = false;
}
3. GetVisualParentOfType code (as part of extension class):
public static class VisualTreeExtensions
{
public static T GetVisualParentOfType<T>(this DependencyObject child)
where T : DependencyObject
{
if (child is T)
return child as T;
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null) return null;
var parent = parentObject as T;
return parent ?? GetVisualParentOfType<T>(parentObject);
}
public static T GetChildOfType<T>(this 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;
}
}
regards,

I found the following solution
private void grAssessment_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
int x = e.Column.DisplayIndex;
int y = e.Row.GetIndex();
DataGridCell cell = grAssessment.GetCell(y, x);
if (((System.Windows.Controls.ComboBox)(cell.Content)).Text != "")
{
grAssessment.GetCell(x, y).IsEnabled = false;
grAssessment.GetCell(x, y).Background = Brushes.LightGray;
}
else
{
grAssessment.GetCell(x, y).IsEnabled = true;
grAssessment.GetCell(x, y).Background = Brushes.White;
}
}

Related

How to change DataGridCell value programatically

I have a DataGrid with some rows.Now I want change some cell style, eg:
|red| Hel |/red| |blue| lo |/blue| Everybody.
Here is my GetCell function.
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
var v = (Visual) VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
public static DataGridRow GetSelectedRow(this DataGrid grid)
{
return (DataGridRow) grid.ItemContainerGenerator.ContainerFromItem(grid.SelectedItem);
}
public static DataGridRow GetRow(this DataGrid grid, int index)
{
var row = (DataGridRow) grid.ItemContainerGenerator.ContainerFromIndex(index);
if (row != null) return row;
// May be virtualized, bring into view and try again.
grid.UpdateLayout();
grid.ScrollIntoView(grid.Items[index]);
row = (DataGridRow) grid.ItemContainerGenerator.ContainerFromIndex(index);
return row;
}
public static DataGridCell GetCell(this DataGrid grid, DataGridRow row, int column)
{
if (row == null) return null;
var presenter = GetVisualChild<DataGridCellsPresenter>(row);
if (presenter == null)
{
grid.ScrollIntoView(row, grid.Columns[column]);
presenter = GetVisualChild<DataGridCellsPresenter>(row);
}
var cell = (DataGridCell) presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
grid.ScrollIntoView(row, grid.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
public static DataGridCell GetCell(this DataGrid grid, int row, int column)
{
DataGridRow rowContainer = grid.GetRow(row);
return grid.GetCell(rowContainer, column);
}
When I set DataGridCell content with some value by grid.GetCell(1, 0).Content = "PpppPppp", and then scroll DataGrid, the value is gone!
Why?
Even the value jumps to another cell.So strange.
I want to set the cell with style, so not use the funtion about:
(this.dataGrid1.Items[0] as DataRowView)[0] = "new value";
But:
private void SetBlockStyle(TextBlock block, Dictionary<int, int> section)
{
Brush foreground = Brushes.Red;
int start = 0;
string text = block.Text;
block.Text = "";
foreach (int i in section.Keys)
{
if (text.Length <= i)
{
break;
}
block.Inlines.Add(text.Substring(start, i - start));
start = i;
block.Inlines.Add(new Run(text.Substring(i, section[i]))
{
Foreground = foreground,
FontWeight = FontWeights.Bold
});
start += section[i];
}
if (start < text.Length)
{
block.Inlines.Add(text.Substring(start, text.Length - start));
}
}
Can you give me some advice?

How to resize a stacklayoutpanel to fit its contents?

I have searched telerik's site for a while now and can not find any mention on how to resize a stacklayoupanel to fit its elements. There are properties that allow resizing to fit its elements; however, these properties are not working for me. I was wondering if there was anyone on here who has used this and can help me out. I have a list view that has listViewVisualItems that do not fit their contents. Rather the contents "leak" out of the visual items below and bleed into the next one.
Here is my custom item class.
public class ChargePlotListViewItem : SimpleListViewVisualItem
{
private LightVisualElement imageElement;
private LightVisualElement titleElement;
private LightVisualElement bioElement;
private StackLayoutPanel stackLayout;
protected override void CreateChildElements()
{
base.CreateChildElements();
stackLayout = new StackLayoutPanel();
stackLayout.Orientation = System.Windows.Forms.Orientation.Vertical;
//stackLayout.AutoSize = true; These do not work
//stackLayout.AutoSizeMode = RadAutoSizeMode.WrapAroundChildren;
imageElement = new LightVisualElement();
imageElement.DrawText = false;
imageElement.ImageLayout = System.Windows.Forms.ImageLayout.Zoom;
//imageElement.StretchVertically = false;
imageElement.Margin = new System.Windows.Forms.Padding(1, 1, 1, 2);
imageElement.ShouldHandleMouseInput = false;
imageElement.NotifyParentOnMouseInput = true;
imageElement.AutoSizeMode = RadAutoSizeMode.FitToAvailableSize;
//stackLayout.Children.Add(imageElement);
titleElement = new LightVisualElement();
titleElement.TextAlignment = ContentAlignment.TopCenter;
titleElement.Margin = new Padding(2, 1, 1, 2);
titleElement.Font = new System.Drawing.Font("Segoe UI", 8, FontStyle.Italic, GraphicsUnit.Point);
titleElement.ShouldHandleMouseInput = false;
titleElement.NotifyParentOnMouseInput = true;
stackLayout.Children.Add(titleElement);
bioElement = new LightVisualElement();
bioElement.TextAlignment = ContentAlignment.BottomLeft;
bioElement.ShouldHandleMouseInput = false;
bioElement.NotifyParentOnMouseInput = true;
bioElement.Margin = new Padding(2, 1, 1, 2);
bioElement.Font = new System.Drawing.Font("Segoe UI", 9, FontStyle.Regular, GraphicsUnit.Point);
bioElement.ForeColor = Color.FromArgb(255, 114, 118, 125);
stackLayout.Children.Add(bioElement);
this.Children.Add(stackLayout);
//this.stackLayout.Measure(new System.Drawing.SizeF((float)stackLayout.Size.Width, (float)20));
this.Padding = new Padding(1, 2, 1, 2);
this.Shape = new RoundRectShape(3);
this.BorderColor = Color.Black;
this.BorderGradientStyle = GradientStyles.Solid;
this.DrawBorder = true;
this.DrawFill = true;
this.BackColor = Color.Azure;
this.GradientStyle = GradientStyles.Solid;
}
protected override void SynchronizeProperties()
{
base.SynchronizeProperties();
frmBingMaps.CriminalPlotObject plotObject = this.Data.Value as frmBingMaps.CriminalPlotObject;
if (plotObject != null)
{
try
{
this.imageElement.Image = Crime_Information_System.Properties.Resources
.bullet_blue;
}
catch
{
}
//building the title for the element depending on which names are on record
StringBuilder NameBuilder = new StringBuilder();
if (plotObject.Data.FirstName != null | plotObject.Data.FirstName != string.Empty)
NameBuilder.Append(plotObject.Data.FirstName + " ");
if (plotObject.Data.LastName != null | plotObject.Data.LastName != string.Empty)
NameBuilder.Append(plotObject.Data.LastName + " ");
//NameBuilder.Append(" Charge: " + gangBanger.Incidents[0].Charges[0].ChargeDescription);
this.titleElement.Text = NameBuilder.ToString();
StringBuilder BioBuilder = new StringBuilder();
//this.radDesktopAlert1.ContentText = "<html><b>" + CentralDataStore.AllUsers.Find(P => P.intUserID
// == BLAH.SenderID).strFirstName + " " + CentralDataStore.AllUsers.Find(P => P.intUserID ==
// BLAH.SenderID).strLastName + "</b><br>" + BLAH.Subject;
BioBuilder.Append("<html>");
BioBuilder.Append("<b>Incident ID</b>: " + plotObject.Data.Incidents.Find(
P => P.IncidentID == plotObject.CaseID).IncidentID.ToString());
BioBuilder.Append("<br>");
BioBuilder.Append("<b>Date</b>: " + plotObject.Data.Incidents.Find(
P => P.IncidentID == plotObject.CaseID).DateOfIncident.ToShortDateString());
BioBuilder.Append("<br>");
BioBuilder.Append(plotObject.Data.Incidents.Find(P => P.IncidentID == plotObject
.CaseID).Description);
BioBuilder.Append("<br>");
//BioBuilder.Append("\r\n");
BioBuilder.Append("<b>Location</b>: ");
BioBuilder.Append(plotObject.Data.Incidents.Find(P => P.IncidentID ==
plotObject.CaseID).Location);
BioBuilder.Append("<br>");
//BioBuilder.Append("\r\n");
BioBuilder.Append(string.Format("<b>Charges</b>: "));
foreach (Charge c in plotObject.Data.Incidents.Find(P => P.IncidentID == plotObject.CaseID
).Charges)
{
BioBuilder.Append(c.ChargeDescription + ", ");
}
BioBuilder.Remove(BioBuilder.Length - 2,2);
//BioBuilder.Append("
bioElement.Text = BioBuilder.ToString();
this.Text = ""; //here to erase the system.crimesysteminformation.plot blah object name
}
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(IconListViewVisualItem);
}
}
protected override SizeF MeasureOverride(SizeF availableSize)
{
SizeF measuredSize = base.MeasureOverride(availableSize);
this.stackLayout.Measure(measuredSize);
return measuredSize;
}
protected override SizeF ArrangeOverride(SizeF finalSize)
{
base.ArrangeOverride(finalSize);
this.stackLayout.Arrange(new RectangleF(PointF.Empty, finalSize));
return finalSize;
}
To overcome this behavior, please consider allowing the items take their desired size by setting the following property:
radListView1.AllowArbitraryItemHeight = true;
For your convenience, here is a simplified version of your code in action:
void radListView1_VisualItemCreating(object sender, ListViewVisualItemCreatingEventArgs e)
{
e.VisualItem = new ChargePlotListViewItem();
}
public class ChargePlotListViewItem : SimpleListViewVisualItem
{
private LightVisualElement imageElement;
private LightVisualElement titleElement;
private LightVisualElement bioElement;
private StackLayoutPanel stackLayout;
protected override void CreateChildElements()
{
base.CreateChildElements();
stackLayout = new StackLayoutPanel();
stackLayout.Orientation = System.Windows.Forms.Orientation.Vertical;
imageElement = new LightVisualElement();
imageElement.DrawText = false;
imageElement.ImageLayout = System.Windows.Forms.ImageLayout.Center;
imageElement.ShouldHandleMouseInput = false;
imageElement.NotifyParentOnMouseInput = true;
stackLayout.Children.Add(imageElement);
titleElement = new LightVisualElement();
titleElement.TextAlignment = ContentAlignment.TopCenter;
titleElement.Font = new System.Drawing.Font("Segoe UI", 8, FontStyle.Italic, GraphicsUnit.Point);
titleElement.ShouldHandleMouseInput = false;
titleElement.NotifyParentOnMouseInput = true;
stackLayout.Children.Add(titleElement);
bioElement = new LightVisualElement();
bioElement.TextAlignment = ContentAlignment.BottomLeft;
bioElement.ShouldHandleMouseInput = false;
bioElement.NotifyParentOnMouseInput = true;
bioElement.Margin = new Padding(2, 1, 1, 2);
bioElement.Font = new System.Drawing.Font("Segoe UI", 9, FontStyle.Regular, GraphicsUnit.Point);
bioElement.ForeColor = Color.FromArgb(255, 114, 118, 125);
stackLayout.Children.Add(bioElement);
this.Children.Add(stackLayout);
}
protected override void SynchronizeProperties()
{
base.SynchronizeProperties();
DataRowView rowView = this.Data.DataBoundItem as DataRowView;
imageElement.Image = (Image)rowView.Row["Image"];
titleElement.Text = rowView.Row["Title"].ToString();
bioElement.Text = rowView.Row["Bio"].ToString();
this.Text = ""; //here to erase the system.crimesysteminformation.plot blah object name
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(IconListViewVisualItem);
}
}
}

WPF ICollectionView Filtering

I've written a code for filtering items in ComboBox:
My question is, how would you do that?
I think that this solution with reflection could be very slow..
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
view.Filter += this.FilterPredicate;
private bool FilterPredicate(object value)
{
if (value == null)
return false;
if (String.IsNullOrEmpty(SearchedText))
return true;
int index = value.ToString().IndexOf(
SearchedText,
0,
StringComparison.InvariantCultureIgnoreCase);
if ( index > -1) return true;
return FindInProperties(new string[] { "Property1", "Property2" }, value, SearchedText);
}
private bool FindInProperties(string[] properties, object value, string txtToFind)
{
PropertyInfo info = null;
for (int i = 0; i < properties.Length; i++)
{
info = value.GetType().GetProperty(properties[i]);
if (info == null) continue;
object s = info.GetValue(value, null);
if (s == null) continue;
int index = s.ToString().IndexOf(
txtToFind,
0,
StringComparison.InvariantCultureIgnoreCase);
if (index > -1) return true;
}
return false;
}
Why not just this:
ICollectionView view = CollectionViewSource.GetDefaultView(newValue);
IEqualityComparer<String> comparer = StringComparer.InvariantCultureIgnoreCase;
view.Filter = o => {
Person p = o as Person;
return p.FirstName.Contains(SearchedText, comparer)
|| p.LastName.Contains(SearchedText, comparer);
}
Do you need to search properties dynamically?

ListBox List Rotation

I want to create a ListBox that basically displays a circular list. For example a list with three items:
1
2
3 <- (Selector on item 3)
will rotate the list and have the selector over item 1 after passing item 3:
2
3
1 <- (Selector on item 1)
This is similar to the menu paradigm of the Windows Media Center.
What part of the ListBox should I be tweaking???
Well, I updated the Items... not sure it's the right way, but, anyhow, if you want to take a look at my implementation... here it is:
using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Collections.ObjectModel;
using ScrollLimit;
using System.Windows.Controls.Primitives;
using System.Text.RegularExpressions;
namespace ScrollLimit
{
public enum ScrollLimitBehaviour { Springs, Circular };
}
namespace SmoothScroll
{
[TemplatePart(Name = "PART_Border", Type = typeof(Border))]
[TemplatePart(Name = "PART_ScrollViewer", Type = typeof(ScrollViewer))]
[TemplatePart(Name = "PART_StackPanel", Type = typeof(StackPanel))]
public class SmoothScrollViewer : ListBox
{
private double move_init, scroll_init, scroll_offset, scroll_t0, scroll_span, scroll_v0, scroll_offset0, backOffset, adjustLimit, stopWindowCoord, hitOffset;
private bool scroll_mouseDown = false, scroll_direction = false, scroll_out = false, scrollLessThanZero = false, scrollMoreThanEnd = false, selectionAllowed = false, canUpdate = true, external = true;
private DispatcherTimer scroll_timerClock = new DispatcherTimer();
private EventHandler decelerateEventHandler, adjustEventHandler;
private int selectedIndex;
private ScrollViewer sv;
private Rectangle stopWindow;
private StackPanel sp;
private ListBoxItem lbi;
private Grid g;
private TextBox filterEdit;
//proprietatea de orientare a listei
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation",
typeof(Orientation),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(Orientation.Vertical,
new PropertyChangedCallback(OnOrientationChanged),
new CoerceValueCallback(OnCoerceOrientation))
);
private static object OnCoerceOrientation(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceOrientation((Orientation)value);
else return value;
}
private static void OnOrientationChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnOrientationChanged((Orientation)e.OldValue, (Orientation)e.NewValue);
}
protected virtual Orientation OnCoerceOrientation(Orientation value)
{
return value;
}
protected virtual void OnOrientationChanged(Orientation oldValue, Orientation newValue)
{
}
public Orientation Orientation
{
get
{
return (Orientation)GetValue(OrientationProperty);
}
set
{
SetValue(OrientationProperty, value);
}
}
//proprietatea de multiplicator de deplasament a chenarului de oprire a elementului evidentiat
public static readonly DependencyProperty StopWindowOffsetProperty =
DependencyProperty.Register("StopWindowOffset",
typeof(double),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(-1.0,
new PropertyChangedCallback(OnStopWindowOffsetChanged),
new CoerceValueCallback(OnCoerceStopWindowOffset))
);
private static object OnCoerceStopWindowOffset(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceStopWindowOffset((double)value);
else return value;
}
private static void OnStopWindowOffsetChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnStopWindowOffsetChanged((double)e.OldValue, (double)e.NewValue);
}
protected virtual double OnCoerceStopWindowOffset(double value)
{
return value;
}
protected virtual void OnStopWindowOffsetChanged(double oldValue, double newValue)
{
}
public double StopWindowOffset
{
get
{
return (double)GetValue(StopWindowOffsetProperty);
}
set
{
SetValue(StopWindowOffsetProperty, value);
}
}
//proprietatea de comportament la capete
public static readonly DependencyProperty ScrollLimitBehaviourProperty =
DependencyProperty.Register("ScrollLimitBehaviour",
typeof(ScrollLimitBehaviour),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(ScrollLimitBehaviour.Springs,
new PropertyChangedCallback(OnScrollLimitBehaviourChanged),
new CoerceValueCallback(OnCoerceScrollLimitBehaviour))
);
private static object OnCoerceScrollLimitBehaviour(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceScrollLimitBehaviour((ScrollLimitBehaviour)value);
else return value;
}
private static void OnScrollLimitBehaviourChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnScrollLimitBehaviourChanged((ScrollLimitBehaviour)e.OldValue, (ScrollLimitBehaviour)e.NewValue);
}
protected virtual ScrollLimitBehaviour OnCoerceScrollLimitBehaviour(ScrollLimitBehaviour value)
{
return value;
}
protected virtual void OnScrollLimitBehaviourChanged(ScrollLimitBehaviour oldValue, ScrollLimitBehaviour newValue)
{
}
public ScrollLimitBehaviour ScrollLimitBehaviour
{
get
{
return (ScrollLimitBehaviour)GetValue(ScrollLimitBehaviourProperty);
}
set
{
SetValue(ScrollLimitBehaviourProperty, value);
}
}
//proprietatea de existenta a filtrarii
public static readonly DependencyProperty CanFilterProperty =
DependencyProperty.Register("CanFilter",
typeof(bool),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(false,
new PropertyChangedCallback(OnCanFilterChanged),
new CoerceValueCallback(OnCoerceCanFilter))
);
private static object OnCoerceCanFilter(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceCanFilter((bool)value);
else return value;
}
private static void OnCanFilterChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnCanFilterChanged((bool)e.OldValue, (bool)e.NewValue);
}
protected virtual bool OnCoerceCanFilter(bool value)
{
return value;
}
protected virtual void OnCanFilterChanged(bool oldValue, bool newValue)
{
}
public bool CanFilter
{
get
{
return (bool)GetValue(CanFilterProperty);
}
set
{
SetValue(CanFilterProperty, value);
}
}
//previne scroll-ul prin drag in afara listei
protected override void OnMouseMove(MouseEventArgs e)
{
}
protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e)
{
}
//copie ItemsSource in Items
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
if (ItemsSource != null)
{
ObservableCollection<object> temp = new ObservableCollection<object>();
foreach (object o in ItemsSource) temp.Add(o);
ItemsSource = null;
for (int i = 0; i < temp.Count; i++) Items.Add(temp[i]);
}
}
//returneaza elementul primit ca parametru ca ListBoxItem
private ListBoxItem getListBoxItem(UIElement element)
{
if (element is ListBoxItem) return element as ListBoxItem;
while (element != this && element != null)
{
element = VisualTreeHelper.GetParent(element) as UIElement;
if (element is ListBoxItem) return element as ListBoxItem;
}
return null;
}
//la aplicarea sablonului vizual au loc asocierile de evenimente si initializarile
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
sv = GetTemplateChild("PART_ScrollViewer") as ScrollViewer;
sp = GetTemplateChild("PART_StackPanel") as StackPanel;
g = GetTemplateChild("PART_Grid") as Grid;
if ((ScrollBarVisibility)GetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty) == ScrollBarVisibility.Disabled) sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
if ((ScrollBarVisibility)GetValue(ScrollViewer.VerticalScrollBarVisibilityProperty) == ScrollBarVisibility.Disabled) sv.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
sp.PreviewMouseDown += new MouseButtonEventHandler(l_MouseDown);
sp.PreviewMouseMove += new MouseEventHandler(l_MouseMove);
sp.PreviewMouseUp += new MouseButtonEventHandler(l_MouseUp);
sp.MouseLeave += new MouseEventHandler(l_MouseLeave);
sp.PreviewMouseWheel += new MouseWheelEventHandler(l_PreviewMouseWheel);
sp.PreviewKeyDown += new KeyEventHandler(sp_PreviewKeyDown);
if (Orientation == Orientation.Vertical)
{
sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
HorizontalContentAlignment = HorizontalAlignment.Stretch;
}
else
{
sv.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
VerticalContentAlignment = VerticalAlignment.Stretch;
}
scroll_timerClock.Interval = new TimeSpan(0, 0, 0, 0, 1);
decelerateEventHandler = new EventHandler(scroll_timerClock_Tick);
adjustEventHandler = new EventHandler(adjust_timerClock_Tick);
scroll_timerClock.Tick += decelerateEventHandler;
LayoutUpdated += new EventHandler(l_LayoutUpdated);
PreviewMouseDown += new MouseButtonEventHandler(SmoothScrollViewer_MouseDown);
}
//prin interactiunea cu mouse-ul asupra listei, se initiaza o actiune de
//selectie non-externa
void SmoothScrollViewer_MouseDown(object sender, MouseButtonEventArgs e)
{
external = false;
}
//functie de scroll la element specificat
public void ScrollTo(object item)
{
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
int indexOfItem = Items.IndexOf(item);
int nrItemsToMove = 0,
i = 0;
double cummulativeSize = 0;
do
{
lbi = (ListBoxItem)(ItemContainerGenerator.ContainerFromIndex(i));
cummulativeSize += (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
i++;
nrItemsToMove++;
}
while (cummulativeSize <= ((Orientation == Orientation.Vertical) ? sv.ViewportHeight : sv.ViewportWidth));
if (indexOfItem > Items.Count - nrItemsToMove || indexOfItem == 0)
{
for (i = 0; i <= nrItemsToMove; i++)
{
object elt = Items[0];
Items.RemoveAt(0);
Items.Add(elt);
}
indexOfItem = Items.IndexOf(item);
}
double scrollAmount = 0;
for (i = 0; i < indexOfItem - 1; i++)
{
lbi = (ListBoxItem)(ItemContainerGenerator.ContainerFromIndex(i));
scrollAmount += (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
}
if (Orientation == Orientation.Vertical) sv.ScrollToVerticalOffset(scrollAmount);
else sv.ScrollToHorizontalOffset(scrollAmount);
selectionAllowed = true;
SelectedItem = item;
selectionAllowed = false;
scroll_out = false;
}
}
//Manipularea listei din tastele sageti
void sp_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (((e.Key == Key.Right || e.Key == Key.Left) && Orientation == Orientation.Horizontal) || ((e.Key == Key.Up || e.Key == Key.Down) && Orientation == Orientation.Vertical))
{
adjustLimit = 0;
scrollLessThanZero = false;
scrollMoreThanEnd = false;
SelectedIndex = -1;
backOffset = ((Orientation == Orientation.Vertical) ? (sv.ExtentHeight - sv.ViewportHeight) : (sv.ExtentWidth - sv.ViewportWidth));
scroll_mouseDown = false;
scroll_v0 = (e.Key == Key.Right || e.Key == Key.Up ? -1 : 1);
scroll_t0 = Environment.TickCount;
scroll_direction = (scroll_v0 >= 0);
scroll_offset0 = ((Orientation == Orientation.Vertical) ? sv.VerticalOffset - sp.Margin.Top : sv.HorizontalOffset - sp.Margin.Left);
scroll_timerClock.IsEnabled = true;
}
else
if (e.Key == Key.Return && stopWindow == null)
{
UIElement elt = InputHitTest(new Point(ActualWidth / 2, ActualHeight / 2)) as UIElement;
if (elt != null)
{
lbi = getListBoxItem(elt);
selectionAllowed = true;
SelectedIndex = ItemContainerGenerator.IndexFromContainer(lbi);
}
}
e.Handled = true;
}
//la ficare actualizare a randarii controlului, se initializeaza/redimensioneaza chenarul
//de oprire a elementului selectabil si campul editabil de filtrare in cazul in care acesta
//exista
void l_LayoutUpdated(object sender, EventArgs e)
{
try
{
if (StopWindowOffset >= 0)
{
lbi = (ListBoxItem)(ItemContainerGenerator.ContainerFromIndex(((SelectedIndex > 0) ? SelectedIndex : selectedIndex)));
hitOffset = (Orientation == Orientation.Vertical) ? lbi.ActualHeight / 4 : lbi.ActualWidth / 4;
stopWindowCoord = StopWindowOffset * ((Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth);
if (stopWindow == null)
{
stopWindow = new Rectangle();
stopWindow.SetValue(Grid.RowProperty, 1);
stopWindow.HorizontalAlignment = HorizontalAlignment.Left;
stopWindow.VerticalAlignment = VerticalAlignment.Top;
stopWindow.Fill = BorderBrush;
stopWindow.Opacity = 0.5;
stopWindow.IsHitTestVisible = false;
g.Children.Add(stopWindow);
}
stopWindow.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, stopWindowCoord, 0, 0) : new Thickness(stopWindowCoord, 0, 0, 0);
stopWindow.Width = lbi.ActualWidth;
stopWindow.Height = lbi.ActualHeight;
}
if (CanFilter)
{
if (filterEdit == null)
{
filterEdit = new TextBox();
filterEdit.HorizontalAlignment = HorizontalAlignment.Center;
filterEdit.VerticalAlignment = VerticalAlignment.Top;
filterEdit.Margin = new Thickness(3);
filterEdit.TextChanged += new TextChangedEventHandler(filterEdit_TextChanged);
filterEdit.PreviewKeyDown += new KeyEventHandler(filterEdit_KeyDown);
g.Children.Add(filterEdit);
}
filterEdit.Width = ActualWidth - 20;
}
}
catch (Exception) { }
}
//La apasarea tastei sageata jos in filtru, se coboara in lista
void filterEdit_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
sp.Focusable = true;
Keyboard.Focus(sp);
}
}
//textul dupa care are loc filtrarea
void filterEdit_TextChanged(object sender, TextChangedEventArgs e)
{
Items.Filter = new Predicate<object>(PassesFilter);
}
public bool PassesFilter(Object value)
{
if (filterEdit.Text != "")
{
Regex regex = new Regex("^" + Regex.Escape(filterEdit.Text).Replace("\\*", ".*").Replace("\\?", ".") + ".*$");
return regex.IsMatch(extractText(value as UIElement));
}
else return true;
}
//tratarea evenimentului de selectie asupra unui element din lista
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
//MessageBox.Show(selectedIndex+" "+SelectedIndex);
if (!external)
{
//MessageBox.Show(SelectedIndex + "");
if (!selectionAllowed)
{
if (SelectedIndex != -1)
{
selectedIndex = SelectedIndex;
SelectedIndex = -1;
}
}
}
else selectionAllowed = false;
external = true;
base.OnSelectionChanged(e);
}
//Extrage textul care apare in interiorul oricarui control
private string extractText(UIElement item)
{
if (item is TextBlock) return ((TextBlock)item).Text;
if (item is TextBox) return ((TextBox)item).Text;
if (item is ContentControl)
{
object content = ((ContentControl)item).Content;
if (content is UIElement) return extractText(content as UIElement);
else return content.ToString();
}
else
{
string result = "";
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(item); i++)
result += extractText(VisualTreeHelper.GetChild(item, i) as UIElement) + " ";
return result;
}
}
//scroll prin rotita mouse-ului
void l_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
sp.Focusable = true;
Keyboard.Focus(sp);
adjustLimit = 0;
scrollLessThanZero = false;
scrollMoreThanEnd = false;
SelectedIndex = -1;
backOffset = ((Orientation == Orientation.Vertical) ? (sv.ExtentHeight - sv.ViewportHeight) : (sv.ExtentWidth - sv.ViewportWidth));
scroll_mouseDown = false;
scroll_v0 = -e.Delta / 100;
scroll_t0 = Environment.TickCount;
scroll_direction = (scroll_v0 >= 0);
scroll_offset0 = ((Orientation == Orientation.Vertical) ? sv.VerticalOffset - sp.Margin.Top : sv.HorizontalOffset - sp.Margin.Left);
scroll_timerClock.IsEnabled = true;
}
//la parasirea controlului de catre cursorul mouse-ului, cu butonul apasat, se simuleaza
//invocarea unui eveniment de eliberare a butonului mouse-ului
private void l_MouseLeave(object sender, MouseEventArgs e)
{
if (scroll_mouseDown)
{
MouseButtonEventArgs e1 = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left);
e1.RoutedEvent = MouseLeaveEvent;
l_MouseUp(sender, e1);
}
}
//scroll controlat de miscarea mouse-ului
private void l_MouseMove(object sender, MouseEventArgs e)
{
if (scroll_mouseDown)
{
scroll_offset = scroll_init - ((Orientation == Orientation.Vertical) ? e.GetPosition(this).Y : e.GetPosition(this).X);
if (scroll_offset < 0)
if (ScrollLimitBehaviour == ScrollLimitBehaviour.Springs) sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, -scroll_offset, 0, 0) : new Thickness(-scroll_offset, 0, 0, 0);
else
{
if (canUpdate)
{
object elt = Items[Items.Count - 1];
Items.RemoveAt(Items.Count - 1);
Items.Insert(0, elt);
lbi = (ListBoxItem)ItemContainerGenerator.ContainerFromIndex(Items.Count - 1);
double adjust = (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
scroll_init += adjust;
canUpdate = false;
}
}
else
if (scroll_offset - backOffset > 0)
if (ScrollLimitBehaviour == ScrollLimitBehaviour.Springs) sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, 0, 0, scroll_offset - backOffset) : new Thickness(0, 0, scroll_offset - backOffset, 0);
else
{
if (canUpdate)
{
object elt = Items[0];
Items.RemoveAt(0);
Items.Add(elt);
lbi = (ListBoxItem)ItemContainerGenerator.ContainerFromIndex(0);
double adjust = (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
scroll_init -= adjust;
canUpdate = false;
}
}
else canUpdate = true;
if ((Orientation == Orientation.Vertical)) sv.ScrollToVerticalOffset(scroll_offset);
else sv.ScrollToHorizontalOffset(scroll_offset);
}
}
//comportamentul la eliberarea butonului mouse-ului; daca miscarea efectuata este una
//minora, se recurge la selectarea elementului vizat, altfel se continua cu initierea
//miscarii inertiale induse de acceleratia impusa de miscarea pana in acest moment
private void l_MouseUp(object sender, MouseButtonEventArgs e)
{
double move_offset = move_init - ((Orientation == Orientation.Vertical) ? e.GetPosition(this).Y : e.GetPosition(this).X);
selectionAllowed = (Math.Abs(move_offset) <= 10 && SelectedIndex != selectedIndex && StopWindowOffset < 0);
if (selectionAllowed) SelectedIndex = selectedIndex;
adjustLimit = 0;
if (scroll_mouseDown && move_offset != 0)
{
scroll_mouseDown = false;
scroll_span = Environment.TickCount - scroll_t0;
if (scroll_span > 0) scroll_v0 = move_offset / scroll_span;
else scroll_v0 = 0;
scroll_t0 = Environment.TickCount;
scroll_direction = (move_offset >= 0);
scroll_offset0 = ((Orientation == Orientation.Vertical) ? sv.VerticalOffset - sp.Margin.Top : sv.HorizontalOffset - sp.Margin.Left);
scroll_timerClock.IsEnabled = true;
}
else
{
scroll_mouseDown = false;
if (move_offset == 0) scrollStopped();
}
}
//timer-ul responsabil cu actualizarea deplasamentului de derulare in urma miscarii
//uniform incetinite de dupa eliberarea butonului mouse-ului
private void scroll_timerClock_Tick(object sender, EventArgs e)
{
double scroll_a = (scroll_direction ? -1 : 1) * ((scroll_out) ? 0.005 : 0.003),
scroll_t = Environment.TickCount - scroll_t0,
scroll = 0.5 * scroll_a * scroll_t * scroll_t + scroll_v0 * scroll_t + scroll_offset0,
scroll_v = scroll_a * scroll_t + scroll_v0;
if (scroll > 0 && scroll < Math.Abs(backOffset))
if (scroll_out)
{
sp.Margin = new Thickness(0, 0, 0, 0);
scroll_out = false;
scrollStopped();
}
else
{
if (Orientation == Orientation.Vertical) sv.ScrollToVerticalOffset(scroll);
else sv.ScrollToHorizontalOffset(scroll);
if ((scroll_v <= 0) == scroll_direction) scrollStopped();
}
else
if (ScrollLimitBehaviour == ScrollLimitBehaviour.Springs)
{
if (scroll < 0) scrollLessThanZero = true;
else scrollMoreThanEnd = true;
if (scrollLessThanZero && scrollMoreThanEnd)
{
sp.Margin = new Thickness(0, 0, 0, 0);
scrollLessThanZero = false;
scrollMoreThanEnd = false;
scroll_out = false;
scrollStopped();
}
else
{
scroll_out = true;
if (scroll > 0) sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, 0, 0, scroll - backOffset) : new Thickness(0, 0, scroll - backOffset, 0);
else sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, -scroll, 0, 0) : new Thickness(-scroll, 0, 0, 0);
if (Orientation == Orientation.Vertical) sv.ScrollToVerticalOffset(scroll);
else sv.ScrollToHorizontalOffset(scroll);
}
}
else
{
scroll_out = false;
if (scroll <= 0)
{
object elt = Items[Items.Count - 1];
Items.RemoveAt(Items.Count - 1);
Items.Insert(0, elt);
lbi = (ListBoxItem)ItemContainerGenerator.ContainerFromIndex(Items.Count - 1);
double adjust = (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.A

Control for tags with auto-completion in Winforms?

I am seeking a WinForm control that would provide an autocomplete behavior for multiple space-separated - exactly ala del.icio.us (or stackoverflow.com for that matter).
Does anyone knows how to do that within a .NET 2.0 WinForm application?
ComboBox can autocomplete, but only one word at a time.
If you want to have each word separately autocompleted, you have to write your own.
I already did, hope it's not too long. It's not 100% exactly what you want, this was used for autocompleting in email client when typing in email adress.
/// <summary>
/// Extended TextBox with smart auto-completion
/// </summary>
public class TextBoxAC: TextBox
{
private List<string> completions = new List<string>();
private List<string> completionsLow = new List<string>();
private bool autocompleting = false;
private bool acDisabled = true;
private List<string> possibleCompletions = new List<string>();
private int currentCompletion = 0;
/// <summary>
/// Default constructor
/// </summary>
public TextBoxAC()
{
this.TextChanged += new EventHandler(TextBoxAC_TextChanged);
this.KeyPress += new KeyPressEventHandler(TextBoxAC_KeyPress);
this.KeyDown += new KeyEventHandler(TextBoxAC_KeyDown);
this.TabStop = true;
}
/// <summary>
/// Sets autocompletion data, list of possible strings
/// </summary>
/// <param name="words">Completion words</param>
/// <param name="wordsLow">Completion words in lowerCase</param>
public void SetAutoCompletion(List<string> words, List<string> wordsLow)
{
if (words == null || words.Count < 1) { return; }
this.completions = words;
this.completionsLow = wordsLow;
this.TabStop = false;
}
private void TextBoxAC_TextChanged(object sender, EventArgs e)
{
if (this.autocompleting || this.acDisabled) { return; }
string text = this.Text;
if (text.Length != this.SelectionStart) { return; }
int pos = this.SelectionStart;
string userPrefix = text.Substring(0, pos);
int commaPos = userPrefix.LastIndexOf(",");
if (commaPos == -1)
{
userPrefix = userPrefix.ToLower();
this.possibleCompletions.Clear();
int n = 0;
foreach (string s in this.completionsLow)
{
if (s.StartsWith(userPrefix))
{
this.possibleCompletions.Add(this.completions[n]);
}
n++;
}
if (this.possibleCompletions.Count < 1) { return; }
this.autocompleting = true;
this.Text = this.possibleCompletions[0];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos;
}
else
{
string curUs = userPrefix.Substring(commaPos + 1);
if (curUs.Trim().Length < 1) { return; }
string trimmed;
curUs = this.trimOut(curUs, out trimmed);
curUs = curUs.ToLower();
string oldUs = userPrefix.Substring(0, commaPos + 1);
this.possibleCompletions.Clear();
int n = 0;
foreach (string s in this.completionsLow)
{
if (s.StartsWith(curUs))
{
this.possibleCompletions.Add(this.completions[n]);
}
n++;
}
if (this.possibleCompletions.Count < 1) { return; }
this.autocompleting = true;
this.Text = oldUs + trimmed + this.possibleCompletions[0];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos + trimmed.Length;
}
this.currentCompletion = 0;
}
private void TextBoxAC_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
{
this.acDisabled = true;
}
if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down)
{
if ((this.acDisabled) || (this.possibleCompletions.Count < 1))
{
return;
}
e.Handled = true;
if (this.possibleCompletions.Count < 2) { return; }
switch (e.KeyCode)
{
case Keys.Up:
this.currentCompletion--;
if (this.currentCompletion < 0)
{
this.currentCompletion = this.possibleCompletions.Count - 1;
}
break;
case Keys.Down:
this.currentCompletion++;
if (this.currentCompletion >= this.possibleCompletions.Count)
{
this.currentCompletion = 0;
}
break;
}
int pos = this.SelectionStart;
string userPrefix = this.Text.Substring(0, pos);
int commaPos = userPrefix.LastIndexOf(",");
if (commaPos == -1)
{
pos--;
userPrefix = this.Text.Substring(0, pos);
this.autocompleting = true;
this.Text = userPrefix + this.possibleCompletions[this.currentCompletion].Substring(userPrefix.Length);
this.autocompleting = false;
this.SelectionStart = pos + 1;
this.SelectionLength = this.Text.Length - pos;
}
else
{
string curUs = userPrefix.Substring(commaPos + 1);
if (curUs.Trim().Length < 1) { return; }
string trimmed;
curUs = this.trimOut(curUs, out trimmed);
curUs = curUs.ToLower();
string oldUs = userPrefix.Substring(0, commaPos + 1);
this.autocompleting = true;
this.Text = oldUs + trimmed + this.possibleCompletions[this.currentCompletion];
this.autocompleting = false;
this.SelectionStart = pos;
this.SelectionLength = this.Text.Length - pos + trimmed.Length;
}
}
}
private void TextBoxAC_KeyPress(object sender, KeyPressEventArgs e)
{
if (!Char.IsControl(e.KeyChar)) { this.acDisabled = false; }
}
private string trimOut(string toTrim, out string trim)
{
string ret = toTrim.TrimStart();
int pos = toTrim.IndexOf(ret);
trim = toTrim.Substring(0, pos);
return ret;
}
}

Resources