How to make a WPF listbox item not clickable - c#

I am using a listbox to display a list of items that I am selecting programmatically in a voice activated program. Is there any way to keep the selected item from being clicked on? I do want mouse over functionality, just not clicking on the actual item.
I have tried to set Focusable (does not do anything for what I want) and IsEnabled (disables mouse over)
Here is my current style:
<Style x:Key="GlyphList" TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" IsEnabled="False"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate DataType="models:SpellingGlyph">
<Label VerticalAlignment="Bottom">
<Label.Template>
<ControlTemplate>
<Grid>
<TextBlock Name="MainText" Text="{Binding Text}" VerticalAlignment="Bottom" Margin="0,0,5,0"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource ObjectReferenceEqualityConverter}">
<Binding />
<Binding Path="SelectedItem" RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBox}"/>
</MultiBinding>
</DataTrigger.Binding>
<Setter TargetName="MainText" Property="Foreground" Value="#75BAFF"/>
<Setter TargetName="MainText" Property="FontWeight" Value="SemiBold"/>
<Setter TargetName="MainText" Property="FontSize" Value="22"/>
</DataTrigger>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource MultiBooleanConverter}"> <!--SelectedItem trumps mouse over-->
<Binding ElementName="MainText" Path="IsMouseOver"/>
<Binding Path="SelectedItem" RelativeSource="{RelativeSource FindAncestor, AncestorType=ListBox}" Converter="{StaticResource InvertedNullCheckToBooleanConverter}"/>
</MultiBinding>
</DataTrigger.Binding>
<Setter TargetName="MainText" Property="Foreground" Value="#75BAFF"/>
<Setter TargetName="MainText" Property="FontWeight" Value="SemiBold"/>
<Setter TargetName="MainText" Property="FontSize" Value="22"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Label.Template>
</Label>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>

<ListBox PreviewMouseDown="ListBox_OnPreviewMouseDown"..
private void ListBox_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}

An alternative solution to what I accepted was to add the following in my view model:
if (_viewModelSetSelectedGlyph != value) return;
_selectedGlyph = value;
OnPropertyChanged("SelectedGlyph");
Then, set the _viewModelSetSelectedGlyph each time before actually setting the SelectedGlyph. Then, when the UI tries to set the SelectedGlyph, it would not succeed, only when the view model sets it by also setting the private variable does it succeed.

Simply set IsHitTestVisible to false
https://msdn.microsoft.com/en-us/library/system.windows.uielement.ishittestvisible(v=vs.110).aspx

Related

User Prism Library With WPF, DataTrigger can not be triggered in ItemContainerStyle. Any Suggestion to get Instance of ViewModel

