I have a checkbox which is binded to a object's property "IsValidCustomer" and I have a listview that holds some customers.
Whenever My user selects any Customer in the list, I want the Checkbox Checked property to set to False that means my "IsValidCustomer" property also will set to False automatically. Is there any way of achieving this using WPF bindings?
Any help in this regard would be highly appriciated.
Regards
-Srikanth
First make sure that your view's Datacontext is set to a viewmodel that implements the INotifyPropertyChanged interface then add a SelectedCustomer property that will hold the selected Customer from the ListView,
Each time the SelectedCustomer is set, check its value and set the IsValidCustomer property
here the full code :
the View model
public class Customer
{
public String Name { get; set; }
public String Id { get; set; }
}
public partial class MainWindow : Window, INotifyPropertyChanged
{
private Customer _selectedCustomer;
public Customer SelectedCustomer
{
get
{
return _selectedCustomer;
}
set
{
if (_selectedCustomer == value)
{
return;
}
_selectedCustomer = value;
OnPropertyChanged();
IsValidCustomer = (_selectedCustomer == null);
}
}
private ObservableCollection<Customer> _listCustomers;
public ObservableCollection<Customer> ListCustomers
{
get
{
return _listCustomers;
}
set
{
if (_listCustomers == value)
{
return;
}
_listCustomers = value;
OnPropertyChanged();
}
}
private bool _isValidCustomer = false;
public bool IsValidCustomer
{
get
{
return _isValidCustomer;
}
set
{
if (_isValidCustomer == value)
{
return;
}
_isValidCustomer = value;
OnPropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
and the view
<StackPanel>
<CheckBox Content="IsValidCustomer" IsChecked="{Binding IsValidCustomer,Mode=TwoWay}"></CheckBox>
<ListView ItemsSource="{Binding ListCustomers}" SelectedItem="{Binding SelectedCustomer,Mode=TwoWay}"></ListView>
</StackPanel>
I am sure you have something like this in your model :
private bool _IsValidCustomer;
public bool IsValidCustomer
{
get { return _IsValidCustomer; }
set
{
_IsValidCustomer= value;
PropertyChanged(this, new PropertyChangedEventArgs("IsValidCustomer"));
}
}
Set the Binding for that bool property.
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsValidCustomer, Converter={StaticResource InverseBooleanConverter}}"/>
</Style>
Your CheckBox will be bound to this also :
<CheckBox IsChecked="{Binding IsValidCustomer, Mode=TwoWay}"/>
So, i assume you start with that IsValidCustomer set to true. And on selecting each row, you want to set it to false.
You will need an inverse boolean converter for this:
public class InverseBooleanConverter: IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (targetType != typeof(bool))
throw new InvalidOperationException("The target must be a boolean");
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
#endregion
}
Related
So I have this view model:
public class WiresharkFiles : INotifyPropertyChanged
{
public ObservableCollection<WiresharkFile> List { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private bool _inUse;
private int _packets;
private bool _hasItems;
public WiresharkFiles()
{
List = new ObservableCollection<WiresharkFile>();
HasItems = false;
List.CollectionChanged += List_CollectionChanged;
}
private void List_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
HasItems = List.Count > 0;
}
public bool InUse
{
get { return _inUse; }
set
{
_inUse = value;
NotifyPropertyChanged("InUse");
}
}
public int Packets
{
get { return _packets; }
set
{
_packets = value;
NotifyPropertyChanged("Packets");
}
}
public bool HasItems
{
get { return _hasItems; }
set
{
_hasItems = value;
NotifyPropertyChanged("HasItems");
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MainWindow.xaml
private WiresharkFiles caps;
public MainWindow()
{
InitializeComponent();
caps = new WiresharkFiles();
}
Window.Resources
<Window.Resources>
<Convertors:CollectionHasItemsConverter x:Key="CollectionHasItemsConverter"/>
</Window.Resources>
Converter
public class CollectionHasItemsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And base of my collection item (empty or not) i want to enable/disable my Button:
<Button Name="btnDeleteAll"
Click="btnDeleteAll_Click"
IsEnabled="{Binding Path=(caps.HasItems),Converter={StaticResource CollectionHasItemsConverter}}">
And i got this error:
XamlParseException: Type reference cannot find type named
'{http://schemas.microsoft.com/winfx/2006/xaml/presentation}caps'.
I don't see where you're associating your DataContext with the caps property.
Make sure you have a public property because the WPF engine isn't running from within your class and won't be able to access the private WiresharkFiles caps; variable. Try the following:
private WiresharkFiles caps;
public WiresharkFiles Files { get { return caps; } }
with a corresponding
public MainWindow()
{
InitializeComponent();
caps = new WiresharkFiles();
DataContext = Files;
}
Your XAML will then bind to Files as follows
IsEnabled="{Binding Path=HasItems}"
Update You'll need to have a look at implementing and binding to commands for the button which will make it a lot better. Look at this article for info on implementing and dealing with commands.
caps is a private variable:
private WiresharkFiles caps;
In order to bind, it would have to be a public property:
public WiresharkFiles caps {get;set;}
You would also have to set the datacontext of the window to itself. Something like:
this.DataContext = this;
or
In your window tag put:
DataContext="{Binding RelativeSource={RelativeSource Self}}"
I don't see how this relates to your initial question but you can use dot notation in binding.
You can bind:
{Binding AnObservableCollection.Count}
And you can compare that to 0 in a datatrigger. With a button and a bound command if you want to disable it then I'd use the canexecute of icommand and return false if you have no entries or whatever your logic is.
I need help as i've a UserControl, "myUC" and i want change its visibility when i press a MenuItem. I've following class BoolToVisibilityConverter :
[ValueConversion(typeof(bool), typeof(Visibility))]
public sealed class BoolToVisibilityConverter : IValueConverter
{
public Visibility TrueValue { get; set; }
public Visibility FalseValue { get; set; }
public BoolToVisibilityConverter()
{
// set defaults
TrueValue = Visibility.Visible;
FalseValue = Visibility.Collapsed;
}
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (!(value is bool))
return null;
return (bool)value ? TrueValue : FalseValue;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (Equals(value, TrueValue))
return true;
if (Equals(value, FalseValue))
return false;
return null;
}
}
I am setting my converter as StaticResource in Windows.Resource
<Window.Resources>
<vs:BoolToVisibilityConverter x:Key="VisibilityConverter" TrueValue="Visible" FalseValue="Hidden" />
</Window.Resources>
And i've added converter when i call user control in XAML
<uc:Add Visibility="{Binding MyProperty,Converter={StaticResource VisibilityConverter},FallbackValue=Hidden}" />.
I've binding on the property " MyProperty" so:
private bool _myProperty;
public bool MyProperty
{
get {
return _myProperty;
}
set {
if (_myProperty== true)
_myProperty= value;
else
_myProperty= true;
OnPropertyChanged("MyProperty");
}
}
But when i launch the application, it does not change the visibility of UserControl.
I forgot to mention that i've the MenuItem bindig with ICommand
<MenuItem Name="mnuAggiungi" Header="_Aggiungi" Command="{Binding MyCommand}"/>
RelayCommand _add;
public ICommand MyCommand
{
get
{
if (_add == null) _add = new RelayCommand(param => this.MyCommandUC());
return _add;
}
}
public void MyCommandUC()
{
}
I forgot to mention that i've the MenuItem bindig with ICommand
MenuItem Name="mnuAggiungi" Header="_Aggiungi" Command="{Binding MyCommand}"
RelayCommand _add;
public ICommand MyCommand
{
get
{
if (_add == null) _add = new RelayCommand(param => this.MyCommandUC());
return _add;
}
}
public void MyCommandUC()
{
}
in command handler MyCommandUC do this..
public void MyCommandUC
{
MyProperty = false; // for hidden
}
but saying this I would want to tell you that, your code is quite confusing, sometimes you set visibility to Hidden sometimes you set it to Collapsed, also, you try to set truevalue and FalseValues from xaml but your converter has hard coded values in its constructor there by making it useless to set anything from xaml
--- edit
I just saw this .. and I.. !
set {
if (_myProperty== true)
_myProperty= value;
else
_myProperty= true;
OnPropertyChanged("MyProperty");
}
change above code to
set {
_myProperty= value;
OnPropertyChanged("MyProperty");
}
Value of MyProperty change when click on MenuItem, and i capture click with ICommand. I've think to do so
_private bool _myProperty;
...
set
{ _
myProperty = value;
}
}
public void MyCommandUC()
{
if (MyProperty == false)
MyProperty = true;
else
MyProperty = false;
}
but don't work
I am new to WPF and am a little lost.
I want to display Text within a label binding it to the following class:
class Status
{
public string Message;
public bool Success;
}
I want the label to display the "message" in green if success and in red if not. I am not sure how to start on it.
First, you need to bind to properties, not members. You should also get into the habit of implementing INotifyPropertyChanged on your class that you're binding to.
public class Status : INotifyPropertyChanged
{
private string message;
public string Message
{
get { return this.message; }
set
{
if (this.message == value)
return;
this.message = value;
this.OnPropertyChanged("Message");
}
}
private bool success;
public bool Success
{
get { return this.success; }
set
{
if (this.success == value)
return;
this.success = value;
this.OnPropertyChanged("Success");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In terms of binding, you'd have to use a custom IValueConverter
public class RGColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
bool success = (bool) value;
return success ? Brushes.Green : Brushes.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And the relevant binding/setup
<Window.Resources>
<wpfApplication2:RGColorConverter x:Key="colorConverter" />
</Window.Resources>
<Label Content="{Binding Message}" Foreground="{Binding Success, Converter={StaticResource colorConverter}}" />
I have a list control and each item contains two images and text. On the click on each item I want to hide or show selected image on selected list item.
Here is XAML code snippet:
<ListBox x:Name="list" SelectionChanged="list_SelectionChanged" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<Image Source="{Binding ImagePath}" Stretch="None"/>
<Image Source="{Binding ImagePath}" Stretch="None"
Visibility="{Binding ImageVisibility,
Converter={StaticResource boolVisibilityConverter}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C# code:
dataSource = new ObservableCollection<ImageData>()
{
new ImageData(){Name = "User1:", ImagePath="/Images/user1.png", ImageVisibility = false},
new ImageData(){Name = "User1:", ImagePath="/Images/user1.png", ImageVisibility = true},
new ImageData(){Name = "User1:", ImagePath="/Images/user1.png", ImageVisibility = true},
new ImageData(){Name = "User2:", ImagePath="/Images/user2.png", ImageVisibility = true}
};
List Selection Changed Event:
private void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
((ImageData)(((object[])(e.AddedItems))[0])).ImageVisibility = false;
list.UpdateLayout();
}
ImageData class:
public class ImageData
{
public string ImagePath { get; set; }
public string Name { get; set; }
public bool ImageVisibility { get; set; }
}
Image Visibility Converter:
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = false;
if (value is bool)
{
flag = (bool)value;
}
else if (value is bool?)
{
bool? nullable = (bool?)value;
flag = nullable.HasValue ? nullable.Value : false;
}
return (flag ? Visibility.Visible : Visibility.Collapsed);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((value is Visibility) && (((Visibility)value) == Visibility.Visible));
}
}
Please help me to accomplish such functionality.
You need to use INotifyPropertyChanged interface http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
For example so:
public class ImageData : INotifyPropertyChanged
{
private bool _imageVisibility;
public string ImagePath { get; set; }
public string Name { get; set; }
public bool ImageVisibility
{
get
{
return _imageVisibility;
}
set
{
_imageVisibility = value;
OnPropertyChanged("ImageVisibility");
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Full changes according to your task you can see here (dropbox)
I'm working on an application using a TCP protocol.
I want to show the different statuses of the communication in different colors (connect = green, disconnect = red)
I defined an enum:
public enum ComunicationStateTypeEnum
{
COMUNICATION_CONNECTED,
COMUNICATION_DISCONNECTED
};
I defined a conversion class:
namespace Conversion
{
[ValueConversion(typeof(ComunicationStateTypeEnum), typeof(Brushes))]
public class ComStatusToColor : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ComunicationStateTypeEnum state = (ComunicationStateTypeEnum)value;
if (state == ComunicationStateTypeEnum.COMUNICATION_CONNECTED)
return Brushes.Green;
return Brushes.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
In Xaml I defined an ellipse:
<Ellipse Name="ComEllipse" Height="25" Width="30" Fill ="{Binding Path=eCommStatus, Converter={StaticResource ComStatusToColor}}" Stroke="Black" DockPanel.Dock="Left"/>
also in Xaml I defined:
xmlns:ConversionNamespace="clr-namespace:Conversion"
<Window.Resources>
<ConversionNamespace:ComStatusToColor x:Key="ComStatusToColor"/>
</Window.Resources>
I want to bind to an existing object, therefore I initiated:
ComEllipse.DataContext = SystemLogic.GetInstance();
(SystemLogic is a singleton)
and in SystemLogic I defined:
public class SystemLogic
{
public ComunicationStateTypeEnum eCommStatus { get; set; }
...
}
eCommStatus is initiated to COMUNICATION_DISCONNECTED in the constructor and the ellipse turns red, and still when eCommStatus member changes to COMUNICATION_CONNECTED , the ellipse doesn't change its color
What's wrong?
Gil
You need to implement INotifyPropertyChanged interface in your SystemLogic class to let UI know that a property's value has changed. This way UI can update itself.
Example
public class SystemLogic : INotifyPropertyChanged
{
private ComunicationStateTypeEnum _eCommStatus;
public ComunicationStateTypeEnum eCommStatus
{
get
{
return _eCommStatus;
}
set
{
_eCommStatus = value;
RaisePropertyChanged("eCommStatus");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(String propertyName)
{
PropertyChangedEventHandler temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Nothing wrong with your binding. But SystemLogic must implement INotifyPropertyChanged to report back when it is changed.
public class SystemLogic
{
private ComunicationStateTypeEnum _eCommStatus;
public ComunicationStateTypeEnum eCommStatus
{
get{return _eCommStatus;}
set
{
_eCommStatus = value;
OnPropertyChanged("ComunicationStateTypeEnum");
}
}
...
}