WPF binding visibility to gridview listview button - c#

How do I bind the visibility of a button inside a listview without using converter, but using the data trigger property. But i not manage to understand how to code behind. Do we still need to use Boolean property to hold the true/ false value? If yes, how to implement that? Sorry that i am new to WPF, and still not able to understand those complex code badly.
private void Btnfolder_Click(object sender, RoutedEventArgs e)
{
try
{
// the excel file open from here to display gridview with button true and false for certain rows but i do not know how to set the visibility here
}
catch (Exception ex){
MessageBox.Show(ex.ToString());
}
}
public bool _isVisible = false;
public bool IsVisible
{
get { return _isVisible; }
set
{
_isVisible = value;
OnPropertyChanged("IsVisible"); --> error- cannot convert from string to System.Windows.DependencyPropertyChangedEventArgs
}
}
<GridViewColumn Header="View CriticalPart" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button x:Name="btnCritical" Content="Edit" Click="Button_Click" Width="80" Height="30" Margin="5" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

Related

WPF datagrid change row color based on a property value

I have a WPF Datagrid that is filled with a CollectionViewSource and what I want is to change the row background color depending on a binded property value.
Red if value is "KO"
Green if value is "OK"
Yellow if value is "Created"
I've read different threads here on SO such as Change Data bound WPF Datagrid row background/foreground color depending on the boolean property of an object or WPF Datagrid row colour based on value but still struggling to make this work.
I don't know what is wrong with my code. Here is what I tried:
Main.Xaml
<UserControl.DataContext>
<Viewmodel:LoadServerViewModel/>
</UserControl.DataContext>
<Grid Margin="10,20,20,20" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="6">
<DataGrid AutoGenerateColumns="False"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
VerticalAlignment="Stretch"
IsReadOnly="False"
ItemsSource="{Binding Servers}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding RowStatus}" Value="Created">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
<DataTrigger Binding="{Binding RowStatus}" Value="OK">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding RowStatus}" Value="KO">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Last Update" Binding="{Binding LastUp} />
....
</DataGrid.Columns>
</DataGrid>
</Grid>
<Button Style="{DynamicResource RoundedButtonStyle}" Grid.Row="1" Grid.Column="3"
Content="Refresh"
Margin="0,0,40,0"
Height="25"
Width="90"
Foreground="#FFFFFF"
Background="#2f3640"
Command="{Binding ButtonRefresh}">
</Button>
LoadServerViewModel.cs
private string _rowStatus = "Created";
private readonly RelayCommand _buttonRefresh;
public string RowStatus
{
get => _rowStatus;
set
{
_rowStatus = value;
OnPropertyChanged(nameof(RowStatus));
}
}
public ICollectionView Servers
{
get
{
if (_collectionViewSource.View != null)
{
_collectionViewSource.View.CurrentChanged += (sender, e) => ServerGridFormat = _collectionViewSource.View.CurrentItem as ServerGridFormat;
return _collectionViewSource?.View;
}
return null;
}
}
public ServerGridFormat ServerGridFormat
{
get => _servergridformat;
set
{
servergridformat = value;
OnPropertyChanged(nameof(ServerGridFormat));
}
}
public LoadServerViewModel() {
// Button to trigger the change of RowStatus from "Created" to "OK" therefore the color of all rows
_buttonRefresh = new RelayCommand(o => RowStatus = "OK");
}
Thanks for your help
You current binding uses the DataContext of the individual row as binding source (which is the data model stored in the ItemsSource). But your property RowStatus is defined on the object that is the DataContext of the DataGrid (which is the LoadServerViewModel).
To make it work, you must adjust your data bindings to use the correct source (or alternatively move the RowSatus property to the data models):
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}, Path=DataContext.RowStatus}"
Value="Created">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>

Get Control (Button) from parent in usercontrol

