How to TwoWay bind a UserControl in UWP XAML? (C++/WinRT) - xaml

I am trying to two way bind data inside of a UserControl. The code below works for one way binding, but when I try to use two way binding I get the following error from the xaml compiler:
XamlCompiler error WMC1118: TwoWay binding target 'value_prop' must be a dependency property
However it's very confusing to me because I did make value_prop a dependency property. How can I make this work?
// MainPage.xaml
<local:attribute_slider Label="Scale" value_prop="{x:Bind texture_showcase_vm.current_texture.scale, Mode=TwoWay}"/>
// attribute_slider.xaml
<UserControl
x:Class="wzrd_editor.attribute_slider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:wzrd_editor"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center" >
<TextBlock x:Name="scale_label" Text="{x:Bind Label, Mode=OneWay}" HorizontalAlignment="Left" />
<TextBlock x:Name="scale_text_value" Text="{x:Bind value_prop, Mode=TwoWay}" HorizontalAlignment="Right"
RelativePanel.AlignRightWithPanel="True"
RelativePanel.RightOf="scale_label" />
<Slider x:Name="Scale" Value="{x:Bind value_prop, Mode=TwoWay}" Width="200" Orientation="Horizontal" Minimum="0" Maximum="10" StepFrequency="0.01" TickFrequency="0.01" SnapsTo="StepValues" TickPlacement="None"
RelativePanel.Below="scale_label"
RelativePanel.AlignRightWith="scale_text_value"
RelativePanel.AlignLeftWith="scale_label"
RelativePanel.AlignRightWithPanel="True" />
</StackPanel>
</UserControl>
//attribute_slider.idl
namespace wzrd_editor
{
[bindable]
[default_interface]
runtimeclass attribute_slider : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
attribute_slider();
static Windows.UI.Xaml.DependencyProperty LabelProperty{ get; };
static Windows.UI.Xaml.DependencyProperty value_property{ get; set; };
String Label;
Single value_prop;
}
}
attribute_slider.h
namespace winrt::wzrd_editor::implementation
{
struct attribute_slider : attribute_sliderT<attribute_slider>
{
attribute_slider();
static Windows::UI::Xaml::DependencyProperty LabelProperty();
static Windows::UI::Xaml::DependencyProperty value_property();
static void value_property(Windows::UI::Xaml::DependencyProperty const& value);
hstring Label();
void Label(hstring const& value);
float value_prop();
void value_prop(float const& value);
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
void PropertyChanged(winrt::event_token const& token) noexcept;
private:
static Windows::UI::Xaml::DependencyProperty m_labelProperty;
static Windows::UI::Xaml::DependencyProperty m_value_property;
hstring m_label = L"";
float m_value = 0.0f;
winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_property_changed;
void raise_property_changed(hstring const& property_name)
{
m_property_changed(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs(property_name));
}
template <class T>
void update_value(hstring const& property_name, T & var, T value)
{
if (var != value)
{
var = value;
raise_property_changed(property_name);
}
}
};
}
//attribute_slider.cpp
namespace winrt::wzrd_editor::implementation
{
Windows::UI::Xaml::DependencyProperty attribute_slider::m_labelProperty =
Windows::UI::Xaml::DependencyProperty::Register(
L"Label",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<wzrd_editor::attribute_slider>(),
Windows::UI::Xaml::PropertyMetadata{ nullptr }
);
Windows::UI::Xaml::DependencyProperty attribute_slider::m_value_property =
Windows::UI::Xaml::DependencyProperty::Register(
L"value_prop",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<wzrd_editor::attribute_slider>(),
Windows::UI::Xaml::PropertyMetadata{ nullptr }
);
attribute_slider::attribute_slider()
{
InitializeComponent();
}
hstring attribute_slider::Label()
{
return m_label;
}
void attribute_slider::Label(hstring const& value)
{
update_value(L"Label", m_label, value);
}
float attribute_slider::value_prop()
{
return m_value;
}
void attribute_slider::value_prop(float const& value)
{
update_value(L"value_prop", m_value, value);
}
Windows::UI::Xaml::DependencyProperty attribute_slider::LabelProperty()
{
return m_labelProperty;
}
Windows::UI::Xaml::DependencyProperty attribute_slider::value_property()
{
return m_value_property;
}
void attribute_slider::value_property(Windows::UI::Xaml::DependencyProperty const& value)
{
m_value_property = value;
}
winrt::event_token attribute_slider::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_property_changed.add(handler);
}
void attribute_slider::PropertyChanged(winrt::event_token const& token) noexcept
{
m_property_changed.remove(token);
}
}

