This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Validation in textbox in WPF
I am currently using this code to create a numeric only textbox
Xaml
<TextBox Height="22" HorizontalAlignment="Left" Margin="192,118,0,0" Name="Unit_ID" VerticalAlignment="Top" Width="173" PreviewTextInput="UnitID_PreviewTextInput" TextInput="Unit_ID_TextInput" TextChanged="Unit_ID_TextChanged" />
and the C# codebehind
private void UnitID_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
foreach (char c in e.Text)
if (!Char.IsDigit(c))
{
e.Handled = true;
break;
}
is is possible to do this by using XAML EXCLUSIVELY?i am trying to minimize my .cs file
If you bind the value of the TextBox's Text attribute to an int, you'll get a sort of validation, in as much as you won't be able to set the value of MyInt to anything other than an int (and the TextBox border will go red if you try).
In the XAML:
<TextBox Text="{Binding MyInt}"/>
In the presenter:
public class MyPresenter : INotifyPropertyChanged
{
public int MyInt { get; set; }
// ...
}
and set the DataContext of the XAML to an instance of MyPresenter.
Just like you can't use pure HTML to get this done, you can't use XAML exclusively (to my knowledge). I get the whole "less is more" philosophy, but in this case you'll need at least SOME code, e.g. Regex, to validate the input.
Related
googling for this showed me that this is often a problem but never reallay solved.
I do have an App/Prgramm in C#, i'll try to be mvvm conform.
I do have an window, in it a UserControl show different views.
One of my view contains a textbox, the text of the textbox is bound to a proptery of the VM.
My textbox got 2 inputbindings, for "enter" and "return" - both leading to same command.
On hitting "enter" the value of the textbox should be processed, the textbox shoud be cleared and refocused ... This works .... One Time ....
Clearing the textbox with String.Empty breaks the Bindings ... this could be found in several postings here ... the most Solution is textboxname.clear() ...
But i dont have the "textboxname" in the viewmodel, only in code-behind, but all my logic is in the VM ... So can somebody pls help me sort things out, how i could clear the textbox without breaking the bindings to input text and hit enter more then one time ?
My Code
<TextBox x:Name="tb_checkinbox" Grid.Row="0" Grid.Column="1" Width="200" Height="25" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding CheckInNumber}">
<TextBox.InputBindings>
<KeyBinding Command="{Binding OnCheckInEnterCommand}" Key="Return"/>
<KeyBinding Command="{Binding OnCheckInEnterCommand}" Key="Enter"/>
</TextBox.InputBindings>
</TextBox>
public CheckinVM()
{
OnCheckInEnterCommand = new RelayCommand(OnCheckInEnter, CanCheckInEnter);
}
private string _checkInNumber;
public string CheckInNumber
{
get { return _checkInNumber; }
set { SetProperty(ref _checkInNumber, value); }
}
public ICommand OnCheckInEnterCommand { get; set; }
public void OnCheckInEnter(object value)
{
CheckInNumber = String.Empty;
/// More to do
}
public bool CanCheckInEnter(object value)
{
return true;
}
The assignment
CheckInNumber = string.Empty;
does not "clear" any Binding. Your conclusion is wrong.
You do however only get empty strings - after clearing - in the setter of the CheckInNumber property. In order to get property updates not only when the TextBox loses focus or you reset the source property, set UpdateSourceTrigger=PropertyChanged on the Text Binding:
<TextBox ... Text="{Binding CheckInNumber, UpdateSourceTrigger=PropertyChanged}">
I am having issues with a ComboBoxselecting the first entered character, which then causes the a problem where the second entered character overwrites the first one.
EDIT: A small explanation of what I an trying to do.
I have set up the ComboBox to act as an autocomplete control. When I enter a character, I am using CollectionView class to filter any names that match each entered character. Upon entered text the ComboBox drop down menu needs to open up, which is why I am binding to IsDropDownOpen. This is how it is supposed to look here.
This is beyond me, I can't research what I need to do to stop this behavior.
Here is a screen shot of what I mean.
This is the ComboBox XAML:
<ComboBox Style="{StaticResource ComboBoxToggleHidden}"
DisplayMemberPath="FullName" SelectedValuePath="Key"
IsTextSearchEnabled="False"
IsEditable="True"
StaysOpenOnEdit="True"
Text="{Binding Path=EnteredText, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Path=Employees}"
SelectedItem="{Binding UpdateSourceTrigger=PropertyChanged, Path=SelectedEmployee}"
IsDropDownOpen="{Binding IsDropDown}">
</ComboBox>
EDIT: I have narrowed it down to this, IsDropDown = true;, commenting this out fixes the issue. But I need the drop down when editing the ComboBox
In the EnteredText property
private string _enteredText;
public string EnteredText
{
get { return _enteredText; }
set
{
_enteredText = value;
Filter(value);
IsDropDown = true;
OnPropertyChanged();
}
}
public bool IsDropDown { get; set; }
OK, I solved this doing a hack, but it will have to do until I can figure out why this behavior is happening.
I created an KeyUpEvent Event in the constructor,
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.KeyUpEvent,
new RoutedEventHandler(DeselectText));
Then in the Handler I just deselected the text.
private void DeselectText(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox == null) return;
if (textBox.Text.Length >= 2) return;
textBox.SelectionLength = 0;
textBox.SelectionStart = 1;
}
I know this is a hack, but I have no choice until the correct solution is posted.
This is how it looks with the hack.
Consider this as another solution. It mights resove the side effect of above mentioned problem.
I am expecting the TemplateChild to have the Name (PART_EditableTextBox). If you are changing the name in the Template then please do the necessary changes here as well.
private TextBox EditableTextBox => (TextBox)GetTemplateChild("PART_EditableTextBox");
protected override void OnDropDownOpened(EventArgs e)
{
EditableTextBox.Select(Text.Length, 0);
base.OnDropDownOpened(e);
}
I am new to WPF(4.0) and I am trying to make a simple form with some TEXTBOX and a SUBMIT BUTTON.
when user click on the submit Button and the program checks if all Textboxs filled, if not, the unfilled Textbox will surrounded by a "Red Border".
<StackPanel>
<Border Padding>
<StackPanel Orientation="Horizontal">
<TextBox Name="name_textbox"/>
</StackPanel>
</Border>
<Border>
<StackPanel>
<Button HorizontalAlignment="Center" Margin="0">Submit</Button>
</StackPanel>
</Border>
</StackPanel>
I read and I am trying to understand the following as well as some other documents and stack overflow posts and I found there are lots of things and terms that i could not understand.
https://www.codeproject.com/Articles/15239/Validation-in-Windows-Presentation-Foundation#welcome
https://www.codeproject.com/Articles/140620/WPF-Tutorial-Dependency-Property
My QUESTION is:
I think there are something to do with data binding validation, and apart from that what else should I need to know?
or are there any good resources recommend or quick examples?
I am lost and hope someone could help, thanks!
This is part of a class that i write to check validation after an element losts focus.
add FocusAdvancement in your window and set ValidationOnLostFocus to true. and add your custom validation in textbox ValidationRules.
public static class FocusAdvancement
{
public static readonly DependencyProperty ValidationOnLostFocusProperty=
DependencyProperty.RegisterAttached ("ValidationOnLostFocus",typeof (bool),typeof (FocusAdvancement),new UIPropertyMetadata (OnValidationOnLostFocusPropertyChanged));
public static bool GetValidationOnLostFocusProperty(DependencyObject d)
{
return (bool)d.GetValue (ValidationOnLostFocusProperty);
}
public static void SetValidationOnLostFocusProperty(DependencyObject d,bool value)
{
d.SetValue (ValidationOnLostFocusProperty,value);
}
private static void OnValidationOnLostFocusPropertyChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
{
var element=(UIElement)d;
if (element==null)
return;
if ((bool)e.NewValue)
{
element.LostFocus+=LostFocus;
}
else
element.GotFocus-=LostFocus;
}
private static void LostFocus(object sender,RoutedEventArgs e)
{
var element=(UIElement)sender;
if (element!=null)
{
TextBox oTextBox=(TextBox)element;
oTextBox.GetBindingExpression (TextBox.TextProperty).UpdateSource ();
}
}
I've been looking around but I haven't been able to find anything on this. I am trying to get started making Windows 8.1 apps in C# with Visual Studio 2013 Pro. I want to be able to access multiple elements (particularly buttons or text blocks) in an array because this is more convenient for developing things like board games. For instance, if I were developing tic-tac-toe, I might use a series of buttons like this:
<Grid>
<Button Name="Cell00"/>
<Button Name="Cell01"/>
<Button Name="Cell02"/>
<Button Name="Cell10"/>
<Button Name="Cell11"/>
<Button Name="Cell12"/>
<Button Name="Cell20"/>
<Button Name="Cell21"/>
<Button Name="Cell22"/>
<Grid/>
Now for the function that would check for a win, I would have to check all possible combinations like this is in the code behind:
private bool CheckForWin()
{
if((Cell00 == Cell01) && (Cell01 == Cell02) && isNotBlank(Cell02)) return true;
if((Cell10 == Cell11) && (Cell11 == Cell12) && isNotBlank(Cell12)) return true
...
return false; //if none of the win conditions pass
}
This type of code would be extremely cumbersome. I would like to write it instead in a way that lets me check the array with for loops.
I realize that with tic-tac-toe, it is fairly easy to code it using brute force, but this was the first example that came to my head. Other games like Reversi or Go would not work well like this because of either the sheer size or the fact that pieces placed can change other cells than the one they were placed on.
Any help with this would be greatly appreciated.
This is not the correct way to use WPF. WPF is designed to use data binding....creating and manipulating UI elements directly is bad form. There are more posts/discussion/questions about this than you can imagine and I'll leave you to research them for yourself. In the mean time this is how you use WPF "properly":
First use NuGet to add MVVM lite to your project so that you get the ViewModelBase class and create a view model for a single cell:
public class Cell : ViewModelBase
{
private string _Text;
public string Text
{
get { return _Text; }
set { _Text = value; RaisePropertyChanged(() => this.Text); }
}
}
One level up you'll want a main model to encapsulate an array of these, this is where you will typically do all your game logic:
public class MainModel : ViewModelBase
{
private ObservableCollection<Cell> _Cells;
public ObservableCollection<Cell> Cells
{
get { return _Cells; }
set { _Cells = value; RaisePropertyChanged(() => this.Cells); }
}
public MainModel()
{
this.Cells = new ObservableCollection<Cell>(
Enumerable.Range(1, 100)
.Select(i => new Cell { Text = i.ToString() })
);
}
}
Notice that all I'm doing at the moment is creating a 100-element collection of cells. This main view model becomes the one that you assign to your window's data context:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainModel();
}
Now your XAML controls need to bind to this data. ItemsControl is used to render a collection of elements so use one of those and bind it to your array. You want them displayed in a 2D grid so replace the ItemsPanelTemplate with a WrapPanel. Finally add a DataTemplate for your Cell class so that a button gets drawn for each cell:
<Window.Resources>
<DataTemplate DataType="{x:Type local:Cell}">
<Button Width="32" Height="32" Content="{Binding Text}"/>
</DataTemplate>
</Window.Resources>
<ItemsControl ItemsSource="{Binding Cells}" Width="320" Height="320" HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
That's how you use WPF. Your logic is stored entirely in the view model and it's completely decoupled from the view. Here's what this particular code displays, it should be pretty self-evident how flexible this code is and easy to change:
That's very possible. Simply declare an array variable :
private Button[] _buttonArray;
populate the array once, maybe in constructor :
_buttonArray = new[] {Cell00, Cell01, .... , Cell22};
And all of the buttons are now accessible through _buttonArray.
I am working on a textbox and combobox in my wpf app. I am sorry for weird title. Well here is the scenario:
Xaml:
<ComboBox ItemsSource="{Binding PortModeList}" SelectedItem="{Binding SelectedPortModeList, Mode=OneWayToSource}" SelectedIndex="0" Name="PortModeCombo" />
<TextBox Grid.Column="1" Text="{Binding OversampleRateBox}" Name="HBFilterOversampleBox" />
ViewModel Class:
public ObservableCollection<string> PortModeList
{
get { return _PortModeList; }
set
{
_PortModeList = value;
OnPropertyChanged("PortModeList");
}
}
private string _selectedPortModeList;
public string SelectedPortModeList
{
get { return _selectedPortModeList; }
set
{
_selectedPortModeList = value;
OnPropertyChanged("SelectedPortModeList");
}
}
private string _OversampleRateBox;
public string OversampleRateBox
{
get
{
return _OversampleRateBox;
}
set
{
_OversampleRateBox = value;
OnPropertyChanged("OversampleRateBox");
}
}
Here I have three requirements:
By using SelectedIdin xaml I am able to select the id but I want to set the selectedid of my combobox from viewmodel class. I.e.
int portorder = 2
PortModeList->SetSelectedId(portOrder). How can I do something like this? or is their any other approach?
I need to restrict number of entries inside a textbox to 4. I.e. 1234 is entered in textbox, it should not let user exceed 4 digits.
I want to set the format of text in OversampleRateBox as: 0x__. I.e. if user wants to enter 23 present in a variable, then I shud set text as 0x23. Basically 0x should be present at the beginning.
Please help :)
I would use the SelectedItem property of the ComboBox (as you are doing), but make the binding two-way. Then, you can set your SelectedPortModeList (which should be called SelectedPortMode) in your view model.
<ComboBox ItemsSource="{Binding PortModeList}"
SelectedItem="{Binding SelectedPortMode}" ...
In the view model:
// Select first port mode
this.SelectedPortMode = this.PortModeList[0];
If you want to limit the number of characters in a TextBox, then use the MaxLength property:
<TextBox MaxLength="4" ... />
If you wish to add a prefix to the OversampleRateBox, one option would be to test for the presence of this in the setter for OversampleRateBox, and if it's not there, then add it before assigning to your private field.
Update
Bind your TextBox to a string property:
<TextBox Grid.Column="1" Text="{Binding OversampleRateBox}" ... />
In the setter for your property, check that the input is valid before setting your private field:
public string OversampleRateBox
{
get
{
return _OversampleRateBox;
}
set
{
// You could use more sophisticated validation here, for example a regular expression
if (value.StartsWith("0x"))
{
_OversampleRateBox = value;
}
// Now if the value entered is not valid, then the text box will be refreshed with the old (valid) value
OnPropertyChanged("OversampleRateBox");
}
}
Because the binding is two-way, you can also set the value from your view model code (for example in the view model constructor):
this.OversampleRateBox = "0x1F";