How can I add KeyUp event for my UserControl? - xaml

I have a user control that working like WatermarkPasswordBox and I want to add KeyUp event for my user control's PasswordBox's Key Up event. How can I do it?
<UserControl
x:Class="Windows8.StoreApp.Common.CustomControls.WatermarkPasswordTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows8.StoreApp.Common.CustomControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<PasswordBox x:Name="passwordB" GotFocus="PasswordBox_GotFocus" LostFocus="PasswordBox_LostFocus" PasswordChanged="passwordB_PasswordChanged" Style="{StaticResource AkbankControlStyleWatermarkPasswordBoxLoginFormInputPasswordBox}"></PasswordBox>
<TextBlock x:Name="lblWaterMark" Tapped="lblWaterMark_Tapped" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,4,10,4" Opacity="0.8" FontFamily="Segoe UI" FontSize="16" Foreground="#FF8E8E8E" FontWeight="SemiBold"></TextBlock>
</Grid>
public WatermarkPasswordTextBox()
{
this.InitializeComponent();
}
private void PasswordBox_GotFocus(object sender, RoutedEventArgs e)
{
lblWaterMark.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
private void PasswordBox_LostFocus(object sender, RoutedEventArgs e)
{
if ((sender as PasswordBox).Password.Length == 0)
{
lblWaterMark.Visibility = Windows.UI.Xaml.Visibility.Visible;
}
}
private void passwordB_PasswordChanged(object sender, RoutedEventArgs e)
{
if ((sender as PasswordBox).Password.Length != 0)
{
lblWaterMark.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
private void lblWaterMark_Tapped(object sender, TappedRoutedEventArgs e)
{
lblWaterMark.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
passwordB.Focus(Windows.UI.Xaml.FocusState.Pointer);
}
private string _watermark=String.Empty;
public string Watermark
{
get
{
_watermark = lblWaterMark.Text;
return _watermark;
}
set
{
SetProperty<string>(ref _watermark, value, "Watermark");
lblWaterMark.Text = _watermark;
}
}
private int _lenghtMax;
public int LenghtMax
{
get
{
if (passwordB != null)
{
_lenghtMax = passwordB.MaxLength;
return _lenghtMax;
}
else
{
return 0;
}
}
set
{
if (passwordB != null)
{
SetProperty<int>(ref _lenghtMax, value, "LenghtMax");
passwordB.MaxLength = _lenghtMax;
}
}
}
private string _passText = String.Empty;
public string PassText
{
get
{
if (passwordB != null)
{
_passText = passwordB.Password;
return _passText;
}
else
{
return String.Empty;
}
}
set
{
if (passwordB != null)
{
SetProperty<string>(ref _passText, value, "PassText");
passwordB.Password = _passText;
passwordB_PasswordChanged(passwordB, null);
}
else
{
SetProperty<string>(ref _passText, value, "PassText");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I want to use like this;
and this Key_Up will equal to mycontrol's PasswordBox' key up event.
Thanks.

public event KeyEventHandler RelayedKeyUp
{
add
{
passwordB.KeyUp += value;
}
remove
{
passwordB.KeyUp -= value;
}
}

Related

TextChanged Event is not getting fired - MVVM Xamarin Forms

I have a Entry control inside DataTemplate of Bindable StackLayout. I have implemented TextChanged event of Entry control with Behavior but event is not getting fired.
This is xaml code
<Frame Padding="20,14,10,10"
Grid.Column="1"
BorderColor="LightGray">
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding RefreshCommand}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>
</Frame>
Behavior classes in a single file
namespace Product.Helpers
{
public class EventToCommandBehavior : BehaviorBase<VisualElement>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
protected override void OnAttachedTo(VisualElement bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(VisualElement bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null) return;
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name)) return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name) || eventHandler == null)
return;
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null) return;
object resolvedParameter;
resolvedParameter = eventArgs;
if (Command.CanExecute(resolvedParameter))
Command.Execute(resolvedParameter);
}
}
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
BindingContext = bindable.BindingContext;
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
}
ViewModel Code for Command
public ICommand RefreshCommand
{
get
{
return new Command(async (args) =>
{
Refresh();
});
}
}
public void Refresh()
{
var textbox = Subtotal;
}
From here I have take the code csharpcorer - behavior. How can I make it work ?
The reason you are not able to find it is because of the context.
Give your current ContentPage a name :
<ContentPage
...
x:Name="currentPage"/>
Then your Entry would look something like:
<Entry MaxLength="5"
Keyboard="Numeric"
HeightRequest="42">
<Entry.Behaviors>
<helpers:EventToCommandBehavior Command="{Binding BindingContext.RefreshCommand, Source={x:Reference currentPage}}"
EventName="TextChanged"></helpers:EventToCommandBehavior>
</Entry.Behaviors>
</Entry>