Related

How to bind an object to a view programmatically using WinUI3 with C++/WinRT?

I am using WinUI3 with C++/WinRT and I am trying to bind an object like "User" to a collection like "ListViewItem".
Below you can see the xaml and the code behind creating a list view item and the binding part.
XAML:
<StackPanel>
<Button x:Name="button" Click="button_Click" Content="Add" />
<ListView x:Name="listView" />
</StackPanel>
CPP:
class User : public ::winrt::Microsoft::UI::Xaml::Data::INotifyPropertyChanged
{
public:
User() {}
~User() {}
void Name(const ::winrt::hstring& aName) {
if (mName != aName) {
mName = aName;
mPropertyChanged(*this, ::winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{ L"Name" });
}
}
::winrt::hstring Name() {
return mName;
}
::winrt::event_token PropertyChanged(::winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& aHandler) {
return mPropertyChanged.add(aHandler);
}
void PropertyChanged(::winrt::event_token const& aToken) noexcept {
mPropertyChanged.remove(aToken);
}
private:
::winrt::hstring mName = L"NoName";
event<::winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler> mPropertyChanged;
};
::winrt::Microsoft::UI::Xaml::Controls::ListViewItem CreateLVI() {
::winrt::Microsoft::UI::Xaml::Controls::TextBlock myText;
User myDataObject;
::winrt::Microsoft::UI::Xaml::Data::Binding myBinding;
myBinding.Path(::winrt::Microsoft::UI::Xaml::PropertyPath(L"Name"));
myBinding.Source(myDataObject);
::winrt::Microsoft::UI::Xaml::Data::BindingOperations::SetBinding(myText, ::winrt::Microsoft::UI::Xaml::Controls::TextBlock::TextProperty(), myBinding);
::winrt::Microsoft::UI::Xaml::Controls::ListViewItem lvi;
lvi.Content(myText);
return lvi;
}
MainWindow::MainWindow()
{
InitializeComponent();
}
void MainWindow::button_Click(::winrt::Windows::Foundation::IInspectable const& sender, ::winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
listView().Items().Append(CreateLVI());
}
But it doesnt work, the user's name doesnt show in the list view item. The list view item is created tho.

How to two way bind to a UserControl DependencyProperty?

I am making a custom slider called scalar_slider using a UserControl. I would like to two way bind one of it's DependencyProperty.
The problem is that the value changes made inside scalar_slider are not updated back to the parent's view model vm which correctly implements INotifyPropertyChanged. I assume the problem has to do with how I am setting the binding in MainPage.xaml.
// MainPage.xaml
<local:scalar_slider scalar_value="{x:Bind vm.my_scalar_value Mode=TwoWay}" />
// scalar_slider.xaml
<UserControl
x:Class="transformations.scalar_slider"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:transformations"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel>
<TextBox Text="{x:Bind scalar_value, Mode=TwoWay}"/>
<Slider Value="{x:Bind scalar_value, Mode=TwoWay}"/>
</StackPanel>
</UserControl>
//scalar_slider.idl
namespace transformations
{
[default_interface]
runtimeclass scalar_slider : Windows.UI.Xaml.Controls.UserControl, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
scalar_slider();
static Windows.UI.Xaml.DependencyProperty scalar_valueProperty;
Single scalar_value;
}
}
//scalar_slider.h
namespace winrt::transformations::implementation
{
struct scalar_slider : scalar_sliderT<scalar_slider>
{
scalar_slider();
static Windows::UI::Xaml::DependencyProperty scalar_valueProperty();
static void scalar_valueProperty(Windows::UI::Xaml::DependencyProperty value);
float scalar_value();
void scalar_value(float value);
winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
void PropertyChanged(winrt::event_token const& token) noexcept;
template <class T>
void update_value(hstring const& property_name, T & var, T value)
{
if (var != value)
{
var = value;
raise_property_changed(property_name);
}
}
private:
event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_property_changed;
void raise_property_changed(hstring const& property_name)
{
m_property_changed(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs(property_name));
}
static Windows::UI::Xaml::DependencyProperty m_scalar_value_property;
float m_scalar_value = 0.0f;
};
}
//scalar_slider.cpp
namespace winrt::transformations::implementation
{
scalar_slider::scalar_slider()
{
InitializeComponent();
}
winrt::event_token scalar_slider::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_property_changed.add(handler);
}
void scalar_slider::PropertyChanged(winrt::event_token const& token) noexcept
{
m_property_changed.remove(token);
}
Windows::UI::Xaml::DependencyProperty scalar_slider::m_scalar_value_property = Windows::UI::Xaml::DependencyProperty::Register(
L"scalar_value",
winrt::xaml_typename<float>(),
winrt::xaml_typename<winrt::transformations::scalar_slider>(),
Windows::UI::Xaml::PropertyMetadata{ nullptr }
);
Windows::UI::Xaml::DependencyProperty scalar_slider::scalar_valueProperty()
{
return m_scalar_value_property;
}
void scalar_slider::scalar_valueProperty(Windows::UI::Xaml::DependencyProperty value)
{
m_scalar_value_property = value;
}
float scalar_slider::scalar_value()
{
return m_scalar_value;
}
void scalar_slider::scalar_value(float value)
{
update_value(L"scalar_value", m_scalar_value, value);
}
}
About your code, I find the get and set function of scalar_slider property you write are not correct in scalar_slider.cpp, you can change them like below code.
You can also read XAML custom (templated) controls with C++/WinRT to understand better.
float scalar_slider::scalar_value()
{​
return winrt::unbox_value<float>(GetValue(m_scalar_value_property));​
}​
​
void scalar_slider::scalar_value(float value)​
{​
SetValue(m_scalar_value_property, winrt::box_value(value));​
m_property_changed(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs(L"scalar_value"));​
}

