How can I turn off default validation in WPF? - wpf

It seems that WPF has some validation rule which is turned on by default. When I enter non numeric text into the bound textbox and tab out it, a read border shows around it. What is going on here? I Have set ValidatesOnExceptions to false, where is the validation rule coming from? I am using version 4.5.2 of the .Net framework.
Here is my XAML
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication2"
mc:Ignorable="d"
Title="MainWindow" Height="159.206" Width="193.953">
<Grid>
<TextBox x:Name="textBox" Height="23" HorizontalAlignment="Left" VerticalAlignment="Top" TextWrapping="Wrap"
Text="{Binding Foo, ValidatesOnExceptions=False, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
Width="91" Margin="10,10,0,0"/>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="10,48,0,0"
TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="91"/>
</Grid>
</Window>
Here is the code behind
namespace WpfApplication2
{
public partial class MainWindow : Window
{
public int Foo { get; set; } = 42;
public MainWindow()
{
InitializeComponent();
}
}
}

You can never set an int property to anything else than a valid int value.
This "validation", or rather type-safety feature of the programming language, cannot be turned off.
You can however get rid of or customize the the default error template if you want to. Just set the Validation.ErrorTemplate property to an emoty ControlTemplate:
<TextBox x:Name="textBox" Height="23" HorizontalAlignment="Left" VerticalAlignment="Top" TextWrapping="Wrap"
Text="{Binding Foo, ValidatesOnExceptions=False, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
Width="91" Margin="10,10,0,0">
<Validation.ErrorTemplate>
<ControlTemplate />
</Validation.ErrorTemplate>
</TextBox>

On app startup, you can add this call to FrameworkCompatibiltyPreferences to disable all textboxes from messing with your input:
class App
{
[STAThread]
public static void Main(params string[] args)
{    
System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;
Application app = new Application();
app.Run(new Window1());
}
}
If you're using data binding, it appears that the textboxes will still protect against invalid input. A validation error will be shown (default being the red border) and the view model property will not be set with the invalid value. But now you can input whatever string you want. Makes entering decimal values bound to float or double properties MUCH easier.

Related

Self DataContext binding not working in XAML but working in code behind