I have a window with different items and different views for each type.
I would like to access the button in the window (parent) from my code behind from the content control.
OutputConfigView:
<ContentControl Margin="5">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedOutputRendererTyp}" Value="{x:Type outTypes:XmlBarcodeRenderer}">
<Setter Property="ContentTemplate" Value="{StaticResource OutputRendererView}"/>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedOutputRendererTyp}" Value="{x:Type outTypes:CsvBarcodeRenderer}">
<Setter Property="ContentTemplate" Value="{StaticResource CsvOutputRendererView}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
.
.
<Button x:Name="CloseButton"
Grid.Column="1"
Click="WindowClose"
Content="Ok"
Margin="0 0 0 -5"
HorizontalAlignment="Center"
VerticalAlignment="Bottom">
</Button>
OutputRendererView.xaml.cs:
public partial class OutputRendererView : UserControl
{
public OutputRendererView()
{
InitializeComponent();
}
private void Border_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var parentWindow = (OutputRendererView)this.Parent;
var button = (Button)parentWindow.FindName("CloseButton");
}
In this case the parentWindow is null.
How can I access the button of the calling window from the code behind of my control ?
To access the button inside the user control, you must first find the usercontrol and then the button inside it.
var button = (Button)((UserControl)parentWindow.FindName("userControlName")).FindName("CloseButton");

CheckBox does not react to unchecking [duplicate]

This question already has answers here:
How do I make a textbox visible and hidden with a checkbox?
(3 answers)
Closed 4 years ago.
I have 3 CheckBoxes and I want to disable/enable two of them when the other one is checked/unchecked. The first step works (if I check checkBoxcaja, the other two checkBoxes are disabled well, but when I uncheck checkBoxcaja, the other two checkBoxes don't return to their original Enabled state.
What am I doing wrong?
I'm a newbie in WPF.
This is the code:
private void checkBoxcaja_Checked(object sender, RoutedEventArgs e)
{
if (checkBoxcaja.IsChecked == true)
{
checkBoxbanderola.IsEnabled = false;
checkBoxletra.IsEnabled = false;
}
else if (checkBoxcaja.IsChecked == false)
{
checkBoxbanderola.IsEnabled = true;
checkBoxletra.IsEnabled = true;
}
}
Thanks in advance
I'm taking a guess here and say you connected this to the Checked event.
Well, that's only fired if the box is checked. There is an Unchecked event that is fired when it is unchecked so you need to connect to that as well. Half you method belongs there.
private void checkBoxcaja_Checked(object sender, RoutedEventArgs e)
{
checkBoxbanderola.IsEnabled = false;
checkBoxletra.IsEnabled = false;
}
private void checkBoxcaja_Unchecked(object sender, RoutedEventArgs e)
{
checkBoxbanderola.IsEnabled = true;
checkBoxletra.IsEnabled = true;
}
Don't forget to hook them up. Alternatively, you can use the same event handler for both.
You can also do this completely in XAML with Datatriggers:
<CheckBox x:Name="CBOne" Grid.Column="1" Grid.Row="3" Content="One" HorizontalAlignment="Center" VerticalAlignment="Center"></CheckBox>
<CheckBox x:Name="CBTwo" Grid.Column="2" Grid.Row="3" Content="Two" HorizontalAlignment="Left" VerticalAlignment="Center">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="True">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="False">
<Setter Property="IsEnabled" Value="True"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<CheckBox x:Name="CBThree" Grid.Column="2" Grid.Row="3" Content="Three" HorizontalAlignment="Right" VerticalAlignment="Center">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="True">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=CBOne, Path=IsChecked}" Value="False">
<Setter Property="IsEnabled" Value="True"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>

ListBox HasItems DataTrigger not working when Items are cleared from ItemsSource