Attached.Property="{Binding}" does not work

I have created a simple attached property that enables dragging an item around the screen.
1/ Here's how you would implement it on your element:
<Rectangle Fill="Green" local:MyExtension.CanMove="True" />
2/ This works like a charm. So does this:
// in resources
<x:Boolean x:Key="MyCanMove">true</x:Boolean>
<Rectangle Fill="Blue" local:MyExtension.CanMove="{StaticResource MyCanMove}" />
3/ But one syntax does not work. This fails:
<Rectangle Fill="Red" local:MyExtension.CanMove="{Binding Path=CanMove}" />
What's different? The only thing different is that it is binding the value into the attached property instead of setting it explicitly or through a static resource.
I'm missing something. But what is it?
Here's the full XAML:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.DataContext>
<local:ViewModel/>
</Grid.DataContext>
<ToggleSwitch Header="Enable Dragging"
HorizontalAlignment="Center"
IsOn="{Binding CanMove, Mode=TwoWay}">
<ToggleSwitch.RenderTransform>
<TranslateTransform Y="-100" />
</ToggleSwitch.RenderTransform>
</ToggleSwitch>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel.Resources>
<Style TargetType="Rectangle">
<Setter Property="Height" Value="100" />
<Setter Property="Width" Value="100" />
</Style>
<x:Boolean x:Key="MyCanMove">true</x:Boolean>
</StackPanel.Resources>
<Rectangle Fill="Green" local:MyExtension.CanMove="True" />
<Rectangle Fill="Blue" local:MyExtension.CanMove="{StaticResource MyCanMove}" />
<Rectangle Fill="Red" local:MyExtension.CanMove="{Binding Path=CanMove}" />
</StackPanel>
</Grid>
And here's the full code-behind:
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
bool m_CanMove = true;
public bool CanMove
{
get { return m_CanMove; }
set
{
m_CanMove = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("CanMove"));
}
}
}
public class MyExtension
{
// canmove aproperty
public static bool GetCanMove(DependencyObject obj)
{
return (bool)obj.GetValue(CanMoveProperty);
}
public static void SetCanMove(DependencyObject obj, bool value)
{
System.Diagnostics.Debug.WriteLine("SetCanMove");
obj.SetValue(CanMoveProperty, value);
var rectangle = obj as FrameworkElement;
rectangle.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
rectangle.ManipulationDelta -= rectangle_ManipulationDelta;
if (value)
rectangle.ManipulationDelta += rectangle_ManipulationDelta;
}
public static readonly DependencyProperty CanMoveProperty =
DependencyProperty.RegisterAttached("CanMove", typeof(bool), typeof(MyExtension), new PropertyMetadata(false));
// implementation
static void rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
var rectangle = sender as FrameworkElement;
var canMove = System.Convert.ToBoolean(rectangle.GetValue(MyExtension.CanMoveProperty));
if (canMove)
{
var transform = rectangle.RenderTransform as CompositeTransform;
if (transform == null)
rectangle.RenderTransform = (transform = new CompositeTransform());
transform.TranslateX += e.Delta.Translation.X;
transform.TranslateY += e.Delta.Translation.Y;
}
}
}
I'll remind you that this attached property works fine in the first two syntaxes. As a result, I can't imagine the error is in the attached property. And, I read on a few forums where path= is necessary to bind to an attached property, so I included that (though it didn't make a difference). Changing the Mode (OneWay, TwoWay) doesn't make a difference. Binding with an ElementName didn't make a difference. I am wondering if this simply isn't enabled in Windows 8.0 WinRT. Can anyone else get this to work?
EDIT: Solution
The problem was that without a changed event handler setup, the binding doesn't raise a changed event. Here's the updated MyExtension code:
public class MyExtension
{
// canmove aproperty
public static bool GetCanMove(DependencyObject obj) { return (bool)obj.GetValue(CanMoveProperty); }
public static void SetCanMove(DependencyObject obj, bool value) { obj.SetValue(CanMoveProperty, value); }
public static readonly DependencyProperty CanMoveProperty =
DependencyProperty.RegisterAttached("CanMove", typeof(bool), typeof(MyExtension), new PropertyMetadata(false, OnCanMoveChanged));
// respond to change
private static void OnCanMoveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rectangle = d as FrameworkElement;
rectangle.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
rectangle.ManipulationDelta -= rectangle_ManipulationDelta;
if ((bool)e.NewValue)
rectangle.ManipulationDelta += rectangle_ManipulationDelta;
}
// implementation
static void rectangle_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
var rectangle = sender as FrameworkElement;
var canMove = System.Convert.ToBoolean(rectangle.GetValue(MyExtension.CanMoveProperty));
if (canMove)
{
var transform = rectangle.RenderTransform as CompositeTransform;
if (transform == null)
rectangle.RenderTransform = (transform = new CompositeTransform());
transform.TranslateX += e.Delta.Translation.X;
transform.TranslateY += e.Delta.Translation.Y;
}
}
}
This is just speculation as I don't have a compiler in front of me, but I'm wondering if the binding infrastructure doesn't use the exposed methods you created GetCanMove etc.
Try registering a property changed method in the PropertyMetadata
new PropertyMetadata(false, OnCanMoveChanged)
and have the setup and teardown code in there
private void OnCanMoveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