In MVVM pattern without Prism Library with WPF , view model is injected in manually. DataTrigger Path can be specified by
Path=DataContext.ColumnColorSlideStatus}". It works fine.
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListView}}, **Path=DataContext.ColumnColorSlideStatus}"**
Value="Review">
<Setter Property="Background">
<Setter.Value>
<Binding
Converter="{StaticResource ColumnBackGroundColorConverter}"
ConverterParameter="Review"
RelativeSource="{RelativeSource Self}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListView}}, **Path=DataContext.ColumnColorSlideStatus}"**
Value="NFR">
<Setter Property="Background">
<Setter.Value>
<Binding
Converter="{StaticResource ColumnBackGroundColorConverter}"
ConverterParameter="NFR"
RelativeSource="{RelativeSource Self}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
When Using Prism Library with WPF, the view and viewmodel is linked automatically by code below.
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
There is no instance of DataContext in View Xaml Code. the DataTrigger Path can not be specified to the DataContext.ColumnColorSlideStatus. DataTrigger can not be triggered.
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListView}}, **Path=ColumnColorSlideStatus}"**
Value="Review">
<Setter Property="Background">
<Setter.Value>
<Binding
Converter="{StaticResource ColumnBackGroundColorConverter}"
ConverterParameter="Review"
RelativeSource="{RelativeSource Self}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListView}}, **Path=ColumnColorSlideStatus}"**
Value="NFR">
<Setter Property="Background">
<Setter.Value>
<Binding
Converter="{StaticResource ColumnBackGroundColorConverter}"
ConverterParameter="NFR"
RelativeSource="{RelativeSource Self}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
```
Is any suggestions to get instance of viewmodel into view when Prism Library is used or some way works around it

WPF TextBox selected text does not work

I have a readonly TextBox control with a static resource, looks like this:
<Style TargetType="TextBox" x:Key="MyEditTextEditor">
<Setter Property="FontFamily" Value="{Binding Path=TextEditorFontFamily, ElementName=LogViewerProperty}" />
<Setter Property="FontWeight" Value="{Binding Path=TextEditorFontWeight, ElementName=LogViewerProperty}" />
<Setter Property="FontSize" Value="{Binding Path=TextEditorFontSize, ElementName=LogViewerProperty}" />
<Setter Property="FontStyle" Value="{Binding Path=TextEditorFontStyle, ElementName=LogViewerProperty}" />
<Setter Property="TextWrapping" Value="{Binding Path=WordWrapping, ElementName=LogViewerProperty, Converter={StaticResource BoolToTextWrap}}" />
<Setter Property="Text" Value="{Binding Message, Mode=OneWay}" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<TextBox Text="{TemplateBinding Text}" BorderThickness="0" Margin="-3,-1"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Opacity="0.4" Color="{Binding Source={x:Reference LogViewerProperty}, Path=TextEditorSelectionColor}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
It's embedded into a ListBox. All works fine, but when I want to get the selected text, the property is always string.Empty. The SelectionChanged event works perfect. Any suggestions? At the moment I do not know, why the SelectedText is string.Empty.
Here is the SelectionChanged event
private void ReadOnlyEditor_SelectionChanged(object sender, RoutedEventArgs e)
{
LOG.Debug("Current text {3}; selection {0} length {1}, start {2}", readOnlyEditor.SelectedText, readOnlyEditor.SelectionLength, readOnlyEditor.SelectionStart, readOnlyEditor.Text);
}
And yes, the text is selected in the control, but the property is empty. In readOnlyEditor.Text exists the right text.
Put your data binding into the ListBoxItem, then call the data from the ListBoxItem. Then the whole ListBoxItem is selectable. e.g.
<ListBox SelectionChanged="ListItemSelected" ItemTemplate="{StaticResource SelectedTextTemplate}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
.../...
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Build your data template or control template outside of the ListBox e.g.
<DataTemplate x:Key="SelectedTextTemplate">
<TextBox Text="{Binding SelectedText}"/>
</DataTemplate>

ContextMenu passing multiple parameter to viewmodel

I have a canvas which is bound to a List of items. Each item has his own X and Y field and is painted as rectangles on the canvas.
Each item has its contextmenu which in this case is bound to a List and is filled dynamically (e.g.: "On", "Off").
I'm now trying to pass the sender (item where the Contextmenu is assigned to) and the string of the binding as CommandParameter the viewmodel.
e.g.: itemA, "On"
How should I do this?
Here is my code:
<ItemsControl
x:Name="Overlay"
Grid.Column="1"
GCextAp:Dragging.IsDragging="{Binding IsDragging, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ItemsSource="{Binding Path=MapElements, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas
localAp:MapProperties.GenerateMapElementFunc="{Binding CreateMapElementFunc}"
localAp:MapProperties.IsEditingMode="{Binding IsEditMode}"
localAp:MapProperties.ManipulationFinished="{Binding ManipulationFinishedDelegate}"
localAp:MapProperties.ScaleFactor="{Binding ElementName=Overlay, Path=DataContext.ScaleFactor}"
AllowDrop="True"
RenderOptions.BitmapScalingMode="LowQuality">
<Canvas.Style>
<Style TargetType="Canvas">
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect
BlurRadius="8"
Direction="270"
ShadowDepth="2.5"
Color="#DDDDDD" />
</Setter.Value>
</Setter>
<Setter Property="Opacity" Value="1" />
<Setter Property="Background" Value="{x:Null}" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=Overlay, Path=(GCextAp:Dragging.IsDragging)}" Value="true" />
<Condition Binding="{Binding IsEditMode}" Value="true" />
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="WhiteSmoke" />
<Setter Property="Opacity" Value="0.1" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Canvas.Style>
<i:Interaction.Behaviors>
<localBehave:MapCanvasDropBehavior />
</i:Interaction.Behaviors>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding DynamicX}" />
<Setter Property="Canvas.Top" Value="{Binding DynamicY}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle
Width="{Binding DynamicWidth}"
Height="{Binding DynamicHeight}"
Stroke="Black"
Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Canvas}}"
Visibility="{Binding IsVisible, Converter={StaticResource converter}}">
<Rectangle.Fill>
<ImageBrush ImageSource="{Binding Image}" />
</Rectangle.Fill>
<i:Interaction.Behaviors>
<localBehave:MapElementMoveBehavior />
</i:Interaction.Behaviors>
<Rectangle.ContextMenu>
<ContextMenu>
<MenuItem Header="Commands" ItemsSource="{Binding Path=PlacementTarget.Tag.AvailableElementCommands, RelativeSource={RelativeSource AncestorType=ContextMenu}, UpdateSourceTrigger=PropertyChanged}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding}" />
<Setter Property="Command" Value="{Binding Path=PlacementTarget.Tag.CMD_MapElement, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
<Setter Property="CommandParameter" Value=" I have no idea" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</ContextMenu>
</Rectangle.ContextMenu>
</Rectangle>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Sorry about asking questions which are unclear or not usefull :-). Anyway I found the solution myself.
The command paramater should look like this:
<Setter Property="CommandParameter">
<Setter.Value>
<MultiBinding Converter="{StaticResource menuItemCommandConverter}">
<MultiBinding.Bindings>
<Binding Path="DataContext" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}" />
<Binding Path="Header" RelativeSource="{RelativeSource Mode=Self}" />
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>

Show IDataErrorInfo errors in tooltip on keyboard focus and mouse over

I have a TextBox which shows IDataErrorInfo validation information via a ToolTip by using this style:
<Style x:Key="EntityPropertyTextBoxErrorStyle" TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<!-- this gets rid of all adornment INCLUDING THE DEFAULT RED BORDER -->
<AdornedElementPlaceholder />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="Background" Value="MistyRose" />
</Trigger>
</Style.Triggers>
</Style>
Now I want the ToolTip to show on keyboard focus as well.
The best solution I found was to use a Popup instead of a ToolTip:
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel>
<AdornedElementPlaceholder x:Name="ControlWithError" />
<Popup PlacementTarget="{Binding ElementName=ControlWithError}" Placement="Top">
<Popup.IsOpen>
<MultiBinding Converter="{StaticResource AtLeastOneTrueConverter}">
<Binding Path="AdornedElement.IsMouseOver"
ElementName="ControlWithError" Mode="OneWay" />
<Binding Path="AdornedElement.IsKeyboardFocusWithin"
ElementName="ControlWithError" Mode="OneWay" />
</MultiBinding>
</Popup.IsOpen>
<Border BorderThickness="1">
<TextBlock Text="{Binding
AdornedElement.(Validation.Errors)[0].ErrorContent,
ElementName=ControlWithError}"
Background="White"
FontSize="8" />
</Border>
</Popup>
</StackPanel>
</ControlTemplate>
<Style x:Key="EntityPropertyTextBoxErrorStyle" TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Background" Value="MistyRose" />
</Trigger>
</Style.Triggers>
</Style>

WPF CustomControl switch content of ContentControl

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomControlLibrary1">
<ContentControl x:Key="BackSide" Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Back}" RenderTransformOrigin="0.5,0.5">
<ContentControl.RenderTransform>
<ScaleTransform ScaleX="-1" />
</ContentControl.RenderTransform>
</ContentControl>
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<ContentControl Grid.Row="1">
<ContentControl.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="tf" ScaleX="1" />
</TransformGroup>
</ContentControl.RenderTransform>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Front}" />
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<Binding ElementName="tf" Path="ScaleX">
<Binding.Converter>
<loc:LessThanXToTrueConverter X="0" />
</Binding.Converter>
</Binding>
</DataTrigger.Binding>
<DataTrigger.Setters>
<Setter Property="Content" Value="{StaticResource BackSide}"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This is some XAML code from a customcontrol. Where there are two dependency properties (Front and Back).
Via my DataTrigger I want to change the Content of the ContentControl from using "Front" to using "Back".
At first it shows the depencency property "Front" and then it should use the depencency property "Back" as the Content.
This is done via this code:
<DataTrigger.Setters>
<Setter Property="Content" Value="{StaticResource BackSide}"/>
</DataTrigger.Setters>
But this doesn't work...
I can bind and display the content of the Front dependency property in my control via:
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Front}" />
but I can't figure out how to bind the DataTrigger setter so that it uses the ContentControl's Content with the x:Key="BackSide" ContentControl.
Thanks in advance.
You said that this XAML works:
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource
TemplatedParent}, Path=Front}" />
So why don't you just try putting this XAML into your DataTrigger?:
<Setter Property="Content" Value="{Binding RelativeSource={RelativeSource
TemplatedParent}, Path=Back}" />
UPDATE >>>
I'm not really sure what you're trying to do with your UIElement DependencyPropertys, but I am guessing that you are taking the wrong approach. Typically in WPF, our properties are data types, not UI types and then we generate UI types using DataTemplates... perhaps you should re-think your approach.
Please see the Data Templating Overview page on MSDN for further help.
You might also find my answer to the WPF MVVM navigate views question helpful to read.

Categories