display picker when clicking in imagebutton xamarin

i want to display a picker (or list) when i click in my imageButton but it didn't work, but when i create only a picker , it worked.
Xaml
<StackLayout Orientation="Horizontal" x:Name="stacklayout">
<Entry Placeholder="préciser l'entité correspondante"
ClearButtonVisibility="WhileEditing" x:Name="entit"/>
<ImageButton Source="list.png" WidthRequest="30" HeightRequest="30" x:Name="listEntité" Clicked="listEntité_Clicked"/>
Xaml.cs
private void listEntité_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://192.168.1.3:3000/api/adepApi/GetCurrencyLists");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await httpClient.GetAsync("http://192.168.1.3:3000/api/adepApi/GetCurrencyLists");
var content = await response.Content.ReadAsStringAsync();
ResponseDataD EL = JsonConvert.DeserializeObject<ResponseDataD>(content);
p.ItemsSource= EL.Data.DeviseList;
stacklayout.Children.Add(p.ItemsSource);
}
class DeviseModel
public class DeviseModel
{
public class DeviseL
{
// public string devis;
[JsonProperty("Label")]
public string Devis { get; set; }
[JsonProperty("Value")]
public int id { get; set; }
}
public class ResponseDataD
{
public RootModelDevise Data;
}
public class RootModelDevise : INotifyPropertyChanged
{
List<DeviseL> deviseList;
[JsonProperty("list")]
public List<DeviseL> DeviseList
{
get { return deviseList; }
set
{
if (deviseList != value)
{
deviseList = value;
OnPropertyChanged();
}
}
}
DeviseL itemDevise;
public DeviseL ItemDevise
{
get { return itemDevise; }
set
{
if (itemDevise != value)
{
itemDevise = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}}
i have an error in the line
stacklayout.Children.Add(p.ItemsSource);
under p.itemsSource :unable to convert from 'System.Collections.Ilist' to 'Xamarin.Forms.View'
i have tried to add picker by imageButton click event , but nothing appears.
Firstly, please confirm that the EL.Data.DeviseList have list value, you have list binding to Picker, then adding picker to current contentPage.
public partial class Page16 : ContentPage
{
private List<string> list;
public Page16()
{
InitializeComponent();
list = new List<string>();
list.Add("test 1");
list.Add("test 2");
list.Add("test 3");
list.Add("test 4");
}
private void imagebutton1_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
p.ItemsSource = list;
stacklayout.Children.Add(p);
}
}
<StackLayout x:Name="stacklayout">
<ImageButton
x:Name="imagebutton1"
Clicked="imagebutton1_Clicked"
HeightRequest="30"
Source="plu3.png"
WidthRequest="30" />
</StackLayout>
Update:
private void imagebutton1_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
p.SelectedIndexChanged += P_SelectedIndexChanged;
p.ItemsSource = devs;
p.ItemDisplayBinding = new Binding("Devis");
stacklayout.Children.Add(p);
}
private void P_SelectedIndexChanged(object sender, EventArgs e)
{
Picker p = sender as Picker;
DeviseL selectitem = p.SelectedItem as DeviseL;
entit.Text =selectitem.Devis;
}

How to change when the Data Binding (back to Source) happens in Xamarin Forms?

I have multiple Entry views in my page connecting to a View Model using Data Binding. Everything works as intended except I need to calculate a values as the user enters it.
public decimal DownPayment
{
get => this.loanValues.DownPayment;
set
{
this.loanValues.DownPayment = value;
this.CalculateValues();
}
}
public decimal TradeInPrice
{
get => this.loanValues.TradeInPrice;
set
{
this.loanValues.TradeInPrice = value;
this.CalculateValues();
}
}
// Other properties
Now the problem is the property is set whenever user is entering the value. Is there anyway to change the event on which the Data Binding happens (i.e on Completed instead of TextChanged)?
I see there is UpdateSourceEventName property in XAML binding but I don't know why it doesn't work:
<Entry Placeholder="Down Payment ($)" Text="{Binding DownPayment, UpdateSourceEventName=Completed}" />
UPDATE: The documentation of UpdateSourceEventName says it's For internal use by the Xamarin.Forms platform
You could use EventToCommandBehavior to convert the Event Completed of Entry to Command and handle the logic in ViewModel .
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace App18
{
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
{
BindingContext = bindable.BindingContext;
}
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Windows.Input;
using Xamarin.Forms;
namespace App18
{
public class EventToCommandBehavior : BehaviorBase<View>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IValueConverter Converter
{
get { return (IValueConverter)GetValue(InputConverterProperty); }
set { SetValue(InputConverterProperty, value); }
}
protected override void OnAttachedTo(View bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(View bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
}
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
if (eventHandler == null)
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
}
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null)
{
return;
}
object resolvedParameter;
if (CommandParameter != null)
{
resolvedParameter = CommandParameter;
}
else if (Converter != null)
{
resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
}
else
{
resolvedParameter = eventArgs;
}
if (Command.CanExecute(resolvedParameter))
{
Command.Execute(resolvedParameter);
}
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null)
{
return;
}
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
}
}
}
in xaml
</StackLayout>
<Entry WidthRequest="100" Text="{Binding Value1,Mode=OneWayToSource}" Keyboard="Numeric" >
<Entry.Behaviors>
<local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}" />
</Entry.Behaviors>
</Entry>
<Entry WidthRequest="100" Text="{Binding Value2,Mode=OneWayToSource}" Keyboard="Numeric">
<Entry.Behaviors>
<local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}" />
</Entry.Behaviors>
</Entry>
<Label WidthRequest="100" Text="{Binding Sum}" TextColor="Black" />
</StackLayout>
in ViewModel
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
double value1;
public double Value1
{
get
{
return value1;
}
set
{
if (value1 != value)
{
value1 = value;
NotifyPropertyChanged("Value1");
}
}
}
double value2;
public double Value2
{
get
{
return value2;
}
set
{
if (value2 != value)
{
value2 = value;
NotifyPropertyChanged("Value2");
}
}
}
private string sum;
public string Sum
{
get { return sum; }
set
{
if (sum != value)
{
sum = value;
NotifyPropertyChanged("Sum");
}
}
}
public ICommand CompletedCommand { get; set; }
public MyViewModel()
{
CompletedCommand = new Command(()=> {
Sum = (Value1 + Value2).ToString();
});
}
}

