I have a WPF DataGridCheckBoxColumn, which is bound to an object that implements INotifyPropertyChanged as shown below:
DataGridCheckBoxColumn Binding="{Binding Path=IsSelected}" CellStyle="{StaticResource MyDataGridCheckBoxCellStyle}"/>
Here is the associated object:
public class ListItem : INotifyPropertyChanged
{
public int ID { get; set; }
private bool isSelected = false;
public bool IsSelected { get { return isSelected; } set { isSelected = value; OnChanged("IsSelected"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void OnChanged(string prop)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
Everything works as expected, except that in order to set the Checkbox to Checked, I need to double click, in order to first select the column, and then set the checkbox value.
So, I decide to implement a Style trigger as shown below:
<Style x:Key="MyDataGridCheckBoxCellStyle" TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="IsEditing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
Now I am able to single click to Check the Checkbox, but my binding doesn't work anymore. Any idea of what is going on here? Why does setting the Style Trigger remove the binding?
Changing the style can cause some issues with the default template. You would most likely need to copy the entire style + template and then modify that to suit your needs. You could try this http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing however.
Related
This is my first question so be careful :)
i'm trying to do a binding of the property (a) in the xaml, the foreground color works(so the ref of the datagrid cell is right), but the background not and i'm trying to understand why, if i try to debug my property the program doesnt enter in it....
(a)=
public int CellGiorno1
{
get
{
int a = myfunctionexample(day, Username, month, year);
return a;
//return 0-1-2
}
}
(the column of the datagrid where i want to color the background if the number returned is 1)
DataGridTextColumn Header="2" x:Name="HeaderGG1" Binding={Binding Desc_GG1}" CellStyle="{StaticResource CellStyleGiorno}"/>
(the style with the trigger that color the foreground but not the background)
<Style x:Key="CellStyleGiorno" TargetType="DataGridCell">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding CellGiorno1}" Value="1">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
The first problem here is your get and set methods. Take a look at this structure:
class Name
{
private string _mynam = "";
public string mynam
{
set
{
_mynam = value;
}
get
{
return _mynam;
}
}
}
You don't have the set method and you set the method in the get method.
the property need to have a notification of change structure attached to it to enable binding
this is usually done with INotifyPropertyChanged or DependencyProperty
eg
public class myClass :INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void ChangeCell()
{
PropertyChanged(this,new PropertyChangedEventArgs("CellGiorno1")
}
public int CellGiorno1
{
get
{
int a = myfunctionexample(day, Username, month, year);
return a;
//return 0-1-2
}
}
}
so in this case calling ChangeCell would notify all bindings connected to CellGiorno1 that they need to get the value of CellGiorno1 because its changed
I'm having a TextBox, if the TextBox has the Text.Length >0 then I have to change the HasChar property True otherwise False. Here I can't able to Bind the Property in the Setter.
The XAML Source Code:
<TextBox Text="WPF">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Value="0"
Binding="{Binding Text.Length, RelativeSource={RelativeSource Self}}">
<Setter Property="{Binding HasChar}" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The View Model C# Source Code :
private bool _hasChar= true;
public bool HasChar
{
get { return _hasChar; }
set
{
_hasChar= value;
OnPropertyChanged();
}
}
You're misusing triggers.
The right way to go:
1) XAML:
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
2) view model. You don't need to add setter to HasChar. If this property is bound to something in view, just raise appropriate PropertyChanged:
public class ViewModel : INotifyPropertyChanged
{
// INPC implementation is omitted
public string Text
{
get { return text; }
set
{
if (text != value)
{
text = value;
OnPropertyChanged();
OnPropertyChanged("HasChar");
}
}
}
private string text;
public bool HasChar
{
get { return !string.IsNullOrEmpty(Text); }
}
}
You can not bind a property in the setter. Style is used to set the UI element properties like Text,Visibility,Foreground etc.
I'm having a problem where user input is interrupted by updates from the bound ViewModel.
The ViewModel exposes a numerical value which changes each second. This is bound to a TextBox in the view. We want the TextBox to display this value, which it does well.
However, when the user clicks on the TextBox and tries to enter a new value, the value in the model gets updated which causes the user-entered value in the textbox to be overwritten.
How can I most easily solve this issue, supporting user input and regular updates in the same control? I would appreciate code examples (C# / XAML).
If you need more details just ask :)
When TextBox gets focus (IsFocused property equals true) I change binding type so that it would not be updated unless it looses focus.
ViewModel:
class MainViewModel : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
Debug.WriteLine(value);
OnPropertyChanged();
}
}
public MainViewModel()
{
Task.Factory.StartNew(async () =>
{
for (int i = 0; i < 1000; i++)
{
Name = i.ToString();
await Task.Delay(3000);
}
});
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
XAML:
<StackPanel>
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Text" Value="{Binding Name, Mode=OneWay}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsFocused}" Value="True">
<Setter Property="Text" Value="{Binding Name, Mode=OneWayToSource, UpdateSourceTrigger=LostFocus}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button Content="Click"/>
</StackPanel>
I got sequence 2,3 then I inputed 56 and clicked Button so textbox lost focus and sent value to Name property. Debug printed following sequence:
1
2
3
56
4
I want to bind the Cursor of a Border to a private property of my TemplateInstance.
XAML:
<Border Cursor="{Binding ToggleCursor}">
C#:
private Cursor ToggleCursor {
get {
return IsEnabled ? Cursors.Hand : Cursors.Arrow;
}
}
I have also implemented INotifyPropertyChanged in my TemplateClass:
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string PropertyName) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(PropertyName));
}
}
And of course I notify the framework about the changes:
(Even if I wouldn't do that it should still get the property at least a single time)
IsEnabledChanged += (sender, e) => OnIsEnabledChanged();
and
private void OnIsEnabledChanged() {
OnPropertyChanged("ToggleCursor");
}
And yes, the class implements the interface.
The problem is, that the border never takes the value from the property.
F.e. if I return a Cursors.Cross in the property it still shows the Cursors.Arrow.
Any ideas?
Example:
This is some sort of checkbox with animated behaviour and the blue border recieves the curser binding. Problem solved - Forgot to set datacontext -__-
Regardless of whether you're re-templating an existing control or creating your own, you need a control style and also need to set a control template inside that style.
In the control template you can use a trigger to change things:
<Style TargetType="{x:Type YourCustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type YourCustomControl}">
<Border x:Name="Border">
... other elements, etc ...
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter TargetName="Border" Property="Cursor" Value="Hand" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then you don't need to create a custom property in your control class to do this.
ToggleCursor must be a public property and you need to call OnPropertyChanged("ToggleCursor") whenever the ToggleCursor property value changes (which seems to be related to IsEnabled property changes).
Typically this will be via the overridden OnPropertyChanged method:
private override void OnPropertyChanged(string PropertyName)
{
base.OnPropertyChanged(PropertyName);
switch (PropertyName)
{
case "IsEnabled":
OnPropertyChanged("ToggleCursor");
break;
}
}
Edit:
OP set the ToggleCursor property to public and also assigned the DataContext for TemplateInstance and this solved his issue.
View Model
public class MyViewModel
{
public string MyProperty { get; set; }
}
XAML
<CheckBox IsChecked="{Binding !MyProperty.Equals('Steve')}" />
Is this possible? How?
This sort of thing can be done (and many say should be done) in Xaml without involving logic from the View Model. To see it work, create a View Model like this...
public class ViewModel : INotifyPropertyChanged
{
private string _myProperty;
public string MyProperty
{
[DebuggerStepThrough]
get { return _myProperty; }
[DebuggerStepThrough]
set
{
if (value != _myProperty)
{
_myProperty = value;
OnPropertyChanged("MyProperty");
}
}
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
}
And then bind it to some Xaml that looks like this...
<Grid>
<CheckBox Content="Some check box">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="IsChecked" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding MyProperty}" Value="Steve">
<Setter Property="IsChecked" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</Grid>
This is a standard WPF Checkbox that has been styled with a data trigger. The trigger will set the IsChecked property to true whenever the 'MyProperty' property contains "Steve". Otherwise the CB will be unchecked (per the overriding Setter in the Style). It works because the trigger listens to changes in the VM's 'MyProperty'. So visualization is entirely relegated to the user surface.
Triggers can be combined (and even used with Template Selectors) to access powerful functions built-in to WPF; and they will bind to any dependency property on the Check box, like Background colour etc.
A lot of people will suggest a converter, which certainly works. But I've found a much quicker way is to create a new bool property to use and bind to that:
public string MyProperty{get;set;}
public bool MyPropertyChecked
{
get { return !MyProperty.Equals('Steve')}
}