I created a editable ComboBox for searching(filtering) like Google. I am using the ActionHandler "KeyUp" and the first input is highlighted and overwritten. How can i disable the overwriting or highlighting?
private void CbInKuLi_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(cbInKuLi.ItemsSource);
itemsViewOriginal.Filter = ((o) =>
{
if (String.IsNullOrEmpty(cbInKuLi.Text)) return true;
else
{
DeKreditor x = (DeKreditor)o;
string filterText = cbInKuLi.Text;
if (x.Nummer.ToLowerInvariant().Contains(filterText)
|| (!string.IsNullOrWhiteSpace(x.Firma) && x.Firma.ToLowerInvariant().Contains(filterText))
|| (!string.IsNullOrWhiteSpace(x.Vorname) && x.Vorname.ToLowerInvariant().Contains(filterText))
|| (!string.IsNullOrWhiteSpace(x.Name) && x.Name.ToLowerInvariant().Contains(filterText)))
return true;
else
return false;
}
});
itemsViewOriginal.Refresh();
cbInKuLi.IsDropDownOpen = true;
}
XAML:
<ComboBox
x:Name="cbInKuLi"
StaysOpenOnEdit="True"
IsEditable="True"
IsTextSearchEnabled="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Grid.Row="0"
Grid.Column="1"
Margin="5,0,5,5"
SelectionChanged="CbInKuLi_SelectionChanged"
KeyUp="CbInKuLi_KeyUp"
TextOptions.TextFormattingMode="Ideal" />
The Text Highlight caused because of setting IsDropDownOpen to true.
The Editable ComboBox auto select the Text if it is Opened, so you could get the TextBox from the template of the ComboBox by its Name than set the selection length to zero at the end of the text.
private void CbInKuLi_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
CollectionView itemsViewOriginal = (CollectionView)CollectionViewSource.GetDefaultView(cbInKuLi.ItemsSource);
itemsViewOriginal.Filter = ((o) =>
{
if (String.IsNullOrEmpty(cbInKuLi.Text)) return true;
else
{
Model x = (Model)o;
string filterText = cbInKuLi.Text;
if (x.Text.ToLowerInvariant().Contains(filterText))
return true;
else
return false;
}
});
itemsViewOriginal.Refresh();
cbInKuLi.IsDropDownOpen = true;
var textbox = (TextBox)cbInKuLi.Template.FindName("PART_EditableTextBox", cbInKuLi);
textbox.Select(textbox.Text.Length, textbox.Text.Length);
}
UPDATE:
From comments you can replace the last line by the following line and it is better than the original one:
textbox.CaretIndex = textbox.Text.Length;
Related
Code in context
private void button2_Click(object sender, RoutedEventArgs e)
{
edit();
}
public void edit()
{
textBox1.IsEnabled = true;
textBox2.IsEnabled = true;
textBox3.IsEnabled = true;
textBox4.IsEnabled = true;
textBox5.IsEnabled = true;
textBox6.IsEnabled = true;
textBox7.IsEnabled = true;
textBox8.IsEnabled = true;
textBox9.IsEnabled = true;
textBox10.IsEnabled = true;
textBox11.IsEnabled = true;
textBox12.IsEnabled = true;
textBox13.IsEnabled = true;
textBox14.IsEnabled = true;
textBox15.IsEnabled = true;
textBox16.IsEnabled = true;
textBox17.IsEnabled = true;
textBox18.IsEnabled = true;
}
I want perform the above using a simple for loop that loops through 1-18.
I have tried the followng method but doesn't work as intended
for(i=0;i<19;i++)
{
textBox"" + i + "".IsVisible = true;
}
I'm new to wpf and i'm migrating my app from winforms to wpf.
Use binding.
XAML (MyUserControl):
<UserControl Name="MyControl" ...
....
<TextBox Name="textBox1" IsEnabled="{Binding ElementName=MyControl, Path=AreTextBoxesEnabled}" ... />
<TextBox Name="textBox2" IsEnabled="{Binding ElementName=MyControl, Path=AreTextBoxesEnabled}" ... />
<TextBox Name="textBox3" IsEnabled="{Binding ElementName=MyControl, Path=AreTextBoxesEnabled}" ... />
...
Code-behind (MyUserControl):
public static readonly DependencyProperty AreTextBoxesEnabledProperty = DependencyProperty.Register(
"AreTextBoxesEnabled",
typeof(bool),
typeof(MyUserControl));
public bool AreTextBoxesEnabled
{
get { return (bool)GetValue(AreTextBoxesEnabledProperty); }
set { SetValue(AreTextBoxesEnabledProperty, value); }
}
Just calling AreTextBoxesEnabled = true; will make all the textboxes enabled.
Of course, there are many many other ways. But this is the basic way (without MVVM) of doing it, by harnessing the power of binding.
Simple solution (but not recommended) way is as simple as:
for (i = 0; i < 19; i++)
{
var tb = this.FindName("textBox" + i.ToString()) as TextBox;
if (tb != null) tb.IsEnabled = true;
}
Create a list of text boxes like:
var textBoxes = new List<TextBox>();
// Btw, I don't have a compiler by hand, I assume the type is TextBox.
Fill textBoxes:
textBoxes.Add(textBox1);
textBoxes.Add(textBox2);
...
textBoxes.Add(textBox18);
This is a one-time manual action to fill it. Afterwards you can loop through them:
foreach (var textBox in textBoxes)
{
textBox.IsVisible = true;
}
Or use any other setting/algorithm on the text boxes with the foreach loop (or for, linq etc).
I have a little problem. I have 3 states for a togglebutton - two checked and one unchecked, but it is always checked. I don't know why.
XAML:
<ToggleButton Grid.Row="0" Grid.Column="1" Style="{DynamicResource MetroCircleToggleButtonStyle}" IsChecked="{Binding Path=RepeatChecked}" Command="{Binding Path=RepeatCommand}">
<Image Source="../Ressources/repeat.png"></Image>
</ToggleButton>
C#:
private void RepeatFunction()
{
if (!this.RepeatChecked)
{
Console.WriteLine("Not checked");
this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ONE;
}
else if (this.RepeatChecked && this.stateRepeat == StateRepeat.ONE)
{
Console.WriteLine("Not checked - 2");
this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ALL;
}
else if (this.RepeatChecked)
{
Console.WriteLine("Checked");
this.RepeatChecked = false;
this.stateRepeat = StateRepeat.NONE;
}
}
The console write is always Checked. I really don't understand.
EDIT:
this.stateRepeat = StateRepear.NONE;
this.RepeatCommand = new CommandProvider(obj => RepeatFunction());
The problem is that on click of toggle button, you always set the RepeatChecked to false/true which is bind to IsChecked which updates toggle state sets unchecked/checked again; so checked changes to unchecked and unchecked changes to check. Comment the line in all three conditions and run the flow and you will see all conditions working.
private void RepeatFunction()
{
if (!this.RepeatChecked)
{
Console.WriteLine("Not checked");
////this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ONE;
}
else if (this.RepeatChecked && this.stateRepeat == StateRepeat.ONE)
{
Console.WriteLine("Not checked - 2");
////this.RepeatChecked = true;
this.stateRepeat = StateRepeat.ALL;
}
else if (this.RepeatChecked)
{
Console.WriteLine("Checked");
////this.RepeatChecked = false;
this.stateRepeat = StateRepeat.NONE;
}
}
I am using a RadGridView to display some string data in a column. I am using databinding. Some of my text strings have portions of the text encased with {} and I would like to display this text in a different color.
From looking around on the net I have found that I can change text color of text in a text block but Im having trouble applying this to a databound datagrid column.
Could anyone advise if this is possible.
---EDIT---
Heres xaml where I define datacolumn:
<telerik:GridViewDataColumn x:Name="colMasterValue" Header="Localise - Master Value" DataMemberBinding="{Binding MasterValue}" ShowDistinctFilters="False" IsReadOnly="True"/>
Heres the display:
So what I want is {Customer.Panel.field} to appear in a different color.
Let's try the next solution.
Will use a custom TextBlock that can separate regular character and the '{' or '}'.
Let's add the replace mechanism that can replace the original text with decorated text. Where all text except the '{' or '}' colored in some way.
Here is the xaml code:
<telerik:GridViewDataColumn DataMemberBinding="{Binding Path=Text}"
Header="HeaderName"
IsFilterable="False" IsReorderable="False">
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate DataType="flowConfiguration:SomeDataType">
<modules:MyTextBlock Text="{Binding Text,
UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
Here is the MyTextBlock code
public class MyTextBlock:TextBlock
{
private DependencyPropertyDescriptor _descriptor;
private bool _isUpdating;
public MyTextBlock()
{
this.Unloaded += OnUnloaded;
_descriptor = DependencyPropertyDescriptor.FromProperty(TextProperty, typeof(TextBlock));
_descriptor.AddValueChanged(this, OnValueChanged);
}
private void OnValueChanged(object sender, EventArgs eventArgs)
{
if(_isUpdating) return;
_isUpdating = true;
var text = Text;
if(string.IsNullOrEmpty(text)) return;
Inlines.Clear();
UpdateInlines(text);
_isUpdating = false;
}
private void UpdateInlines(string text)
{
//text = #"{Customer.Panel.field}";
var runs = new List<Run>();
var sb = new StringBuilder();
foreach (var current in text)
{
if (current.Equals('}') || current.Equals('{'))
{
if (sb.Length == 0)
{
runs.Add(new Run
{
Text = current.ToString()
});
}
else
{
runs.Add(new Run
{
Text = sb.ToString(),
Foreground = Brushes.Red
});
runs.Add(new Run
{
Text = current.ToString()
});
sb.Clear();
}
}
else
{
sb.Append(current);
}
}
if(sb.Length > 0)
runs.Add(new Run{Text = sb.ToString(), Foreground = Brushes.Red});
runs.ForEach(run =>
Inlines.Add(run));
}
private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
this.Unloaded -= OnUnloaded;
_descriptor.RemoveValueChanged(this, OnValueChanged);
}
}
regards.
I have this XAML for acolumn into DataGrid
<DataGridTemplateColumn Header="% Deduccion Anticipo">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding NumPorcentajeAnticipo, Mode=TwoWay, StringFormat={}{0:00.}%}" Visibility="{Binding Merlin_ConceptosFacturacion.BitOtrosItms_Anticipos,Converter={StaticResource boolToVisibility}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding NumPorcentajeAnticipo, Mode=TwoWay,StringFormat={}{0:00.}%}" Visibility="{Binding Merlin_ConceptosFacturacion.BitOtrosItms_Anticipos,Converter={StaticResource boolToVisibility}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The Stringformat applys as i expect, but muy problem is the user can fill it with any char alpha, number symbol, how can i do to prevent it, it is posible set an inputmask ?
I'm was trying with another StringFormats but any one of them work as I expect.
UPDATE: The column is currently binded to a Numeric property of my view model.
You can use the KeyDown event of a TextBox to intercept and filter out invalid values. You could even create your own derived TextBox and override OnKeyDown for a better encapsulated solution.
None of the built-in controls have the ability to specify an input mask. But, there are masked input controls out there on the internet for WPF. We are using the Telerik Rad Controls for WPF package and it has such a control. I use it in my application and it works very well.
you can achieve your requirement by using following methods.
Put the masked textbox in CellEditingTemplate and set the mask in that masked textbox.
Create the custom render based on your requirement and bind to the CellEditingTemplate.
After some research found this on another question:
Numeric Data Entry in WPF And #Brian Hinchey answer match with some of my needs.
Just add by myself some Culture validations for decimal numbers plus some editing and validation tools. Hope this help somebody else.
To use it:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<controls:NumericTextBox DecimalPlaces="2" DecimalSeparator="."/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
If no decimal places or separator are provided, it take CultureInfo.CurrentCulture parms
Here is the final code:
public class NumericTextBox : TextBox
{
#region Formato
private string previousText = "";
private bool ApplyingFormat = false;
private CultureInfo _CI = new CultureInfo(CultureInfo.CurrentCulture.LCID,true);
public CultureInfo CI
{
get { return _CI; }
set { _CI = value; }
}
private int _DecimalPlaces = 0;
/// <summary>
/// Numero de plazas decimales
/// </summary>
public int DecimalPlaces
{
get { return _DecimalPlaces; }
set { _DecimalPlaces = value; _CI.NumberFormat.NumberDecimalDigits = value; }
}
public Decimal DecimalValue = 0;
private string _DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
public string DecimalSeparator
{
get { return _DecimalSeparator; }
set { _DecimalSeparator = value; _CI.NumberFormat.NumberDecimalSeparator = _DecimalSeparator; }
}
//public string DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
#endregion
public NumericTextBox()
{
HorizontalContentAlignment = HorizontalAlignment.Right;
DataObject.AddPastingHandler(this, OnPaste);
}
private void OnPaste(object sender, DataObjectPastingEventArgs dataObjectPastingEventArgs)
{
var isText = dataObjectPastingEventArgs.SourceDataObject.GetDataPresent(System.Windows.DataFormats.Text, true);
if (isText)
{
var text = dataObjectPastingEventArgs.SourceDataObject.GetData(DataFormats.Text) as string;
if (IsTextValid(text))
{
return;
}
}
dataObjectPastingEventArgs.CancelCommand();
}
private bool IsTextValid(string enteredText)
{
// If keyboard insert key is in toggled mode, and the actual insert point is Decimalseparator, we must avoid to overwrite it
if (SelectionStart == this.Text.IndexOf(DecimalSeparator)
& System.Windows.Input.Keyboard.GetKeyStates(System.Windows.Input.Key.Insert) == System.Windows.Input.KeyStates.Toggled)
{
SelectionStart += 1;
}
if (!enteredText.All(c => Char.IsNumber(c) || c == DecimalSeparator.ToCharArray()[0] || c == '-'))
{
return false;
}
//We only validation against unselected text since the selected text will be replaced by the entered text
var unselectedText = this.Text.Remove(SelectionStart, SelectionLength);
if ( enteredText == DecimalSeparator && unselectedText.Contains(DecimalSeparator))
{
// Before return false, must move cursor beside Decimal separator
SelectionStart = this.Text.IndexOf(DecimalSeparator) + 1;
return false;
}
if (enteredText == "-" && unselectedText.Length > 0)
{
return false;
}
return true;
}
private bool ApplyFormat(TextChangedEventArgs e)
{
if (!ApplyingFormat)
{
ApplyingFormat = true;
int SelectionStartActual = SelectionStart;
string FinallText = this.Text;
if (!FinallText.Contains(DecimalSeparator) & DecimalPlaces > 0)
{
FinallText = String.Format("{0}{1}{2}", this.Text, DecimalSeparator, new string('0', DecimalPlaces));
}
bool state = Decimal.TryParse(FinallText, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint | NumberStyles.AllowTrailingSign, _CI, out DecimalValue);
DecimalValue = Math.Round(DecimalValue, DecimalPlaces);
if (DecimalValue == 0)
{
FinallText = "";
}
else
{
if (FinallText != DecimalValue.ToString(_CI))
{
FinallText = DecimalValue.ToString(_CI);
}
}
if (FinallText != this.Text)
{
this.Text = FinallText;
SelectionStart = SelectionStartActual;
}
previousText = this.Text;
ApplyingFormat = false;
return state;
}
else
{
return true;
}
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
e.Handled = !ApplyFormat(e);
base.OnTextChanged(e);
}
protected override void OnPreviewTextInput(System.Windows.Input.TextCompositionEventArgs e)
{
e.Handled = !IsTextValid(e.Text);
base.OnPreviewTextInput(e);
}
}
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.