I have a <TextBlock x:Key="_tb1"/> and another <TextBlock x:Key="_tb2"/>.
How to set visibility of _tb1 when for exemple IsMouseOver of _tb2 is true ?
As #MuhammadSulaiman correctly wrote, x:Key is used only in resources and will not work in layout.
You must specify x:Name in the layout.
And then this XAML will work:
<StackPanel>
<TextBlock x:Name="tb1" Text="Some Text" Background="Transparent"/>
<TextBlock x:Name="tb2" Text="Popup text" Background="LightYellow">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=tb1}"
Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
x:Key is allowed for resources and dictionary elements only! Code won't compile/run when x:Key is declared in <TextBloxk/>.
This is an example of what you want to implement..
In xaml
<TextBlock Text="AA"
x:Name="AA"
MouseEnter="AA_OnMouseEnter"
MouseLeave="AA_OnMouseLeave"/>
<TextBlock Text="BB"
x:Name="BB"/>
In code behind
private void AA_OnMouseEnter(object sender, MouseEventArgs e)
{
BB.Visibility = Visibility.Hidden;
}
private void AA_OnMouseLeave(object sender, MouseEventArgs e)
{
BB.Visibility = Visibility.Visible;
}
Related
I'm new to WPF so please forgive any of the below that doesn't make sense...
I've set up a view model, which is bound to a WPF List view data template. The source objects (belonging to a class called BrowserItem) are in an ObservableCollection, and I use a CollectionViewSource which diplays them in the ListView - after several headaches this works really well.
I thought the simplest part would be the handling when a user double clicks on something, but I was wrong.
The Event attached to the ListView returns the TextBlock control rather than the BrowserItem source object that was clicked on.
Can anyone point me to a simple way of obtaining the original item (BrowserItem) when the control is clicked on - I've seen several ways of doing this, but they all seem very complex to my simple mind.
A simple example would be great.
This is the XAML for the list view if its of use:
<ListView Name="ViewList"
ItemsSource="{Binding GroupItems}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Expander>
<Expander.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Children.Count}"
Value="0">
<Setter Property="Expander.Visibility"
Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<ListBox ItemsSource="{Binding Children}" />
</Expander>
<TextBlock Text="{Binding Name}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Active}"
Value="true">
<Setter Property="Background"
Value="YellowGreen" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander>
<Expander.Header>
<TextBlock Text="{Binding Name}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
Thanks.
You can use EventSetter to add MouseDoubleClick event to listview like below:
<ListView ItemsSource="{Binding Source}" SelectedItem="{Binding SelectedModel, Mode=TwoWay}">
<!--<Behaviors:Interaction.Triggers>
<Behaviors:EventTrigger EventName="MouseDoubleClick">
<Behaviors:InvokeCommandAction Command="{Binding DataContext.Command, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" />
</Behaviors:EventTrigger>
</Behaviors:Interaction.Triggers>-->
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="MouseDoubleClick" Handler="ListViewItem_MouseDoubleClick" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:Model}">
<TextBlock Text="{Binding Age}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In this way you just handle it in code behand , not in ViewModel.
If you want handle it in viewmodel, you need one class like this:
public class EventToCommand
{
public static string GetEventName(DependencyObject obj)
{
return (string)obj.GetValue(EventNameProperty);
}
public static void SetEventName(DependencyObject obj, string value)
{
obj.SetValue(EventNameProperty, value);
}
public static readonly DependencyProperty EventNameProperty =
DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(EventToCommand), new PropertyMetadata("", OnEventNameChanged));
public static void OnEventNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public static ICommand GetCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(CommandProperty, value);
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventToCommand), new PropertyMetadata(OnCommandChanged));
public static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as FrameworkElement;
EventInfo eventInfo = d.GetType().GetEvent(GetEventName(d));
var eventHandlerMethodInfo = typeof(EventToCommand).GetMethod("Invoke", BindingFlags.Static | BindingFlags.Public);
eventInfo.AddEventHandler(d, Delegate.CreateDelegate(eventInfo.EventHandlerType, eventHandlerMethodInfo));
}
public static void Invoke(object sender,EventArgs e)
{
var command = GetCommand(sender as FrameworkElement);
command.Execute(e);
}
}
And use class EventToCommand like this:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="local:EventToCommand.EventName" Value="MouseDoubleClick" />
<Setter Property="local:EventToCommand.Command" Value="{Binding DataContext.Command, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" />
</Style>
</ListView.ItemContainerStyle>
I have a dynamic ListView using a DataTemplate as follows:
<ListView.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="#ccc">
<RadioButton GroupName="MyRadioButtonGroup">
<StackPanel Orientation="Horizontal" Margin="0,0,0,5" Width="{Binding ActualWidth, ElementName=CheckoutGrid}">
<TextBlock Text="{Binding Path=Test1, StringFormat='{}{0} - '}" />
<TextBlock Text="{Binding Path=Test2, StringFormat='{} test {0} - '}" />
<TextBlock Text="{Binding Path=Test, StringFormat='{} test {0}'}" />
</StackPanel>
</RadioButton>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
I would like to have a button disabled until one of the RadioButton IsChecked:
<RadioButton Padding="15,10" VerticalAlignment="Center">
<RadioButton.Style>
<Style TargetType="RadioButton" BasedOn="{StaticResource styleToggleButton4}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MyRadioButtonGroup, Path=IsChecked}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
<TextBlock FontWeight="SemiBold" FontSize="14" Margin="0">NEXT</TextBlock>
</RadioButton>
So the problem is I do not know how to properly bind to the RadioButton GroupName="MyRadioButtonGroup". You will see in the DataTrigger above I am trying Binding="{Binding ElementName=MyRadioButtonGroup, Path=IsChecked}" Value="False", but that is not working for me since obviously it is a GroupName and not an x:Name.
Any suggestions on how to approach this properly? I would rather want to handle this on the front-end if at all possible.
You could bind your radio button to a command and then use the isChecked as a parameter. Then bind to a boolean value based off that. I think this may be more of a workaround though.
<RadioButton
Command="{Binding MyCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"
GroupName="radio" />
<RadioButton
Command="{Binding MyCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}"
GroupName="radio" />
Then in code behind or VM, it would require implementing the ICommand Interface and INotifyPropertyChanged
public bool IsChecked
{
get { return isChecked;}
set
{
isChecked = value;
OnPropertyChanged();
}
}
private void OnMyCommand(object obj)
{
if(obj is bool)
{
IsChecked = (bool)obj;
}
}
A group has no IsChecked property that you can bind to.
If you don't have a source property that keeps track of whether there is at least one checked RadioButton and "want to handle this on the front-end" - which I guess means in the view - you could write some code that simply sets the Tag property of the ListView to true/false depending on whether there is a RadioButton selected. It is a one-liner:
private void ListView_Checked(object sender, RoutedEventArgs e) => lv.Tag = true;
<ListView x:Name="lv" ToggleButton.Checked="ListView_Checked">
<ListView.ItemTemplate>
...
<ListView.ItemTemplate>
</ListView>
<RadioButton Padding="15,10" VerticalAlignment="Center">
<RadioButton.Style>
<Style TargetType="RadioButton" BasedOn="{StaticResource styleToggleButton4}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=lv, Path=Tag}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</RadioButton.Style>
<TextBlock FontWeight="SemiBold" FontSize="14" Margin="0">NEXT</TextBlock>
</RadioButton>
I know it is possible to do this by working with ICommand, but since this is the only place in my whole project where this is needed, I am asking myself, if there is maybe a better solution than implementing RelayCommand and ICommand and an additional method in my otherwise property-only class?
Maybe my scenario may help here:
I have a ListView which is bound to a list of properties (this is a custom-class I made to display those).
I have a button in eacht row of entries, that I want to set the "IsToDelete"-Property to true.
If "IsToDelete" is true, all the controls I show in my ListView will collapse.
The whole logic is up to this point in DataTemplates, the one for my button looks like this:
<DataTemplate x:Key="DeleteButtonTemplate">
<Button Name="bt_Delete"
Command="{Binding RelativeSource={RelativeSource AncestorType=ListView}, Path=ItemSource.DeleteClicked}">
<Image Height="16" Width="16" Source="Images\RecycleBin\VSO_RecycleBin_16x.png"/>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsToDelete}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
Note the command in this DataTemplate is currently not working as intended, that is why I even got to the question ;)
In the optimal case I'd just have to do something like:
<Setter Property="{Binding IsToDelete}" Value="True"/>
So, is there a way to solve it like this or at least in a less complicated way than ICommand with RelayCommand?
why not use ToggleButton and bind IsChecked property to IsToDelete property of a viewModel?
simplified example with ItemsControl
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ToggleButton Content="X" IsChecked="{Binding Path=IsToDelete}"/>
<Border Width="100"
Background="MediumPurple"
Margin="5">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsToDelete}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You could use the Click eventhandler of the Button. Then you don't need any Commands.
private void bt_Delete_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
YourClass dc = btn.DataContext as YourClass;
dc.IsToDelete = true;
}
I don't really like this solution, but I think, it would work.
I have an expander...and a textbox. The textbox is hidden by default. when user click on the expander, I am displaying the text box. This is working fine.
What I need is, when user click on the expander...I need to set the focus in the textbox.
Please help me to do this...I tried with following code...but it seems "IsFocused" is readonly property.
Any help would be appreciated !
<StackPanel>
<DockPanel>
<TextBlock DockPanel.Dock="Left" Text="ID"/>
<Expander x:Name="ID" DockPanel.Dock="Right" IsExpanded="False" ExpandDirection="Down">
</Expander>
</DockPanel>
<TextBox Text="{Binding Path=SearchCCCId.Value,UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding ElementName=ID,Path=IsExpanded,Converter={x:Static local:Converters.BoolToVisibility}}" Width="70" >
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ID, Path=IsEpanded}" Value="True" >
<Setter Property="IsFocused" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
With all your help, I am able to find out the answer...
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ID, Path=IsExpanded}" Value="True">
<Setter Property="FocusManager.FocusedElement"
Value="{Binding ElementName=PropertyIDSearch}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
IsFocused is ReadOnly property. You may want to look at these -
How to set focus to textbox using MVVM?
WPF - Set Focus when a button is clicked - No Code Behind
You can handler Expanded event of Expander and set focus inside handler method.
private void OnExpanderExpanded(object sender, RoutedEventArgs args)
{
txtTest.Focus();
}
I have a simple WPF application with a Window. This window has a dependency property.
public static readonly DependencyProperty ShiftProperty;
static VirtualKeyboard()
{
ShiftProperty = DependencyProperty.Register("Shift", typeof(bool), typeof(VirtualKeyboard));
}
public bool Shift
{
get { return (bool)GetValue(ShiftProperty); }
set { SetValue(ShiftProperty, value); }
}
Now, on this window I have a button that I wish to visually display if Shift is True or not, by applying a style.
I admit to not being very experienced in WPF, but I believe this can be solved using Data triggers. My problem is hooking it up.
Here is the xaml for the button.
<Button Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="0" Command="local:VirtualKeyboard.ShiftButtonPressedCommand" Content="Shift" Name="ShiftButton">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Shift}" Value="True">
<Setter Property="Control.Background" Value="Black">
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I'll appreciate all help I can get.
Thanks,
Stefan
You are right.You can do it with datatriggers.You need to set the datacontext of the widow to this for this to work.Otherwise the binding will not be able to access your dependency property.
public VirtualKeyboard()
{
InitializeComponent();
DataContext = this;
}
and specify your style like
<Button Grid.Column="0" Content="Shift" Name="ShiftButton">
<Button.Style>
<Style>
<Setter Property="Button.Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Shift}" Value="True">
<Setter Property="Button.Visibility" Value="Visible">
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>