问题
Been banging my head against this all morning.
Basically, I have a listbox, and I want to keep people from changing the selection during a long running process, but allow them to still scroll.
Solution:
All the answers were good, I went with swallowing mouse events since that was the most straight forward. I wired PreviewMouseDown and PreviewMouseUp to a single event, which checked my backgroundWorker.IsBusy, and if it was set the IsHandled property on the event args to true.
回答1:
The trick is to not really disable. Disabling will lock out all messages from the scroll box.
During the long operation, gray out the text in the list box using its .ForeColor property and swallow all mouse clicks. This will simulate disabling the control and allow scrolling unimpeded.
回答2:
If you look in to the control template of the ListBox, there is a ScrollBar and ItemsPresenter inside. So Make the ItemsPresenter Disabled and you will get this easily. Use the bellow Style on the ListBox and you are good to go.
<Style x:Key="disabledListBoxWithScroll" TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="1">
<ScrollViewer Padding="{TemplateBinding Padding}" Focusable="false">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" IsEnabled="False" IsHitTestVisible="True"/>
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
On the ListBox use the Style
<ListBox Style="{DynamicResource disabledListBoxWithScroll}" ..... />
回答3:
sorry it has been almost two years, but I think this solution that uses DataTrigger is even simpler. How to disable a databound ListBox item based on a property value?
回答4:
I found that putting a disabled ListBox in a ScrollViewer with auto scrolling enabled gives the desired effect.
回答5:
While it's for Silverlight, maybe this blog post would help you get going in the right direction? Silverlight No Selection ListBox and ViewBox
回答6:
I used this solution, it's really easy and works perfectly:
For every SurfaceListBoxItem item
you put in the Listbox
, do this:
item.IsHitTestVisible = false;
回答7:
This worked best for me. It's easy and whole code is in XAML which is IMO very neat.
<ListBox ItemsSource="{Binding MySource}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditing}" Value="True">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEditing}" Value="False">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
回答8:
Another option worth considering is disabling the ListBoxItems. This can be done by setting the ItemContainerStyle as shown in the following snippet.
<ListBox ItemsSource="{Binding YourCollection}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
If you don't want the text to be grey you can specify the disabled color by adding a brush to the style's resources with the following key: {x:Static SystemColors.GrayTextBrushKey}. The other solution would be to override the ListBoxItem control template.
This question is pretty much the same as this one: There ain't ListBox.SelectionMode=“None”, is there another way to disable selection in a listbox? and my answer is the same.
回答9:
I found a very simple and straight forward solution working for me, I hope it would do for you as well
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
回答10:
A complete answer using http://www.codeproject.com/Tips/60619/Scrollable-Disabled-ListBox-in-WPF
The Style:
<Style TargetType="{x:Type local:CustomListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomListBox}">
<Border SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="1">
<ScrollViewer IsEnabled="True">
<ItemsPresenter IsEnabled="{Binding Path=IsEnabledWithScroll, RelativeSource={RelativeSource TemplatedParent}}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The class
public class CustomListBox : ListBox
{
public bool IsEnabledWithScroll
{
get { return (bool)GetValue(IsEnabledWithScrollProperty); }
set { SetValue(IsEnabledWithScrollProperty, value); }
}
public static readonly DependencyProperty IsEnabledWithScrollProperty =
DependencyProperty.Register("IsEnabledWithScroll", typeof(bool), typeof(CustomListBox), new UIPropertyMetadata(true));
}
Then instead of setted IsEnabled on the ListBox, use IsEnabledWithScroll instead. Scrolling will work if the listbox is enabled or disabled.
回答11:
There seem to be many ways to skin this particular cat. I found that by setting IsHitTestVisible
on the ItemsContainerStyle
in XAML I got exactly what I needed:
<ListBox IsHitTestVisible="true" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
来源:https://stackoverflow.com/questions/529121/wpf-disable-listbox-but-enable-scrolling