In WPF I have this code for disabling a menuitem on a certain condition:
private void gridListPlayers_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
Player player = (Player)gridListPlayers.SelectedItem;
if(player.Owner.GUID == Guid.Empty.ToString())
{
propMenuItem.IsEnabled = false;
}
else
{
propMenuItem.IsEnabled = true;
}
}
I'm trying to achieve the same result of that function via XAML. Is there a simple way to do that?
You can set the visibility on or off according to a property in your selected Item. So create read only property ToggleMenuVisible, which returns (Owner.GUID != Guid.Empty.ToString()) and then in your xaml do something like:
<MenuItem x:Name="MyToggleMenu" Header="My Toggle Menu" >
<MenuItem.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.ToggleMenuVisible}" Value="False">
<Setter Property="UIElement.Visibility" Value="Collapsed" />
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItem.ToggleMenuVisible}" Value="True">
<Setter Property="UIElement.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
Obviously you will need to include SelectedItem in your view's model.
Related
I have a simple DataGrid with the following column:
<DataGridTextColumn Header="Column" Binding="{Binding ColumnValue, Mode=TwoWay, UpdateSourceTrigger=LostFocus}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="IsEnabled" Value="{Binding IsColumnEnabled}" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Gray" />
<Setter Property="Foreground" Value="Transparent" />
</Trigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
Let's assume two rows, the second one is disabled. When I enter a value into the first cell and hit Enter, the focus doesn't jump to the next cell (because it's disabled). The problem is, I cannot enter into edit mode again with doubleclick until the current cell is focused.
Is there any trick to avoid this?
If you want to implement a custom behaviour for Enter key presses, you could override the OnKeyDown method in a custom class:
public class CustomDataGrid : DataGrid
{
protected override void OnKeyDown(KeyEventArgs e)
{
if(e.Key == Key.Return)
{
var currentCell = CurrentCell;
base.OnKeyDown(e);
if (CurrentCell.Column.GetCellContent(CurrentCell.Item)?.Parent is DataGridCell cell && !cell.IsEnabled)
CurrentCell = currentCell;
}
else
{
base.OnKeyDown(e);
}
}
}
Don't forget to change the root element of the DataGrid in your XAML:
<local:CustomerDataGrid ... />
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>
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"; }
}
I have a search box which i am trying to to check if it is empty by using the "hasdata" and if empty return false else return true, but the DataTrigger Binding is not working. can someone point me in the right direction on what i am doing wrong.
code:
public bool hasdata
{
get { if (searchBox.Text.Count() == 0) return false; else return true; }
}
xaml:
<telerik:RadWatermarkTextBox x:Name="searchBox"/>
<Image Source="SomeImage.png" >
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=hasdata}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=hasdata}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
The UI has currently no way of being notified when hasdata is changed. You need to either implement the INotifyPropertyChanged interface or make hasdata a DependencyProperty.
Hi i am trying to put what i am doing in the events from Code Behind in Triggers of a Style who is being applied in a TextBox. What i want is to prevent using the Code Behind to do that and use Triggers. Is there any way to accomplish this?
My Textbox
<TextBox Name="myTextBox" Style="{StaticResource txtBoxStyle}"/>
My style
<Style x:Key="txtBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Silver"/>
<Setter Property="MaxLength" Value="6"/>
</Style>
The Events from Code Behind
private void myTextBox_LostFocus(object sender, RoutedEventArgs e)
{
if (myTextBox.Text.Length == 0)
myTextBox.Text = "000000";
}
private void myTextBox_GotFocus(object sender, RoutedEventArgs e)
{
if (myTextBox.Text == "000000")
myTextBox.Clear();
}
private void myTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (!(e.Key >= Key.D0 && e.Key <= Key.D9) && e.Key != Key.Back)
e.Handled = true;
}
private void myTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (myTextBox.Text == "000000")
myTextBox.Foreground = Brushes.Silver;
else
{
myTextBox.Foreground = Brushes.Black;
if(myTextBox.Text.Length == 6)
myButton.Visibility = Visibility.Visible;
else
myButton.Visibility = Visibility.Hidden;
}
}
Thanks in advance!
Edit: Using triggers for this logic is not a good idea and will in all likelihood fail because of its self-referencing (causes a stack-overflow), value converters are also a bit problematic. To encapsulate complex logic and apply it via a Style use an attached behavior.
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsFocused, RelativeSource={RelativeSource Self}}" Value="False"/>
<Condition Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value=""/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Text" Value="000000"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsFocused, RelativeSource={RelativeSource Self}}" Value="True"/>
<Condition Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value="000000"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Text" Value=""/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<Trigger Property="Text" Value="000000">
<Setter Property="Foreground" Value="Silver"/>
</Trigger>
</Style.Triggers>
<!-- If (Text != "000000") Foreground = Brushes.Black -->
<Setter Property="Foreground" Value="Black"/>
</Style>
The logic which sets the visibility of the button should not be handled in this style but by the button. The key-down event cannot be translated.
Button style:
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Hidden"/> <!-- Normal state -->
<Style.Triggers>
<DataTrigger Binding="{Binding Text.Length, ElementName=myButton}" Value="6">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>