Bind Button IsEnabled property to DataTemplate items state and one additional condition - c#

I have an object with editable parameters collection which are bound as a ItemsSource to ItemsControl, and a property which checks if all parameter values are ok. This property bound to button's IsEnabled.
I also want to disable the button when any of textbox has validation error (Validation.HasError == true).
Thanks in advance.
XAML:
<Window x:Class="MyWPFTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=MyObject.Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}"></TextBlock>
<TextBox Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button IsEnabled="{Binding Path=MyObject.IsParametersOkay}">OK</Button>
</StackPanel>
</Window>
Code:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
namespace MyWPFTest
{
public partial class MainWindow : Window
{
ObjectWithParameters _MyObject = new ObjectWithParameters();
public ObjectWithParameters MyObject { get { return _MyObject; } }
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}
public class ObjectWithParameters : INotifyPropertyChanged
{
ObservableCollection<Parameter> _Parameters = new ObservableCollection<Parameter>();
public ObservableCollection<Parameter> Parameters { get { return _Parameters; } }
public event PropertyChangedEventHandler PropertyChanged;
public ObjectWithParameters()
{
var p1 = new Parameter("Parameter 1", 0); p1.PropertyChanged += ParameterChanged; Parameters.Add(p1);
var p2 = new Parameter("Parameter 2", 0); p2.PropertyChanged += ParameterChanged; Parameters.Add(p2);
}
void ParameterChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsParametersOkay"));
}
public bool IsParametersOkay
{
get { return Parameters.FirstOrDefault(p => p.Value < 0) == null; }
}
}
public class Parameter : INotifyPropertyChanged
{
double val;
public double Value
{
get { return val; }
set { val = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Value")); }
}
public string Name { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public Parameter(string name, double value) { Name = name; Value = value; }
}
}

Check out MultiTriggers.
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" Value="#EEEEEE" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasItems" Value="false" />
<Condition Property="Width" Value="Auto" />
</MultiTrigger.Conditions>
<Setter Property="MinWidth" Value="120"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasItems" Value="false" />
<Condition Property="Height" Value="Auto" />
</MultiTrigger.Conditions>
<Setter Property="MinHeight" Value="95"/>
</MultiTrigger>
</Style.Triggers>

This is the way I solved the problem. May be it's not a very elegant solution, but it works.
I added a new property IsFormOkay to MainWindow class, which checks both controls and parameters validity. Then I bound Button.IsEnabled to this property and added TextChanged event for TextBox to notify about IsFormOkay.
Here is code added to MainWindow:
public event PropertyChangedEventHandler PropertyChanged;
public bool IsFormOkay { get { return IsValid(Items) && MyObject.IsParametersOkay; } }
public bool IsValid(DependencyObject obj)
{
if (Validation.GetHasError(obj)) return false;
for (int i = 0, n = VisualTreeHelper.GetChildrenCount(obj); i < n; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (!IsValid(child)) return false;
}
return true;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsFormOkay"));
}
And changes to XAML:
<StackPanel>
<ItemsControl x:Name="Items" ItemsSource="{Binding Path=MyObject.Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Name}" />
<TextBox TextChanged="TextBox_TextChanged" Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button IsEnabled="{Binding Path=IsFormOkay}" Content="OK" />
</StackPanel>

Related

Datatrigger appropriately changes the initial property of TextBlock but not after the object changes

Issue
When setting datatriggers for my textblock it accepts the default value without issue and changes the foreground appropriately however, when the the value changes it doesn't change colors as one would expect. I looked through a few answers and I should be able to reference the relative-source in someway but it didn't change the result.
XAML Test Code
<ListBox Name="test" Width="90" Margin="20,0,20,40" MouseDown="TextBlock_MouseDownTest"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Name="dttBlock" Text="{Binding Time}" MouseDown="TextBlock_MouseDownTest">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path =Flex}" Value="normal">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
MouseDownClickEvent
private void TextBlock_MouseDownTest(object sender, MouseButtonEventArgs e)
{
TimeLord item = (TimeLord) (sender as TextBlock).DataContext;
var textBlock = sender as TextBlock;
switch (item.Flex)
{
case "off":
MessageBox.Show("Normal ON");
item.Flex = "normal";
break;
case "normal":
MessageBox.Show("Flex ON");
item.Flex = "flex";
break;
case "flex":
MessageBox.Show("OFF");
item.Flex = "off";
break;
}
}
Prior Implementation and Desired Result
If the person responding doesn't mind, I would like to have a larger discussion on this. The reason I'm using data triggers is because I was having trouble implementing a button that resets all of my listboxitem foregrounds to the default color (Black).
Current XAML Code
<ListBox Name="friday" Width="90" Margin="20,0,20,40" MouseDown="TextBlock_MouseDown"
ScrollViewer.VerticalScrollBarVisibility="Disabled" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Time}" MouseDown="TextBlock_MouseDown" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Current C# ButtonClickEvent Code
private void clear_Click(object sender, RoutedEventArgs e)
{
List<System.Windows.Controls.ListBox> weekdays = new List<System.Windows.Controls.ListBox>
{monday, tuesday, wednesday, jueves, friday};
for (var i = 0; i < weekdays.Count; i++)
{
foreach (TimeLord item in weekdays[i].Items)
{
item.Flex = "off";
}
}
}
I have no problems changing the object associated with the listboxitem but I have no way of changing the foreground from the button itself. I can successfully change the foreground by creating an event for when the listboxitem is clicked by using the sender being passed into the event. If there is a way I can access the textbox from the ButtonClick event, that could be an alternative solution to the Datatrigger.
This is a small clip showing off the old implementation and that I can currently change the value of the item.
In my TimeLord class I never implemented the INotifyPropertyChanged, after doing so everything worked as I expected it to with the DataTriggers.
TimeLord.cs
public class TimeLord : INotifyPropertyChanged {
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
public string flex;
public string Flex
{
get { return flex;}
set
{
flex = value;
OnPropertyChanged();
}
}
public string Time
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
XAML Code Block (It's the same one as before but just to show more than the one trigger type)
<DataTemplate>
<TextBlock Name="dttBlock" Text="{Binding Time}" MouseDown="TextBlock_MouseDownTest">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path =Flex}" Value="normal">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding Path =Flex}" Value="flex">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>

WPF binding problem on IsEnabled of DockPanel

I'm writing a WPF application and my problem is that I have a class member bound with the property "IsEnabled" of one element of xaml and basically the binding seems not to work at all.
Here some extracts of my code:
XAML
<Window.Resources>
<Style TargetType="{x:Type DockPanel}" x:Key="MyDockPanel">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<DockPanel x:Name="home_dock_panel" Style="{StaticResource MyDockPanel}" HorizontalAlignment="Left" Height="35" LastChildFill="False" Margin="22,82,0,0" VerticalAlignment="Top" Width="189" MouseDown="GoToHome" IsEnabled="{Binding Path=UnlockMenu}">
<Image Source="images/home.png" Height="26" RenderTransformOrigin="1.277,0.518" Margin="0,5,0,4.2"/>
<Label Content="Home" Height="35" VerticalAlignment="Top" Foreground="White" FontSize="20" FontWeight="Bold"/>
</DockPanel>
Here the function that allows changing page
private void GoToXPage(object sender, MouseButtonEventArgs e)
{
if(central_frame.Content.GetType() != typeof(LathePage))
{
ViewModel viewModel = new ViewModel();
central_frame.Content = new XPage(viewModel);
panel_dock.DataContext = viewModel;
}
Here a part of ViewModel code
public class ViewModel : INotifyPropertyChanged
{
public GenerateCommand Generate { get; set; }
public bool UnlockMenu { get; set; }
public ViewModel()
{
Generate = new GenerateCommand();
Generate.PropertyChanged += InnerPropertyChanged;
UnlockMenu = Generate.UnlockMenu;
}
private void InnerPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "UnlockMenu")
{
UnlockMenu = Generate.UnlockMenu;
NotifyPropertyChanged("UnlockMenu");
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
In the class GenerateCommand I call NotifyPropertyChanged("UnlockMenu").
Does anyone have some suggestions on this problem?

WPF: how to auto show my ListView ToolTip when focus

So i have ListViewItem with my object:
public class ClipboardItem : INotifyPropertyChanged
{
private string _text { get; set; }
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyPropertyChanged();
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
And ToolTip and i want when my ListViewItem IsSelected=True to show my ToolTip
This is my ListViewItem CellTemplate:
<TextBlock Text="{Binding Path=Text}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Grid.Column="1"
Margin="5,0,0,0">
<TextBlock.ToolTip>
<ToolTip Content="{Binding Path=Text}"
Placement="Left"
PlacementRectangle="0,0,0,0"
HorizontalOffset="10"
VerticalOffset="20"
HasDropShadow="false"/>
</TextBlock.ToolTip>
</TextBlock>
When i move over my ListViewItem with my Up & Down arrows i want to auto show my TooTip and not only when MouseIsOver
i also try to dso it in my ListViewItem style:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False" />
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Silver"/>
<Setter Property="BorderThickness" Value="0.5"/>
<Setter Property="ToolTip" Value="{Binding Path=Text}"/>
</MultiDataTrigger>
Non of them works and i can see my ToolTip only when MouseIsOver
In general this is a really bad idea. ToolTips have a very specific behavior, which is why WPF doesn't expose it as conveniently as WinForms did with ToolTip.Show. The correct thing to use here would be an adorner.
That said, if you are absolutely adamant about forcibly showing a ToolTip manually then it can be done with a behavior, but you're going to have to fudge some of the functionality that's normally taken care of for you:
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
namespace YourApp.Behaviors
{
public class ToolTipBehavior : Behavior<FrameworkElement>
{
private ToolTip CurrentToolTip;
public ListViewItem ListViewItem
{
get { return (ListViewItem)GetValue(ListViewItemProperty); }
set { SetValue(ListViewItemProperty, value); }
}
// Using a DependencyProperty as the backing store for ListViewItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ListViewItemProperty =
DependencyProperty.Register("ListViewItem", typeof(ListViewItem), typeof(ToolTipBehavior),
new PropertyMetadata(null, (d, e) => (d as ToolTipBehavior)?.OnListViewItemChanged(e)));
private void OnListViewItemChanged(DependencyPropertyChangedEventArgs e)
{
if (e.OldValue is ListViewItem)
(e.OldValue as ListViewItem).Selected -= ToolTipBehavior_Selected;
if (e.NewValue is ListViewItem)
(e.NewValue as ListViewItem).Selected += ToolTipBehavior_Selected;
}
private void ToolTipBehavior_Selected(object sender, RoutedEventArgs e)
{
if (e.Source != e.OriginalSource)
return;
if ((this.ListViewItem != null) && this.ListViewItem.IsSelected)
{
var tooltip = this.AssociatedObject.ToolTip as ToolTip;
if (tooltip != null)
{
if (this.CurrentToolTip != tooltip)
{
if (this.CurrentToolTip != null)
this.CurrentToolTip.Opened -= Tooltip_Opened;
this.CurrentToolTip = tooltip;
if (this.CurrentToolTip != null)
this.CurrentToolTip.Opened += Tooltip_Opened;
}
this.CurrentToolTip.PlacementTarget = this.AssociatedObject;
this.CurrentToolTip.IsOpen = true;
}
}
}
private async void Tooltip_Opened(object sender, RoutedEventArgs e)
{
await Task.Delay(1000);
(this.AssociatedObject.ToolTip as ToolTip).IsOpen = false;
}
}
}
Which you would then use like this:
<TextBlock Text="{Binding Path=Text}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}"
Grid.Column="1"
Margin="5,0,0,0">
<i:Interaction.Behaviors>
<behaviors:ToolTipBehavior ListViewItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}}" />
</i:Interaction.Behaviors>
<TextBlock.ToolTip>
<ToolTip Content="{Binding Path=Text}" ToolTipService.ShowDuration="2"
...etc...

WPF: DataTrigger not firing

In a WPF Project I have some restyled DataGridColumnHeaders of a DataGrid which show a ComboBox for each DataGridColumnHeader. When the user selects from the ComboBox's the SelectionChanged handler (in the code behind) updates an Array of ColumnOptionViewModel objects on the MainWindowViewModel with the newest selection.
At this point some code also works out if there are any duplicate selections in this array, and then sets an IsDuplicate Boolean property on the ColumnOptionViewModel that are duplicates. The idea is that a DataTrigger picks up the change in IsDuplicate and changes the Background of a TextBlock in the DataTemplate of the ItemTemplate for the duplicate ComboBox's to Red.
However, this trigger is not firing. The IsDuplicate properties are being set ok, and everything else works as expected. What am I doing wrong?
Here is the XAML for the Window:
<Window x:Class="TestDataGrid.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:TestDataGrid"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid Grid.Row="1" x:Name="dataGrid" ItemsSource="{Binding Records}">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<ComboBox x:Name="cbo"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.ColumnOptions}"
SelectionChanged="cbo_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="txt" Text="{Binding Name}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=cbo, Path=SelectedItem.IsDuplicate}">
<Setter TargetName="txt" Property="Background" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
</Grid>
CODE BEHIND:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel(RecordProvider.GetRecords());
}
private void cbo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var vm = (MainWindowViewModel)DataContext;
var selectionChangedCombo = (ComboBox)e.Source;
var dataGridColumnHeader = selectionChangedCombo.TemplatedParent as DataGridColumnHeader;
vm.ColumnSelections[dataGridColumnHeader.DisplayIndex] = selectionChangedCombo.SelectedItem as ColumnOptionViewModel;
CheckForDuplicates();
}
private void CheckForDuplicates()
{
var vm = (MainWindowViewModel)DataContext;
var duplicates = vm.ColumnSelections.GroupBy(x => x.Name)
.Where(g => g.Skip(1).Any())
.SelectMany(g => g);
foreach (var option in duplicates)
{
option.IsDuplicate = true;
}
}
}
MainWindowViewModel :
public class MainWindowViewModel : ViewModelBase
{
public ObservableCollection<ColumnOptionViewModel> _columnOptions = new ObservableCollection<ColumnOptionViewModel>();
public ObservableCollection<RecordViewModel> _records = new ObservableCollection<RecordViewModel>();
ColumnOptionViewModel[] _columnSelections = new ColumnOptionViewModel[3];
public MainWindowViewModel(IEnumerable<Record> records)
{
foreach (var rec in records)
{
Records.Add(new RecordViewModel(rec));
}
ColumnOptions.Add(new ColumnOptionViewModel(TestDataGrid.ColumnOptions.ColumnOption1));
ColumnOptions.Add(new ColumnOptionViewModel(TestDataGrid.ColumnOptions.ColumnOption2));
ColumnOptions.Add(new ColumnOptionViewModel(TestDataGrid.ColumnOptions.ColumnOption3));
ColumnSelections[0] = ColumnOptions[0];
ColumnSelections[1] = ColumnOptions[1];
ColumnSelections[2] = ColumnOptions[2];
}
public ObservableCollection<ColumnOptionViewModel> ColumnOptions
{
get { return _columnOptions; }
set { _columnOptions = value; }
}
public ColumnOptionViewModel[] ColumnSelections
{
get { return _columnSelections; }
set { _columnSelections = value; }
}
public ObservableCollection<RecordViewModel> Records
{
get { return _records; }
set { _records = value; }
}
}
ColumnOptionViewModel :
public class ColumnOptionViewModel : ViewModelBase
{
ColumnOptions _colOption;
public ColumnOptionViewModel(ColumnOptions colOption )
{
_colOption = colOption;
}
public string Name
{
get { return _colOption.ToString(); }
}
public override string ToString()
{
return Name;
}
private bool _isDuplicate = false;
public bool IsDuplicate
{
get { return _isDuplicate; }
set
{ _isDuplicate = value;
OnPropertyChanged();
}
}
}
EDIT:
ViewModelBase :
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
If you are trying to bind to the IsDuplicate property of the SelectedItem in the ComboBox you could use a RelativeSource.
You should also set the Value property of the DataTrigger to true/false depending on when you want the Background property of the TextBlock to be set to Red:
<ComboBox x:Name="cbo" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.ColumnOptions}"
SelectionChanged="cbo_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="txt" Text="{Binding Name}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=SelectedItem.IsDuplicate, RelativeSource={RelativeSource AncestorType=ComboBox}}" Value="True">
<Setter TargetName="txt" Property="Background" Value="Red"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
As #mm8 said, the Value is not chosen in your DataTrigger.
If that doesn't work, you can try using Trigger directly on TextBlock instead of DataTemplate.Triggers:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="White"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsDuplicate}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Also, background and foreground values in controls that have selectable items can be tricky. For example, you may want to disable default selection colors (unfortunately then you will have to manage selected/focused background yourself):
<ComboBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
</ComboBox.Resources>

Refresh ListView item with Image's Source bound to property

I have problem with refreshing my listview data. It doesn't update unless I call:
List.ItemsSource = null;
List.ItemsSource = listviewSource;
This is works but doesn't look good (screen flashes) so I wanted to use, as people suggested, INotifyPropertyChanged.
My listviewSource is ObservableCollection< Class2> where Class2 implements Class1 and Class1 implements INotifyPropertyChanged.
public class Class1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
...
}
public class Class2 : Class1
{
private string ImgSource;
public string imgSource
{
get { return this.ImgSource; }
set
{
this.ImgSource = value;
NotifyPropertyChanged("imgSource");
}
}
....
}
imgSource is binded to ListView but when it changes nothing happens... Am I doing something wrong?
XAML markup
<ListView x:Name="List" Width="400" HorizontalAlignment="Center" Loaded="List_Loaded">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Top"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Tag="{Binding number}" Background="#FF0E1D23" Margin="0,5" >
<Image Margin="339,10,23,13" Source="{Binding imgSource}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
It seems that Image's Source default binding mode is OneTime.
Change it explicitly to OneWay:
Source="{Binding imgSource, Mode = OneWay}"

Categories

Resources