Change of color de my custom enter once is clicked my button

im working with custon entry rendered, i need to hear from xaml in my custom render when i clicked my button
i have this code in my xaml
<local:MyEntry eventRefresh="true">
when i clicked my button this function is actived
private async void Execute(object sender)
{
var entry = ((MyEntry)view);
entry.eventRefresh = "false";
but my EntryRendered donot hear the change
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var element = Element as MyEntry;
You should define the property eventRefresh as Bindable Property .
in your custom Entry
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace xxx
{
public class MyEntry:Entry,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static readonly BindableProperty eventRefreshProperty = BindableProperty.Create("eventRefresh", typeof(bool), typeof(MyEntry), true,propertyChanged:(obj,oldValue,newValue)=> {
//var entry = obj as MyEntry;
// entry.Text = newValue.ToString();
});
bool refresh;
public bool eventRefresh
{
get { return refresh; }
set {
if(refresh !=value)
{
refresh = value;
NotifyPropertyChanged("eventRefresh");
}
}
}
public MyEntry()
{
}
}
}
in xaml
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<local:MyEntry eventRefresh="{Binding Refresh}" BackgroundColor="{Binding BGcolor}" WidthRequest="200" HeightRequest="50" />
<Button Command="{Binding ClickCommand}" />
</StackLayout>
in View Model
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Color color;
public Color BGcolor
{
get { return color; }
set
{
if (color != value)
{
color = value;
NotifyPropertyChanged("BGcolor");
}
}
}
bool refresh;
public bool Refresh
{
get { return refresh; }
set
{
if (refresh != value)
{
refresh = value;
NotifyPropertyChanged("Refresh");
}
}
}
public ICommand ClickCommand { get; set; }
public MyViewModel()
{
BGcolor = Color.LightPink;
ClickCommand = new Command(()=> {
BGcolor = Color.Red;
});
}
}
in Custom Renderer
using System.ComponentModel;
using Android.Content;
using xxx;
using xxx.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly:ExportRenderer(typeof(MyEntry),typeof(NyEntryRenderer))]
namespace xxx.Droid
{
public class NyEntryRenderer : EntryRenderer
{
public NyEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Element.TextChanged += Element_TextChanged;
}
}
private void Element_TextChanged(object sender, TextChangedEventArgs e)
{
// var content = Element.Text;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == MyEntry.BackgroundColorProperty.PropertyName)
{
// will been invoked when click button
}
}
}
}
Make your view model like this.
public class YourViewModel
{
public Command command
{
get
{
return new Command(() => {
//Change here button background colors
BackgroundColor = Color.Green;
});
}
}
private _backgroundColor = Color.White;
public Color BackgroundColor
{
get { return _backgroundColor;}
set
{
if (value == _backgroundColor)
return;
_backgroundColor = value;
NotifyOnPropertyChanged(nameof(BackgroundColor));
}
}
}
Your XAML
<local:MyEntry Text="{Binding Password}" Placeholder="Enter" />
<Button Text="send" Command="{Binding command}" BackgroundColor="{Binding BackgroundColor}"></Button>