I have a Listbox and I have a DataTrigger in xaml to check if there are no items in the ListBox then Hide it (Please see the HasItems DataTrigger). At some point in my application I am Clearing the items from the ItemsSource i.e FilteredVolumesList (Please see the DeSelectAssays method) assuming the ListBox would be hidden because there are no Items In the ItemsSource.
But the problem is the DataTrigger dosen't seem to work and the ListBox is not being collapsed. Please help. I dont want to create a bool property for visibility and keep setting to false. Please note I am doing something like this in xaml ListBox CLear Items Xamly
Here is my xaml
<ListBox
Grid.Row="1"
x:Name="LstVolumes"
HorizontalAlignment="Center"
Margin="0,90,0,0"
VerticalAlignment="Top"
ItemsSource="{Binding FilteredVolumesList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
SelectionChanged="LstVolumes_SelectionChanged"
BorderThickness="0">
<ListBox.Style>
<Style
TargetType="{x:Type ListBox}"
BasedOn="{StaticResource ListBoxDarkBackgroundStyle}">
<Setter
Property="Template"
Value="{StaticResource ListBoxVolumesTemplate}"></Setter>
<Style.Triggers>
<DataTrigger
Binding="{Binding HasItems,RelativeSource={RelativeSource Self},UpdateSourceTrigger=PropertyChanged}"
Value="False">
<Setter
Property="Visibility"
Value="Collapsed"></Setter>
</DataTrigger>
<DataTrigger
Binding="{Binding DataContext.IsVolumeRepeaterVisible,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}}"
Value="False">
<Setter
Property="Template"
Value="{StaticResource ListBoxNoRepeaterTemplate}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Button
x:Name="VolumesButton"
Style="{StaticResource ButtonLightTextGradientDarkBackgroundStyle}"
Margin="{StaticResource AllControlsMargin}"
Click="VolumesButton_Click">
<Button.Content>
<StackPanel
x:Name="stkInnerChildPanel"
Orientation="Vertical"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock
Style="{StaticResource TextBlockLightTextStyle}"
x:Name="TblVolume"
Text="{Binding volume_display_value,StringFormat={}{0} µg}"></TextBlock>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And I am clearing the items like this from the code behind
private ReadJsonAssayViewModel AssayViewModel = null;
public RunSetUpMainContentUserControl()
{
InitializeComponent();
AssayViewModel = ReadJsonAssayViewModel.ReadJsonAssayViewModelInstance;
this.DataContext = AssayViewModel;
FindAssociatedChildrenInstance = FindChildrenAndAssociatedControlsHelper.FindAssociateChildrenInstance;
Messenger.Default.Register<NotificationMessage>(this, DeSelectAssays);
}
private void DeSelectAssays(NotificationMessage obj)
{
for (int i = 0; i < LstAssays.Items.Count; i++)
{
ToggleButton btn = FindAssociatedChildrenInstance.AssociatedPanel(LstAssays, "AssaysButton", i, TargetType.ListAssays, typeof(ToggleButton)) as ToggleButton;
btn.IsChecked = false;
}
LstAssays.SelectedIndex = -1;
AssayViewModel.FilteredVolumesList.Clear();
AssayViewModel.IsStartRunEnabled = false;
this.Focus();
}
Here is the FilteredVolumesList in the viewmodel
private List<Volume> _filteredVolumesList;
public List<Volume> FilteredVolumesList
{
get
{
return _filteredVolumesList;
}
set
{
_filteredVolumesList = value;
OnPropertyChanged("FilteredVolumesList");
}
}

Changing button content according to DataGrid SelectedItem property

I have a WPF Window and a Viewmodel and I need to change the content of a button to fit the property of the SelectedItem in the Datagrid.
For example:
The DataGrid is bound to a list of tasks with two properties: Name and EndDate. If EndDate is null I want the button to display 'End Task' and if it is not null to display 'Resume Task'
I managed to hide the button if SelectedItem is null, but I can't figure out a way to do this.
Here is the XAML code that I have for the button:
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Tasks}"
x:Name="dg"
SelectedItem="{Binding SelectedTask}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTextColumn Header="End Date" Binding="{Binding EndDate}"/>
</DataGrid.Columns>
</DataGrid>
<Button Content="{Binding ButtonText}"
Name="btn_close_resume"
Command="{Binding CloseResumeCommand}"
CommandParameter="{Binding ElementName=dg, Path=SelectedItem}">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedTask}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
On the ViewModel I have the ButtonText property like this:
public string ButtonText
{
get { return this.SelectedTask.EndDate == null ? "Close Task" : "Resume Task"; }
}
But the Button doesn't display any text.
How can I do this?
You can use another DataTrigger to set the content on the button based on the SelectedTask EndDate value
<Button
Name="btn_close_resume"
Command="{Binding CloseResumeCommand}"
CommandParameter="{Binding ElementName=dg, Path=SelectedItem}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Content" Value="Resume Task"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedTask}" Value="{x:Null}">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedTask.EndDate}" Value="{x:Null}">
<Setter Property="Content" Value="Resume Task"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
How ever as you didn't say what's the default value of the button's content when there's nothing selected on the datagridview, the button will say "Resume Task" until something gets selected. If you need to change this, you will need to use a converter.
If you really want to do it through the view model, you have to notify the changes in the SelectedTask setter:
public Task SelectedTask
{
get { return selectedTask; }
set
{
selectedTask = value;
OnPropertyChanged("SelectedTask");
OnPropertyChanged("ButtonText");
}
}
public string ButtonText
{
get { return this.SelectedTask.EndDate == null ? "Close Task" : "Resume Task"; }
}

Categories