This repository has been archived by the owner on Oct 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
313 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,138 @@ | ||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:converters="clr-namespace:TypeCode.Wpf.Helper.Converters" | ||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors" | ||
xmlns:behaviours="clr-namespace:TypeCode.Wpf.Helper.Behaviours" | ||
xmlns:comboBox="clr-namespace:TypeCode.Wpf.Controls.ComboBox" | ||
xmlns:triggers="clr-namespace:TypeCode.Wpf.Helper.Triggers" | ||
xmlns:system="clr-namespace:System;assembly=System.Runtime"> | ||
|
||
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> | ||
<Setter Property="ItemContainerStyle"> | ||
<converters:BooleanToVisibilityConverterSelf x:Key="BooleanToVisibilityConverter" True="Visible" False="Collapsed" /> | ||
<converters:BooleanToVisibilityConverterSelf x:Key="InvertedBooleanToVisibilityConverter" True="Collapsed" | ||
False="Visible" /> | ||
<converters:ObjectToStringConverter x:Key="ObjectToStringConverter"/> | ||
<system:Boolean x:Key="False">False</system:Boolean> | ||
|
||
<Style TargetType="{x:Type comboBox:CustomComboBox}"> | ||
|
||
<Setter Property="Template"> | ||
<Setter.Value> | ||
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource {x:Type ComboBoxItem}}"> | ||
<Setter Property="Background" Value="{StaticResource Primary}"></Setter> | ||
</Style> | ||
<ControlTemplate TargetType="{x:Type comboBox:CustomComboBox}"> | ||
|
||
<Grid Validation.ErrorTemplate="{x:Null}"> | ||
<Grid.ColumnDefinitions> | ||
<ColumnDefinition Width="*" /> | ||
<ColumnDefinition Width="Auto" /> | ||
</Grid.ColumnDefinitions> | ||
|
||
<Grid.RowDefinitions> | ||
<RowDefinition></RowDefinition> | ||
<RowDefinition></RowDefinition> | ||
</Grid.RowDefinitions> | ||
|
||
<Border | ||
VerticalAlignment="Center" | ||
Grid.Row="0" | ||
Grid.Column="0"> | ||
|
||
<Border.Style> | ||
<Style TargetType="{x:Type Border}"> | ||
<Setter Property="BorderThickness" Value="1"></Setter> | ||
<Style.Triggers> | ||
<DataTrigger | ||
Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Validation.HasError), UpdateSourceTrigger=PropertyChanged}" | ||
Value="false"> | ||
<Setter Property="BorderBrush" | ||
Value="{StaticResource Accent}" /> | ||
</DataTrigger> | ||
<DataTrigger | ||
Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Validation.HasError), UpdateSourceTrigger=PropertyChanged}" | ||
Value="true"> | ||
<Setter Property="BorderBrush" | ||
Value="{StaticResource Error}" /> | ||
</DataTrigger> | ||
</Style.Triggers> | ||
</Style> | ||
</Border.Style> | ||
|
||
<TextBlock x:Name="InputTextBox" | ||
Grid.Column="0" | ||
Margin="4" | ||
Validation.ErrorTemplate="{x:Null}" | ||
Text="{Binding Path=SelectedComboBoxItem, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"> | ||
</TextBlock> | ||
|
||
</Border> | ||
|
||
<TextBlock Grid.Row="1" | ||
Grid.Column="0" | ||
Padding="2" | ||
Foreground="{StaticResource Error}" | ||
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Validation.HasError), UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BooleanToVisibilityConverter}}" | ||
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(Validation.Errors)/ErrorContent, UpdateSourceTrigger=PropertyChanged}" /> | ||
|
||
<Popup | ||
Grid.Row="0" | ||
Grid.Column="0" | ||
StaysOpen="False" | ||
Placement="Bottom" | ||
PlacementTarget="{Binding ElementName=InputTextBox}" | ||
Width="{Binding ActualWidth, ElementName=InputTextBox}" | ||
IsOpen="{TemplateBinding IsComboBoxDropDownOpen}"> | ||
|
||
|
||
<ListBox | ||
Name="ComboBoxListBox" | ||
MaxWidth="{Binding ActualWidth, ElementName=InputTextBox}" | ||
Margin="1" | ||
MaxHeight="100" | ||
BorderThickness="1" | ||
Background="{StaticResource Primary}" | ||
BorderBrush="{StaticResource Accent}" | ||
ItemsSource="{Binding Path=ComboBoxItems, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource TemplatedParent}}" | ||
behaviours:SourceChangedScrollTopBehaviour.ScrollToTop="True"> | ||
|
||
<b:Interaction.Triggers> | ||
<b:EventTrigger EventName="SelectionChanged"> | ||
<triggers:SetPropertyActionTrigger | ||
PropertyName="SelectedComboBoxItem" | ||
TargetObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type comboBox:CustomComboBox}}}" | ||
PropertyValue="{Binding ElementName=ComboBoxListBox, Path=SelectedItem}"> | ||
</triggers:SetPropertyActionTrigger> | ||
</b:EventTrigger> | ||
<b:EventTrigger EventName="SelectionChanged"> | ||
<triggers:SetPropertyActionTrigger | ||
PropertyName="IsComboBoxDropDownOpen" | ||
TargetObject="{Binding RelativeSource={RelativeSource AncestorType={x:Type comboBox:CustomComboBox}}}" | ||
PropertyValue="{StaticResource False}"> | ||
</triggers:SetPropertyActionTrigger> | ||
</b:EventTrigger> | ||
</b:Interaction.Triggers> | ||
|
||
<ListBox.ItemTemplate> | ||
<DataTemplate> | ||
<TextBlock Text="{Binding Converter={StaticResource ObjectToStringConverter}}" ToolTip="{Binding}" | ||
TextTrimming="CharacterEllipsis" /> | ||
</DataTemplate> | ||
</ListBox.ItemTemplate> | ||
|
||
<ListBox.ItemsPanel> | ||
<ItemsPanelTemplate> | ||
<VirtualizingStackPanel IsVirtualizing="True" | ||
VirtualizationMode="Recycling"> | ||
</VirtualizingStackPanel> | ||
</ItemsPanelTemplate> | ||
</ListBox.ItemsPanel> | ||
|
||
</ListBox> | ||
|
||
</Popup> | ||
|
||
</Grid> | ||
|
||
</ControlTemplate> | ||
</Setter.Value> | ||
</Setter> | ||
|
||
</Style> | ||
|
||
</ResourceDictionary> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System.Collections; | ||
using System.Windows; | ||
using System.Windows.Controls; | ||
|
||
namespace TypeCode.Wpf.Controls.ComboBox; | ||
|
||
public class CustomComboBox : Control | ||
{ | ||
public CustomComboBox() | ||
{ | ||
PreviewMouseLeftButtonUp += (_, _) => IsComboBoxDropDownOpen = true; | ||
MouseLeave += (_, _) => IsComboBoxDropDownOpen = false; | ||
} | ||
|
||
public static readonly DependencyProperty IsComboBoxDropDownOpenProperty = | ||
DependencyProperty.Register( | ||
name: nameof(IsComboBoxDropDownOpen), | ||
propertyType: typeof(bool), | ||
ownerType: typeof(CustomComboBox), | ||
typeMetadata: new FrameworkPropertyMetadata(false) | ||
); | ||
|
||
public bool IsComboBoxDropDownOpen | ||
{ | ||
get => (bool)GetValue(IsComboBoxDropDownOpenProperty); | ||
private set => SetValue(IsComboBoxDropDownOpenProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty ComboBoxItemsProperty = | ||
DependencyProperty.Register( | ||
name: nameof(ComboBoxItems), | ||
propertyType: typeof(IEnumerable), | ||
ownerType: typeof(CustomComboBox), | ||
typeMetadata: new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault) | ||
); | ||
|
||
public IEnumerable ComboBoxItems | ||
{ | ||
get => (IEnumerable)GetValue(ComboBoxItemsProperty); | ||
set => SetValue(ComboBoxItemsProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty SelectedComboBoxItemProperty = | ||
DependencyProperty.Register( | ||
name: nameof(SelectedComboBoxItem), | ||
propertyType: typeof(object), | ||
ownerType: typeof(CustomComboBox), | ||
typeMetadata: new FrameworkPropertyMetadata(null) | ||
); | ||
|
||
public object SelectedComboBoxItem | ||
{ | ||
get => GetValue(SelectedComboBoxItemProperty); | ||
set => SetValue(SelectedComboBoxItemProperty, value); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/TypeCode.Wpf/Helper/Converters/ObjectToStringConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Globalization; | ||
using System.Windows.Data; | ||
|
||
namespace TypeCode.Wpf.Helper.Converters; | ||
|
||
public class ObjectToStringConverter : IValueConverter | ||
{ | ||
public virtual object? Convert(object value, Type targetType, object parameter, CultureInfo culture) | ||
{ | ||
return value.ToString(); | ||
} | ||
|
||
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) | ||
{ | ||
throw new Exception(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using System.Reflection; | ||
using System.Windows; | ||
using Microsoft.Xaml.Behaviors; | ||
|
||
namespace TypeCode.Wpf.Helper.Triggers; | ||
|
||
public class SetPropertyActionTrigger : TriggerAction<FrameworkElement> | ||
{ | ||
public string PropertyName | ||
{ | ||
get => (string)GetValue(PropertyNameProperty); | ||
set => SetValue(PropertyNameProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty PropertyNameProperty | ||
= DependencyProperty.Register(nameof(PropertyName), typeof(string), | ||
typeof(SetPropertyActionTrigger)); | ||
|
||
public object PropertyValue | ||
{ | ||
get => GetValue(PropertyValueProperty); | ||
set => SetValue(PropertyValueProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty PropertyValueProperty | ||
= DependencyProperty.Register(nameof(PropertyValue), typeof(object), | ||
typeof(SetPropertyActionTrigger)); | ||
|
||
public object TargetObject | ||
{ | ||
get => GetValue(TargetObjectProperty); | ||
set => SetValue(TargetObjectProperty, value); | ||
} | ||
|
||
public static readonly DependencyProperty TargetObjectProperty | ||
= DependencyProperty.Register(nameof(TargetObject), typeof(object), | ||
typeof(SetPropertyActionTrigger)); | ||
|
||
protected override void Invoke(object parameter) | ||
{ | ||
var propertyInfo = TargetObject.GetType().GetProperty( | ||
PropertyName, | ||
BindingFlags.Instance | BindingFlags.Public | ||
| BindingFlags.NonPublic | BindingFlags.InvokeMethod); | ||
|
||
propertyInfo?.SetValue(TargetObject, PropertyValue); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.