I have the startup window in a WPF application, and I have this code in my view:
<Window x:Class="MyView"
Name="ucPrincipal"
Title="{Binding Titulo}"
Visibility="{Binding EsUpdaterVisible, Mode=TwoWay}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Recursos/Diccionarios/Converters.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Button Content="Aceptar" HorizontalAlignment="Left" Margin="10,145,0,0" VerticalAlignment="Top" Width="75">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding AceptarCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
My ViewModel:
private RelayCommand _aceptarCommand;
public RelayCommand AceptarCommand
{
get { return _aceptarCommand ?? (_aceptarCommand = new RelayCommand(aceptarCommand)); }
}
private void aceptarCommand()
{
try
{
EsUpdaterVisible = false;
Titulo = "Después de aceptar.";
}
catch { throw; }
}
private bool _esUpdaterVisible = true;
public bool EsUpdaterVisible
{
get { return _esUpdaterVisible; }
set
{
if (_esUpdaterVisible != value)
{
_esUpdaterVisible = value;
base.RaisePropertyChangedEvent("EsUpdaterVisible");
}
}
}
private string _titulo = "Inicio";
public string Titulo
{
get { return _titulo; }
set
{
if (_titulo != value)
{
_titulo = value;
base.RaisePropertyChangedEvent("Titulo");
}
}
}
When I click the aceptar button, the title of the window is changed, but the windows is still visible.
I would like to hide the window in some cases from the view model. How I could do that?
Thanks.
If you wouldn't like to use converter, just xaml part:
<Window x:Class="MyView"
Name="ucPrincipal"
Title="{Binding Titulo}">
<Window.Style>
<Style TargetType="Window">
<Style.Triggers>
<DataTrigger Binding="{Binding EsUpdaterVisible,UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding EsUpdaterVisible,UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/> <!-- use hide instead of collapsed if you would like to open again this instance of window after close. -->
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Style>
Visibility is not a boolean type.
You can use a converter to accomplish that.
Converter:
[ValueConversion(typeof(bool), typeof(Visibility))]
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Than your XAML will look something like this:
<Window x:Class="MyView"
Name="ucPrincipal"
Title="{Binding Titulo}"
Visibility="{Binding EsUpdaterVisible, Converter={StaticResource visibilityConverter}}">
Related
I'm trying to highlight a row in my ListView based on a property of class. The ItemSource is set to an ObservableCollection<FileInformation> the property I need to determine whether the row should be highlighted is contained in the FileInformation class - bool IsPlaying.
This is my ListView xaml:
<ListView Name="lvListView" Margin="0,0,0,35" AllowDrop="True" ItemsSource="{Binding FilesCollection}">
<ia:Interaction.Triggers>
<ia:EventTrigger EventName="Drop">
<cmd:EventToCommand Command="{Binding ListViewFileDrop}" PassEventArgsToCommand="True"/>
</ia:EventTrigger>
<ia:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding ListViewDoubleClickCommand}" PassEventArgsToCommand="True"/>
</ia:EventTrigger>
</ia:Interaction.Triggers>
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Command="{Binding RemoveCommand}" CommandParameter="{x:Reference Name=lvListView}"/>
<MenuItem Header="Add File" Command="{Binding BrowseCommand}"/>
<MenuItem Header="Clear All" Command="{Binding ClearAllCommand}"/>
</ContextMenu>
</ListView.ContextMenu>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding RelativeSource={RelativeSource Self}, Path=IsPlaying, Converter={converters:TestConverter}}"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Title" Width="350" DisplayMemberBinding="{Binding Title}"/>
<GridViewColumn Header="Time" Width="114"
DisplayMemberBinding="{Binding Time, Converter={converters:TimeSpanFormatConverter}}"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
This is the part I'm struggling with:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding RelativeSource={RelativeSource Self}, Path=IsPlaying, Converter={converters:TestConverter}}"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
Right now in order to highlight the row I need to click on it, I want it to be highlighted in yellow only when the property IsPlaying is set to true.
This is the property declaration:
public static readonly DependencyProperty IsPlayingProperty =
DependencyProperty.Register(nameof(IsPlaying), typeof(bool), typeof(FileInformation),
new PropertyMetadata(null));
private bool _isPlaying = false;
public bool IsPlaying
{
get => (bool)GetValue(IsPlayingProperty);
set
{
SetValue(IsPlayingProperty, value);
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
See if this helps at all. Take a look at the converters XAML (both in the binding and in Window.Resources).
I added a read only datagrid to see the raw data and a button to toggle (true/false) a specific FileInformation.IsPlaying.
MainWindow.xaml
<Window x:Class="WpfApp13.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:WpfApp13"
xmlns:converters="clr-namespace:WpfApp13"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="525">
<Window.Resources>
<converters:TestConverter x:Key="TestConverter" />
<converters:TimeSpanFormatConverter x:Key="TimeSpanFormatConverter" />
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Since it looks like you want to play audio, I set SelectionMode to Single. Probably don't want to play multiple at once -->
<ListView Name="lvListView" Margin="0,0,0,35" AllowDrop="True" ItemsSource="{Binding FilesCollection}" SelectionMode="Single">
<!--<ia:Interaction.Triggers>
<ia:EventTrigger EventName="Drop">
<cmd:EventToCommand Command="{Binding ListViewFileDrop}" PassEventArgsToCommand="True"/>
</ia:EventTrigger>
<ia:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding ListViewDoubleClickCommand}" PassEventArgsToCommand="True"/>
</ia:EventTrigger>
</ia:Interaction.Triggers>-->
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Command="{Binding RemoveCommand}" CommandParameter="{x:Reference Name=lvListView}"/>
<MenuItem Header="Add File" Command="{Binding BrowseCommand}"/>
<MenuItem Header="Clear All" Command="{Binding ClearAllCommand}"/>
</ContextMenu>
</ListView.ContextMenu>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Background" Value="Beige"/>
<!-- The converter, TestConverter, isn't even needed but I'll leave it since you might be doing something else with it -->
<Setter Property="IsSelected" Value="{Binding Path=IsPlaying, Converter={StaticResource TestConverter}}"/>
<Style.Triggers>
<!--<Trigger Property="IsSelected" Value="True">-->
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Title" Width="350" DisplayMemberBinding="{Binding Title}"/>
<GridViewColumn Header="Time" Width="114"
DisplayMemberBinding="{Binding Time, Converter={StaticResource TimeSpanFormatConverter}}"/>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<DataGrid Grid.Row="1" AutoGenerateColumns="False" ItemsSource="{Binding FilesCollection}" IsReadOnly="True">
<DataGrid.Columns>
<DataGridCheckBoxColumn Binding="{Binding IsPlaying}" Header="IsPlaying" />
<DataGridTextColumn Binding="{Binding Title}" Header="Title" />
<DataGridTextColumn Binding="{Binding Time}" Header="Time" />
</DataGrid.Columns>
</DataGrid>
<Button Content="Toggle File 5 IsPlaying" Grid.Row="2" Margin="10" Click="Button_Click" />
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace WpfApp13
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
((MainWindowViewModel)DataContext).PlayToggle(4); // I'm too lazy to use an ICommand...
}
}
public class MainWindowViewModel : DependencyObject
{
public ObservableCollection<FileInformation> FilesCollection
{
get { return (ObservableCollection<FileInformation>)GetValue(FilesCollectionProperty); }
set { SetValue(FilesCollectionProperty, value); }
}
public static readonly DependencyProperty FilesCollectionProperty = DependencyProperty.Register("FilesCollection", typeof(ObservableCollection<FileInformation>), typeof(MainWindowViewModel), new PropertyMetadata(null));
public MainWindowViewModel()
{
FilesCollection = new ObservableCollection<FileInformation>() {
new FileInformation() { Title = "File 1", IsPlaying = false, Time = new TimeSpan(0, 5, 1) },
new FileInformation() { Title = "File 2", IsPlaying = false, Time = new TimeSpan(0, 5, 2) },
new FileInformation() { Title = "File 3", IsPlaying = false, Time = new TimeSpan(0, 5, 3) },
new FileInformation() { Title = "File 4", IsPlaying = false, Time = new TimeSpan(0, 5, 4) },
new FileInformation() { Title = "File 5", IsPlaying = false, Time = new TimeSpan(0, 5, 5) },
new FileInformation() { Title = "File 6", IsPlaying = false, Time = new TimeSpan(0, 5, 6) },
new FileInformation() { Title = "File 7", IsPlaying = false, Time = new TimeSpan(0, 5, 7) },
new FileInformation() { Title = "File 8", IsPlaying = false, Time = new TimeSpan(0, 5, 8) },
new FileInformation() { Title = "File 9", IsPlaying = false, Time = new TimeSpan(0, 5, 9) },
};
}
public void PlayToggle(int idx)
{
FilesCollection[idx].IsPlaying = !FilesCollection[idx].IsPlaying;
}
}
public class FileInformation : DependencyObject
{
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(nameof(IsPlaying), typeof(bool), typeof(FileInformation), new PropertyMetadata(null));
//private bool _isPlaying = false;
public bool IsPlaying
{
get => (bool)GetValue(IsPlayingProperty);
set
{
SetValue(IsPlayingProperty, value);
OnPropertyChanged();
}
}
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(FileInformation), new PropertyMetadata(null));
public string Title
{
get => (string)GetValue(TitleProperty);
set
{
SetValue(TitleProperty, value);
OnPropertyChanged();
}
}
public TimeSpan Time
{
get { return (TimeSpan)GetValue(TimeProperty); }
set { SetValue(TimeProperty, value); }
}
public static readonly DependencyProperty TimeProperty = DependencyProperty.Register("Time", typeof(TimeSpan), typeof(FileInformation), new PropertyMetadata(null));
public event PropertyChangedEventHandler PropertyChanged;
//[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class TestConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// value = IsPlaying
if (value is bool b)
{
return b;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value; // Needed because IsPlaying is twoway bound to IsSelected.
}
}
public class TimeSpanFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// value = Time
if (value is TimeSpan ts)
{
return $"{ts.Minutes} minutes {ts.Seconds} seconds";
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
If you do not want IsSelected tied to IsPlaying but still want IsPlaying to trigger the yellow background then try this:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding IsPlaying}" Value="True">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
I want to add a Custom Property (via a Dependency Property) to my custom ToggleButton Template.
Now i want to have the value of the containing Label (as a placeholder for future implementation) to be a concatenated value of, say "Hello " and the actual Property Value.
Without the concatenation it works fine (displaying "Warrior" on the Label)
But when i try to set the label as a concatenation the xaml doesnt compile anymore.
<Label Content="Hello {TemplateBinding local:HeroClassCheckbox.HeroClass}"/>
How can i achieve this?
The Rest of the Code:
My .xaml
<Window.Resources>
<ResourceDictionary>
<Style x:Key="HeroClassCheckbox" TargetType="ToggleButton">
<Setter Property="Content" Value="Green" />
<Setter Property="local:HeroClassCheckbox.HeroClass" Value="NoClass"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Label Content="{TemplateBinding local:HeroClassCheckbox.HeroClass}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ToggleButton Width="150" Height="50" local:HeroClassCheckbox.HeroClass="Warrior" Style="{DynamicResource HeroClassCheckbox}"/>
</Grid>
My .xaml.cs
public static class HeroClassCheckbox
{
public static readonly DependencyProperty HeroClassProperty = DependencyProperty.RegisterAttached("HeroClass",
typeof(string), typeof(HeroClassCheckbox), new FrameworkPropertyMetadata(null));
public static string GetHeroClass(UIElement element)
{
if (element == null)
throw new ArgumentNullException("element");
return (string)element.GetValue(HeroClassProperty);
}
public static void SetHeroClass(UIElement element, string value)
{
if (element == null)
throw new ArgumentNullException("element");
element.SetValue(HeroClassProperty, value);
}
}
You should use a converter as an approach to your goal. Here is an example..
public class HelloLabelConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
char[] removeThis = "Hello ".ToCharArray();
return value.ToString().TrimStart(removeThis);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return string.Format("Hello {0}", value);
}
}
<Window.Resources>
<local:HelloLabelConverter x:Key="HelloLabelConverter" />
</Window.Resources>
<Grid>
<Label Content="{Binding ElementName= lblPropertyToBind, Path=Text, Converter={StaticResource HelloLabelConverter}}"></Label>
</Grid>
I'd like to be able to change the DataTemplate that my custom class is using, based on a property in the ViewModel.
I can't find any clear examples and I feel like I might not know enough about WPF or XAML to know if this is even possible.
My ViewModel property represents whether the user has collapsed a column on one side of the application. If the column is collapsed, I want to only show the Image for each user, and if the column is expanded, I'll show the picture, first name and last name in a StackPanel.
I feel like there is something really basic that I just don't understand yet and I guess I'm looking for someone who maybe tried something like this or knows how to do this the right way.
User.cs
public class User
{
public string ImageFile {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
}
I'm using an ObservableCollection<User> to hold my collection of User objects in the viewmodel.
My 2 DataTemplates that I'd like to use. (right now I'm just using a default image and text to see how it looks)
DataTemplates
<DataTemplate x:Key="UserCollapsed">
<Image Source="/Images/anon.png"
Height="50"
Width="50"
Margin="0,5,0,0"/>
</DataTemplate>
<DataTemplate x:Key="UserExpanded">
<StackPanel>
<Image Source="/Images/anon.png"
Height="50"
Width="50"
Margin="0,5,0,0"/>
<TextBlock Text="Firstname"/>
<TextBlock Text="Lastnamehere"/>
</StackPanel>
</DataTemplate>
I've tried to write a style, and apply that to my ItemsControl in the view, and I've tried writing a datatemplate that uses triggers to decide which template to use, but I can't quite figure out where I'm going wrong.
Style
<Style x:Key="userTemplateStyle" TargetType="ItemsControl">
<Setter Property="ItemTemplate" Value="{StaticResource UserExpanded}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel}}" Value="True">
<Setter Property="ItemTemplate" Value="{StaticResource UserCollapsed}"/>
</DataTrigger>
</Style.Triggers>
</Style>
I get the following exception when I add the Style property on my ItemsControl in XAML.
Exception
{"Unable to cast object of type 'MS.Internal.NamedObject' to type 'System.Windows.DataTemplate'."}
And the DataTemplate that I tried to use as the ItemTemplate of the ItemsControl. (I feel like this is the wrong way to go about it but I tried anyway)
DataTemplate
<DataTemplate DataType="{x:Type md:CUser}">
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel}}" Value="True">
<Setter Property="DataTemplate" Value="{StaticResource UserCollapsed}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
ItemsControl
<ItemsControl Visibility="{Binding ColumnVisibility}"
Style="{StaticResource userTemplateStyle}"
BorderThickness="0"
Name="itcLoggedInUsers"
Margin="0"
ItemsSource="{Binding LoggedInUsers}"
Grid.Row="1"/>
Your code works fine for me...
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication8="clr-namespace:WpfApplication8"
Title="MainWindow"
Width="525"
Height="350">
<Window.Resources>
<WpfApplication8:ViewModel x:Key="ViewModel" />
<DataTemplate x:Key="UserCollapsed" />
<DataTemplate x:Key="UserExpanded">
<StackPanel Width="200"
Height="200"
Background="Red">
<TextBlock Text="Firstname" />
<TextBlock Text="Lastnamehere" />
</StackPanel>
</DataTemplate>
<Style x:Key="userTemplateStyle" TargetType="ItemsControl">
<Setter Property="ItemTemplate" Value="{StaticResource UserExpanded}" />
<Style.Triggers>
<DataTrigger Binding="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel}}" Value="True">
<Setter Property="ItemTemplate" Value="{StaticResource UserCollapsed}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid x:Name="grid" DataContext="{StaticResource ViewModel}">
<ItemsControl Name="itcLoggedInUsers"
Grid.Row="1"
Margin="0"
BorderThickness="0"
ItemsSource="{Binding LoggedInUsers}"
Style="{StaticResource userTemplateStyle}" />
</Grid>
And the ViewModel
public class ViewModel: INotifyPropertyChanged
{
private bool _columnIsCollapsed;
public ViewModel()
{
ColumnIsCollapsed = false;
LoggedInUsers = new ObservableCollection<User>();
LoggedInUsers.Add(new User(){FirstName = "SSSSSS", LastName = "XXXXXX"});
}
public bool ColumnIsCollapsed
{
get { return _columnIsCollapsed; }
set
{
_columnIsCollapsed = value;
OnPropertyChanged(new PropertyChangedEventArgs("ColumnIsCollapsed"));
}
}
public ObservableCollection<User> LoggedInUsers { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
}
public class User
{
public string ImageFile { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
I over thought this problem. If I needed to show or hide an element in the DataTemplate based on a boolean property of the ViewModel, I could just bind the visibility of the element to the property on the ViewModel, and use a converter to return a Visibility.
Solution
<DataTemplate DataType="{x:Type md:User}">
<StackPanel>
<Image Source="/Images/anon.png"
Height="50"
Width="50"
Margin="0,5,0,0"/>
<TextBlock Text="Firstname" Visibility="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel},Converter={StaticResource InvertBoolVisibility}}"/>
<TextBlock Text="Lastnamehere" Visibility="{Binding ColumnIsCollapsed, Source={StaticResource ViewModel},Converter={StaticResource InvertBoolVisibility}}"/>
</StackPanel>
</DataTemplate>
Converter
public class InvertBoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var theBool = (bool)value;
if (theBool)
return Visibility.Collapsed;
else
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have following code. Here listClear is an object, which is filled by ViewModel. I am using properties of this object to fill a Grid. In below code what property should I use to make Button disable in DataTrigger. I want Button to be disabled when Grid is empty, otherwise it should be enabled.
<Button Grid.Column="3" Margin="2" Command="{Binding Path=ClearCommand}" Content="Clear">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=listClear}" Value="">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
You can use the List Count property for this to indicate empty
Example:
public partial class MainWindow : Window
{
private ObservableCollection<string> myVar = new ObservableCollection<string>();
public MainWindow()
{
InitializeComponent();
MyList.Add("test");
}
public ObservableCollection<string> MyList
{
get { return myVar; }
set { myVar = value; }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MyList.Clear();
}
}
Xaml:
<Window x:Class="WpfApplication11.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication11"
Title="MainWindow" Height="136.3" Width="208" x:Name="UI">
<Grid DataContext="{Binding ElementName=UI}">
<Button Content="Clear" Click="Button_Click">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="True" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=MyList.Count}" Value="0">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</Window>
If your only using IEnumerable<T> its a bit more difficult because IEnumerable has no public properties to bint to, you would have to make a converter.
Something like this
public class IsEmptyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is IEnumerable)
{
var enumerable = (IEnumerable)value;
foreach (var item in enumerable)
{
return false;
}
}
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Xaml:
<Window x:Class="WpfApplication11.MainWindow"
xmlns:local="clr-namespace:Namespace for converter"
....
....
<Window.Resources>
<local:IsEmptyConverter x:Key="IsEmptyConverter" />
</Window.Resources>
....
....
<DataTrigger Binding="{Binding Path=MyList, Converter={StaticResource IsEmptyConverter}}" Value="true">
i've created a Datagrid Control in WPF. how can i make the Button visible only for
row that i have select it so that my Button will be shown in the Button-Column-Cell.
XAML:
<DataGridTemplateColumn x:Name="Button-Column" Header="H." Width="50">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=ObjectType}" Value="E">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ObjectType}" Value="F">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ObjectType}" Value= "P">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</DataTemplate.Triggers>
<Button Name="btnTable" Visibility="{Binding Path=ObjectType}" Height="20"
Width="25" Click="Button_Table_Click">
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Here is a solution using multibinding :
xaml:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication8="clr-namespace:WpfApplication8"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<WpfApplication8:ButtonVisibilityConverter x:Key="buttonVisibilityConverter"/>
</Window.Resources>
<DataGrid x:Name="dataGrid" SelectedItem="{Binding MySelectedItem}" ItemsSource="{Binding MyObjectList}" SelectionMode="Single">
<DataGrid.Columns>
<DataGridTemplateColumn Header="H." Width="50">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button
Height="20"
Width="25">
<Button.Visibility>
<MultiBinding Converter="{StaticResource buttonVisibilityConverter}">
<Binding Path="Parent.MySelectedItem"/>
<Binding></Binding>
</MultiBinding>
</Button.Visibility>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Window>
Code behind :
namespace WpfApplication8
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public class Toto
{
public object Parent { get; set; }
public string Name { get; set; }
public string Content { get; set; }
public Toto(string name, string content, object parent)
{
this.Name = name; this.Content = content; this.Parent = parent;
}
}
private object _mySelectedItem;
public object MySelectedItem
{
get { return _mySelectedItem; }
set
{
_mySelectedItem = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("MySelectedItem"));
}
}
}
private List<Toto> _myObjectList;
public List<Toto> MyObjectList
{
get { return _myObjectList; }
set { _myObjectList = value; }
}
public MainWindow()
{
this.MyObjectList = new List<Toto>
{
new Toto("toto1", "content toto1", this),
new Toto("toto2", "content toto2", this)
};
InitializeComponent();
this.DataContext = this;
}
}
}
Converter :
class ButtonVisibilityConverter : IMultiValueConverter
{
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] == values[1])
{
return Visibility.Visible;
}
else
{
return Visibility.Hidden;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}