When I am trying to bind Datacontext of Window by DataContext="{Binding RelativeSource={RelativeSource Self}}" it is not working, how if I do the same thing in code-behind, it is working quite fine.
Am I wrong in assuming that
is same as
this.DataContext=this
in constructor of the window in code-behind.
Full Code of XAML is...
<Window x:Class="SampleDemoListBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SampleDemoListBox"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
<Window.Resources>
<DataTemplate x:Key="ModelItemTemplate" >
<StackPanel Margin="25" Orientation="Horizontal">
<Image VerticalAlignment="Top" x:Name="ModelPicture" Width="150"
Source="{Binding PicturePath}"></Image>
<Grid VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label VerticalAlignment="Center" FontWeight="Bold" Content="Name:" Grid.Row="0" Grid.Column="0"></Label>
<Label VerticalAlignment="Center" FontWeight="Bold" Grid.Row="1" Grid.Column="0" Content="LastName:"></Label>
<Label VerticalAlignment="Center" FontWeight="Bold" Grid.Row="2" Grid.Column="0" Content="Age:"></Label>
<TextBlock VerticalAlignment="Center" Grid.Row="0" Grid.Column="1" x:Name="Name" Width="120" Text="{Binding Name}" ></TextBlock>
<TextBlock VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" x:Name="LastName" Width="120" Text="{Binding LastName}" ></TextBlock>
<TextBox VerticalAlignment="Center" Grid.Row="2" Grid.Column="1" x:Name="Age" Width="120" Text="{Binding Age}" ></TextBox>
</Grid>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<StackPanel>
<ListBox x:Name="LstModels" Margin="25" ItemsSource="{Binding
Models}" ItemTemplate="{Binding Source={StaticResource
ModelItemTemplate}}"></ListBox>
<Button Width="120" Height="40" Click="AddModel_OnClick"
Content="Add Model" ></Button>
</StackPanel>
</Grid>
</Window>
And Code-behind is...
public partial class MainWindow : Window
{
public ObservableCollection<Model> Models{ get; set; }
public MainWindow()
{
InitializeComponent();
Models= new ObservableCollection<Model> { new Model{ Name =
"Shabana", LastName = "Parveen", Age = 35, PicturePath =
#"Images\pic.bmp" },
new Model { Name = "Ada", LastName = "Lovelace", Age = 37,
PicturePath = #"Images\AdaLovelace.bmp" }};
// this.DataContext = this;
}
}
The behaviour you are observing is due to the order in which you Initialize the View and instantiate the ObservableCollection.
When you assign the DataContext in XAML, all your XAML is parsed when you call InitilizeComponent() in the constructor. The issue is: at the time that your XAML is being parsed, Models is still null as it is instantiated AFTER you call InitilizeComponent(). For this reason, all bindings fail as the collection you're binding to is null when the Binding are evaluated (which happens as xaml is being parsed). When you do instantiate Models, the View is not aware of this, as you have not implemented any notification mechanism.
On the other hand, when you assign the DataContext in the code behind, you do it AFTER all the XAML has been parsed, which forces the View to evaluate the Bindings at the time of assignment...thus it works.
There at at least 3 solutions to this I can think of:
Change the order of initialization
As Andy suggested in his answer, if you first instantiate the Models collection and then call InitilizeComponent(), it will work. As XAML is being parsed, the View will have a non-null DataContext, so all data will propagate to your View via Bindings.
Implement the INotifyPropertyChanged interface.
What this will do is allow you to instantiate Models whenever it is convenient, then Raise the PropertyChanged event to notify the view. This will work just as well. But if you're going to this much trouble, you should really be looking at using the MVVM pattern (lots of tutorials online). I will leave the details of implementation to you as there are countless examples and tutorials out there. Here are a few you can start with:
From SO, nice and to the point
More elaborate explanation here
From WPF Tutorial.net
Make Models a Dependency Property.
If you insist on doing this in the code behind (rather than MVVM), DependencyPropeties will work well. Dependency Properties have their own notification mechanism. Despite being very verbose, they are quite easy to implement. Below is a good source, but you can find lots by just Googling it.
See this article
Your problem is because you have a null observablecollection. If you move your code round, it'll work:
public partial class MainWindow : Window
{
public ObservableCollection<Model> Models{ get; set; }
public MainWindow()
{
Models= new ObservableCollection<Model> { new Model{ Name =
"Shabana", LastName = "Parveen", Age = 35, PicturePath =
#"Images\pic.bmp" },
new Model { Name = "Ada", LastName = "Lovelace", Age = 37,
PicturePath = #"Images\AdaLovelace.bmp" }};
InitializeComponent();
}
}
You should look into using a separate class as a viewmodel and MVVM generally.

Wpf - bestway to register a change on property

Whatsup, I'm new to wpf technology and im having trouble to find out how to popup a message on screen when there is a change on the User property. (Except that, the code works perfect).
*My goal is to register an exsisting event that takes care of it and NOT to do it in the MyData class by rewriting the 'Set'.
xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<StackPanel x:Name="MyGrid1">
<StackPanel.Resources>
<local:MyData x:Key="mySource1"
User="Arik2" />
</StackPanel.Resources>
<TextBox x:Name="target1"
Grid.Row="1"
Grid.Column="2"
Text="{Binding Source={StaticResource mySource1}, Path=User,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="target2"
Grid.Row="2"
Grid.Column="2"
Text="{Binding Source={StaticResource mySource1}, Path=User,Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Window>
Thats my app code:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class MyData
{
public string User { get; set; }
}
}
Thank you all.
For the textboxes you have you can always open a message window in a textchanged event handler.
For example
<TextBox TextChanged="txt_TextChanged" >
Private Sub txt_TextChanged(sender As System.Object, e As System.Windows.Controls.TextChangedEventArgs)
MessageBox.Show("Value changed")
End Sub
Note this is probably what you are looking for but is triggering off the text in the box changing not the property itself. If you use anything like validation and input invalid data this event will fire but the text will not change.
I think you can use the sourcechanged event to get exactly what you want.

How to bind a control's property to a property of the control's element?

I need a digit control to my windows phone app.
I try to create a custom control but I can't bind a property of the control to the control's element.
I had added a dependency property to the control
public static readonly DependencyProperty LineThicknessProperty =
DependencyProperty.Register("LineThickness", typeof (double), typeof (DigitControl), new PropertyMetadata(default(double)));
[DefaultValue(10D)]
public double LineThickness
{
get { return (double) GetValue(LineThicknessProperty); }
set { SetValue(LineThicknessProperty, value); }
}
And have tried to bind it to the control's element
<UserControl x:Class="Library.DigitControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
d:DesignHeight="480" d:DesignWidth="480">
<Grid x:Name="LayoutRoot">
<Rectangle Margin="0" StrokeThickness="0" Width="{Binding LineThickness, RelativeSource={RelativeSource Self}}" Fill="#FFFF5454" RadiusX="5" RadiusY="5"/>
</Grid>
</UserControl>
But it doesn't work. Is where a way to bind that property to the element's property?
Do it in the code behind.
Set a name:
<Rectangle x:Name="theRect" Margin="0" StrokeThickness="0" Fill="#FFFF5454" RadiusX="5" RadiusY="5"/>
Then in code behind:
theRect.SetBinding(Rectangle.WidthProperty, new Binding("LineThickness"){Source = this});
Not at PC with Visual Studio, so applogies if it's not 100% compileable! But gives you the general idea.
What you have done wont work because RelativeSource={RelativeSource Self} sets the source to the target object, which is the Rectangle in your case.
And since rectangle doesn't have a LineThickness property, the binding fails.
To get the right binding you can do several things.
The preferable approach would probably be to set this.DataContext = this; in your UserControl contructor, and then simply set the binding as Width="{Binding LineThickness}" in your XAML.
Or you could target the closest element of type UserControl and find the property on that one, if you don't feel like setting the Datacontext:
Width="{Binding LineThickness, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"
Update
You can also simply give the UserControl a name, and reference it with the ElementName property in the binding:
<UserControl x:Name="uc1" ... </UserControl>
Width="{Binding LineThickness, ElementName=uc1}"

Is it possible to bind code-behind property without setting DataContext?

As titled,
I seen couples of similiar question this or this in SO, but I don't see a solution for it.
I know if I need to bind to the code-beind, I need to set Datacontext = this
But my problem is that my datacontext already binding to my ViewModel, but I want to do some UI manipulation with using Command which is defined in the code-beind.
Is it possbile to bind it in xaml? If so, how?
EDIT: I did tried the follows:
<Window x:Class="WpfApplication3.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" x:Name="_Root">
<Grid x:Name="hellogrid">
<TextBlock x:Name="myTextBlock" Text="AAAA"/>
<Button Margin="82,119,121,120" Name="button2" Content="{Binding Path=Text, ElementName=myTextBlock}"/>
<Button Margin="82,72,121,0" Name="button3" Content="{Binding Path=MyText, ElementName=_Root}" Height="23" VerticalAlignment="Top" />
</Grid>
And code-behind:
public partial class Window1 : Window
{
public string MyText { get; set; }
public Window1()
{
InitializeComponent();
MyText = "ABC";
}
}
I could see the Button2 shows AAAA, but Button3 shows nothing....
Of course
There are many types of bindings. The most basic one binds to a property on the DataContext, which is usually inherited from a Parent object
<DataTemplate DataType="{x:Type MyModel}">
<!-- DataContext is object of type MyModel -->
<local:MyView />
</DataTemplate>
Or
<Window x:Name="MyWindow">
<!-- DataContext Inherited from Window -->
<TextBlock Text="{Binding SomeProperty}" />
</Window>
where
var SomeObject = new SomeModel();
SomeObject.SomeProperty = "Test";
myWindow.DataContext = SomeObject;
Other binding types include ElementName, where you can specify the target UI element to use as the data source for the binding
<StackPanel>
<CheckBox x:Name="SomeCheckBox" />
<TextBlock Text="{Binding ElementName=SomeCheckBox, Path=IsChecked}" />
</StackPanel>
or
<local:MyUserControl x:Name="SomeUserControl">
<Button Command="{Binding ElementName=SomeUserControl, Path=DataContext.SaveCommand}" />
</local:MyUserControl >
Or RelativeSource, which allows you to find an object relative to the current object to use as a DataSource
<Window Title="Test">
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=Title}" />
</Window>
or
<local:MyUserControl>
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:MyUserControl}}, Path=DataContext.SaveCommand}" />
</local:MyUserControl >
And TemplateBinding, which binds is a shortcut to a RelativeSource binding that binds to a templated object
<Button Content="Test">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock Text="{TemplateBinding Content}" />
</ControlTemplate>
</Button.Template>
</Button>
EDIT
The best solution IMO is the one posted by #Saad Imran in this SO question...
With this solution all you have to do is name your window and binding to a property in your XAML will be as easy as this {Binding ElementName=MyWindowName, Path=MyText}
So, what you are doing with Content="{Binding Path=MyText, ElementName=_Root}" is exactly right and your Button Content property IS bound to MyText property but the only thing you are missing is change notification (need to implement INotifyPropertyChanged interface for that) so when you set your MyText property to ABC MyText = "ABC"; no change notification is sent...
Easy way to test this is by setting the MyText property explicitly as such:
private string myText = "ABC";
public string MyText
{
get { return myText; }
set { myText = value; }
}
or setting it in the constructor before InitializeComponent() is called:
MyText = "ABC";
InitializeComponent();
If you do that you'll notice that your button will have ABC as its content but changes to MyText property will not affect the button content because there is no change notification...
Sure, you can use ElementName:
<Window Name="root"
Class="..."
...>
...
<TextBox Text="{Binding Path=Foo, ElementName=root}" />
You could also do it with RelativeSource, but the syntax is uglier...

WPF binding user control with data in C# code

I've create user control like this:
public partial class View
{
public View()
{
InitializeComponent();
}
public static DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(TeaserView) );
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
XAML:
<UserControl x:Class="Controls.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="200" Width="164">
<Grid VerticalAlignment="Stretch"
x:Name="Preview">
<Label Height="28" Content="{Binding ElementName=Preview, Path=Name}" Background="LightYellow" x:Name="name" VerticalAlignment="Top" ></Label>
</Grid>
</UserControl>
and use it in Window1 simply in XAML:
<controls:View Height="200" Name="View1" Width="164" />
and I try set the Content in C# (Name property in this sample) but it does'n work, label's content is still empty. (All refereces, etc. are good) What's wrong?
Your code is wrong. You bind to Grid.Name property, which is "Preview", not to View.Name.
I really encourage you to go read from A to Z "DataBinding Overview" on MSDN. It worth your time, trust me :). In fact whole "Windows Presentation Foundation" section would be worth your attention.
As for your code, the following will work:
<UserControl x:Class="WpfApplication5.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300"
Width="300"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Label Height="28"
Content="{Binding Path=Name}"
Background="LightYellow"
VerticalAlignment="Top"/>
</Grid>
</UserControl>
But are you sure you want to hide "Name" property from parents?
Have you set the datacontext on the user control? Try setting it to point to its own codebehind:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
I've put the Name property just as sample. I'm trying to set Label Content in Window1.xaml.cs like:
View1.Name = "Casablanca";
Try the following binding, it should work:
<Label Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:View}}, Path=Name}" />
You should also define a xmlns:local="whatever_path_you_have" on the top of the file.
I also suggest renaming "Name" DP to something else to avoid name collusion.
Copied your exact code and it works fine.
However, it's not doing what you're probably expecting it to do. You're setting the source of the binding to the Grid instance. Therefore, the Name property will yield "Preview". The Name property you've defined in your UserControl is ignored because there's already a Name property on UserControl.

Resources