How to change the background color of a Silverlight DataGridRow?

I have a Silverlight DataGrid bound to a collection of MyObjects. MyObject has a boolean field called IsHighlighted.
I would like to change the row's background color when this value is true. And to have it changed back if it becomes false.
I already tried by using the Loading_Rowevent (as explained here), but it didn't work for me, as this event is only called once, and my objetcs all have the boolean value set to false at this time (it only becomes truc when another component is selectes; this works, I checked the values).
Anybody has a clue ? Thanks in advance !
Update: I made a test application to illustrate, it reproduces my problem.
<navigation:Page x:Class="AViews.Tests"
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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DesignWidth="640" d:DesignHeight="480"
Title="Tests Page">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<sdk:DataGrid Grid.Row="0" ItemsSource="{Binding AllItems, Mode=TwoWay}" AutoGenerateColumns="False" LoadingRow="DataGrid_LoadingRow">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding Value1}" Header="Value1" />
<sdk:DataGridTextColumn Binding="{Binding Value2}" Header="Value2"/>
<sdk:DataGridCheckBoxColumn Binding="{Binding IsHighlighted}" Header="Is Highlighted" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
<Button Content="Change !" Grid.Row="1" HorizontalAlignment="Left" Click="Button_Click" />
</Grid>
</navigation:Page>
public partial class Tests : Page, INotifyPropertyChanged
{
private SampleConverter bgConverter = new SampleConverter();
Random r = new Random();
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private ObservableCollection<Sample> allItemsField = new ObservableCollection<Sample>();
public ObservableCollection<Sample> AllItems
{
get
{
return this.allItemsField;
}
set
{
if (this.allItemsField != value)
{
this.allItemsField = value;
this.OnPropertyChanged("AllItems");
}
}
}
public Tests()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var tmp = Enumerable.Range(0, 100).Select(f => new Sample(f)).ToList();
foreach (var item in tmp)
{
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
var coll = new ObservableCollection<Sample>(tmp);
this.AllItems = coll;
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.OnPropertyChanged("AllItems");
}
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
Binding b = new Binding("IsHighlighted")
{
Mode = BindingMode.OneWay,
Converter = this.bgConverter,
ValidatesOnExceptions = true
};
e.Row.SetBinding(DataGridRow.BackgroundProperty, b);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
foreach (var item in this.AllItems)
{
item.IsHighlighted = r.Next(1000) % 2 == 0;
}
}
}
public class Sample: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private string value1Field = string.Empty;
public string Value1
{
get
{
return this.value1Field;
}
set
{
if (this.value1Field != value)
{
this.value1Field = value;
this.OnPropertyChanged("Value1");
}
}
}
private string value2Field = string.Empty;
public string Value2
{
get
{
return this.value2Field;
}
set
{
if (this.value2Field != value)
{
this.value2Field = value;
this.OnPropertyChanged("Value2");
}
}
}
private bool isHighlightedField = false;
public bool IsHighlighted
{
get
{
return this.isHighlightedField;
}
set
{
if (this.isHighlightedField != value)
{
this.isHighlightedField = value;
this.OnPropertyChanged("IsHighlighted");
}
}
}
public Sample(int index)
{
this.Value1 = string.Format("Value1 #{0}", index);
this.Value2 = string.Format("Value2 #{0}", index);
}
}
public class SampleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool val = (bool)value;
SolidColorBrush ret = val ? new SolidColorBrush(Colors.Red) : new SolidColorBrush(Colors.Green);
return ret;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And the result can be seen on those pictures:
When I first arrive on the page.
I click the button, which sets some (random) values to true. As you can see, the binding is updated, not the UI.
I use the scrollbar, go to the end, and come back, and Oh! wonderful! All the rows are correctly colored :-(