Binding UI Element Dependency Property with a Data Member of class

I need to bind all the check boxes(IsChecked Property) in an StackPannel with a bool value which is defined in a class. Attaching my Xaml with my question, please help
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel Height="287" HorizontalAlignment="Left" Margin="78,65,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="309" DataContext="checkFlag">
<CheckBox Content="" Height="71" Name="checkBox1" IsChecked="{Binding Path=Binding.MainPage,Source=checkFlag,Mode=TwoWay}"/>
<CheckBox Content="" Height="71" Name="checkBox2" IsChecked="{Binding Path=Binding.MainPage,Source=checkFlag,Mode=TwoWay}"/>
</StackPanel>
<Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="78,400,0,0" Name="button1" VerticalAlignment="Top" Width="160" Click="button1_Click" />
<Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="227,400,0,0" Name="button2" VerticalAlignment="Top" Width="160" Click="button2_Click" />
The checkboxes are not getting check/uncheck on set/reset of checkFlag. Should i implement "INotifyPropertyChanged" for the flag Or something else. Adding the class behind also, Please have a look.'
namespace Binding
{
public partial class MainPage : PhoneApplicationPage
{
public bool checkFlag;
// Constructor
public MainPage()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
checkFlag = true;
}
private void button2_Click(object sender, RoutedEventArgs e)
{
checkFlag = false;
}
}
it looks to me like you need to implement, as you guess, INotifyPropertyChanged here is a link to the MSDN documentation
here is some demo code....
public class MyData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string property)
{
PropertyChangedEventArgs args = new PropertyChangedEventArgs(property);
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, args);
}
}
int _someInt = 0;
public int SomeInt
{
get { return _someInt ;}
set { if ( value == _someInt ) return;
_someInt = value;
RaisePropertyChanged("SomeInt");
}
}
string _someString = string.Empty;
public string SomeString
{
get { return _someString ;}
set { if ( value == _someString ) return;
_someString = value;
RaisePropertyChanged("SomeString ");
}
}
}
you set up your private variables, then add a property for each one you want to expose.
in the getter, just return the value... in the setter, check if the value has changed and if so assign the value and raise the property changed event. make sure that the name you are passing in as a string is the same as the property... same capitalization, same spelling, etc.

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 :-(