728x90
반응형
728x170
▶ Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
xmlns:local="clr-namespace:TestLibrary">
<Style TargetType="{x:Type local:ListControl}">
<Setter
Property="Background"
Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter
Property="BorderBrush"
Value="#ff707070" />
<Setter
Property="BorderThickness"
Value="1" />
<Setter
Property="KeyboardNavigation.TabNavigation"
Value="Once" />
<Setter
Property="Padding"
Value="3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ListControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="scrollViewer"
Padding="{TemplateBinding Padding}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:SelectorItem}">
<Setter
Property="HorizontalContentAlignment"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:Selector}}, Path=HorizontalContentAlignment}" />
<Setter
Property="VerticalContentAlignment"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:Selector}}, Path=VerticalContentAlignment}" />
<Setter
Property="Padding"
Value="4 0 0 0" />
<Setter
Property="IsTabStop"
Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SelectorItem}">
<Border x:Name="backgroundBorder"
Margin="1"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}, Mode=FindAncestor}, Path=ActualWidth}"
LastChildFill="True">
<BulletDecorator DockPanel.Dock="Left"
Margin="2 0 0 0"
VerticalAlignment="Center"
SnapsToDevicePixels="True"
Background="Transparent">
<BulletDecorator.Bullet>
<themes:BulletChrome
BorderBrush="Black"
IsRound="{Binding Path=SingleSelect, RelativeSource={RelativeSource AncestorType={x:Type local:ListControl}, Mode=FindAncestor}}"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}"
RenderMouseOver="{TemplateBinding IsMouseOver}" />
</BulletDecorator.Bullet>
</BulletDecorator>
<ContentControl
Margin="5 1 0 1"
VerticalAlignment="Center"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Foreground="{TemplateBinding Foreground}" />
</DockPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter
TargetName="backgroundBorder"
Property="Background"
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter
Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter
TargetName="backgroundBorder"
Property="Background"
Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter
Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
728x90
▶ ListControl.cs
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace TestLibrary
{
/// <summary>
/// 리스트 컨트롤
/// </summary>
public class ListControl : Selector
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 단일 선택 의존 속성 - SingleSelectProperty
/// <summary>
/// 단일 선택 의존 속성
/// </summary>
public static readonly DependencyProperty SingleSelectProperty = DependencyProperty.Register
(
"SingleSelect",
typeof(bool),
typeof(ListControl),
new UIPropertyMetadata(false, singleSelectPropertyChangedCallback)
);
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// PREVIEW 마우스 DOWN 이벤트 핸들러
/// </summary>
private MouseButtonEventHandler previewMouseDownEventHandler = null;
/// <summary>
/// PREVIEW 마우스 UP 이벤트 핸들러
/// </summary>
private MouseButtonEventHandler previewMouseUpEventHandler = null;
/// <summary>
/// PREVIEW 마우스 이동시 이벤트 핸들러
/// </summary>
private MouseEventHandler previewMouseMoveEventHandler = null;
/// <summary>
/// 드래그 시작 인덱스
/// </summary>
private int dragStartIndex = -1;
/// <summary>
/// 드래그 종료 인덱스
/// </summary>
private int dragEndIndex = -1;
/// <summary>
/// 스크롤 뷰어
/// </summary>
private ScrollViewer scrollViewer = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 단일 선택 - SingleSelect
/// <summary>
/// 단일 선택
/// </summary>
public bool SingleSelect
{
get
{
return (bool)GetValue(SingleSelectProperty);
}
set
{
SetValue(SingleSelectProperty, value);
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Static
#region 생성자 - CheckListBox()
/// <summary>
/// 생성자
/// </summary>
static ListControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListControl), new FrameworkPropertyMetadata(typeof(ListControl)));
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - CheckListBox()
/// <summary>
/// 생성자
/// </summary>
public ListControl()
{
this.previewMouseDownEventHandler = new MouseButtonEventHandler(ItemsControl_PreviewMouseDown);
this.previewMouseUpEventHandler = new MouseButtonEventHandler(ItemsControl_PreviewMouseUp );
this.previewMouseMoveEventHandler = new MouseEventHandler (ItemsControl_PreviewMouseMove);
AddHandler(ItemsControl.PreviewMouseDownEvent, this.previewMouseDownEventHandler);
AddHandler(ItemsControl.PreviewMouseUpEvent , this.previewMouseUpEventHandler );
AddHandler(ItemsControl.PreviewMouseMoveEvent, this.previewMouseMoveEventHandler);
Loaded += Selector_Loaded;
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 단일 선택 속성 변경시 콜백 처리하기 - singleSelectPropertyChangedCallback(dependencyObject, e)
/// <summary>
/// 단일 선택 속성 변경시 콜백 처리하기
/// </summary>
/// <param name="d">의존 객체</param>
/// <param name="e">이벤트 인자</param>
private static void singleSelectPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListControl checkListBox = d as ListControl;
bool newValue = (bool)e.NewValue;
if(newValue)
{
checkListBox.surpressItemSelectionChanged = true;
IList selectedList = checkListBox.SelectedItems;
if(selectedList != null)
{
if(selectedList.Count > 1)
{
IList sourceList = (checkListBox.ItemsSource ?? checkListBox.Items) as IList;
for(int i = 0; i < sourceList.Count; i++)
{
object item = sourceList[i];
SelectorItem selectorItem = checkListBox.ItemContainerGenerator.ContainerFromItem(item) as SelectorItem;
selectorItem.IsSelected = false;
}
}
}
checkListBox.surpressItemSelectionChanged = false;
ItemSelectionChangedEventArgs itemSelectionChangedEventArgs = new ItemSelectionChangedEventArgs
(
Selector.ItemSelectionChangedEvent,
checkListBox,
null,
true
);
checkListBox.RaiseEvent(itemSelectionChangedEventArgs);
}
}
#endregion
////////////////////////////////////////////////////////////////////////////////////////// Instance
//////////////////////////////////////////////////////////////////////////////// Private
#region 셀렉터 로드시 처리하기 - Selector_Loaded(sender, e)
/// <summary>
/// 셀렉터 로드시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Selector_Loaded(object sender, RoutedEventArgs e)
{
this.scrollViewer = Template.FindName("scrollViewer", this) as ScrollViewer;
}
#endregion
#region 항목들 컨트롤 PREVIEW 마우스 DOWN 처리하기 - ItemsControl_PreviewMouseDown(sender, e)
/// <summary>
/// 항목들 컨트롤 PREVIEW 마우스 DOWN 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void ItemsControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if(e.ChangedButton == MouseButton.Left)
{
if(Keyboard.Modifiers == ModifierKeys.Control || Keyboard.Modifiers == ModifierKeys.Shift)
{
return;
}
IList sourceList = (ItemsSource ?? Items) as IList;
if(sourceList == null || sourceList.Count == 0)
{
return;
}
HitTestResult hitTestResult = VisualTreeHelper.HitTest(this, e.GetPosition(this));
if(hitTestResult == null)
{
return;
}
SelectorItem selectorItem = hitTestResult.VisualHit.FindParent<SelectorItem>();
if(selectorItem == null)
{
return;
}
object item = selectorItem.Content as object;
if(item == null)
{
return;
}
this.dragStartIndex = sourceList.IndexOf(item);
}
}
#endregion
#region 항목들 컨트롤 PREVIEW 마우스 이동시 처리하기 - ItemsControl_PreviewMouseMove(sender, e)
/// <summary>
/// 항목들 컨트롤 PREVIEW 마우스 이동시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void ItemsControl_PreviewMouseMove(object sender, MouseEventArgs e)
{
if(e.LeftButton == MouseButtonState.Pressed)
{
Point mousePosition = e.GetPosition(this);
if(this.scrollViewer != null)
{
if(mousePosition.Y > Height - 8)
{
this.scrollViewer.ScrollToVerticalOffset(this.scrollViewer.VerticalOffset + 4);
}
else if(mousePosition.Y < 8)
{
this.scrollViewer.ScrollToVerticalOffset(this.scrollViewer.VerticalOffset - 4);
}
}
}
}
#endregion
#region 항목들 컨트롤 PREVIEW 마우스 UP 처리하기 - ItemsControl_PreviewMouseUp(sender, e)
/// <summary>
/// 항목들 컨트롤 PREVIEW 마우스 UP 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void ItemsControl_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if(e.ChangedButton == MouseButton.Left)
{
if(Keyboard.Modifiers == ModifierKeys.Control || Keyboard.Modifiers == ModifierKeys.Shift)
{
return;
}
IList sourceList = (ItemsSource ?? Items) as IList;
if(sourceList == null || sourceList.Count == 0)
{
return;
}
HitTestResult hitTestResult = VisualTreeHelper.HitTest(this, e.GetPosition(this));
if(hitTestResult == null)
{
return;
}
SelectorItem selectorItemHitted = hitTestResult.VisualHit.FindParent<SelectorItem>();
if(selectorItemHitted == null)
{
return;
}
object itemHitted = selectorItemHitted.Content as object;
if(itemHitted == null)
{
return;
}
this.dragEndIndex = sourceList.IndexOf(itemHitted);
if(this.dragStartIndex == -1 || this.dragEndIndex == -1)
{
return;
}
if(SingleSelect)
{
this.dragStartIndex = this.dragEndIndex;
}
else
{
if(this.dragStartIndex > this.dragEndIndex)
{
int temporaryIndex = this.dragStartIndex;
this.dragStartIndex = this.dragEndIndex;
this.dragEndIndex = temporaryIndex;
}
}
this.surpressItemSelectionChanged = true;
if(SingleSelect)
{
SelectorItem startSelectorItem = ItemContainerGenerator.ContainerFromIndex(this.dragStartIndex) as SelectorItem;
startSelectorItem.IsSelected = !startSelectorItem.IsSelected;
if(startSelectorItem.IsSelected)
{
for(int i = 0; i < sourceList.Count; i++)
{
SelectorItem selectorItem = ItemContainerGenerator.ContainerFromIndex(i) as SelectorItem;
if(selectorItem == startSelectorItem)
{
continue;
}
selectorItem.IsSelected = false;
}
}
}
else
{
for(int i = this.dragStartIndex; i < this.dragEndIndex + 1; i++)
{
SelectorItem selectorItem = ItemContainerGenerator.ContainerFromIndex(i) as SelectorItem;
selectorItem.IsSelected = !selectorItem.IsSelected;
}
}
this.surpressItemSelectionChanged = false;
ItemSelectionChangedEventArgs itemSelectionChangedEventArgs = new ItemSelectionChangedEventArgs
(
Selector.ItemSelectionChangedEvent,
this,
null,
true
);
RaiseEvent(itemSelectionChangedEventArgs);
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] TreeViewItem 클래스 : ItemsSource 속성을 사용해 트리 뷰 만들기 (0) | 2017.06.11 |
---|---|
[C#/WPF] NavigationWindow 엘리먼트 : 페이지 탐색하기 (0) | 2017.06.11 |
[C#/WPF] XAML용 UI 디버깅 도구 숨기기 (0) | 2017.05.30 |
[C#/WPF] ControlTemplate 엘리먼트 : 조직도 TreeViewItem 엘리먼트 정의하기 (0) | 2017.05.25 |
[C#/WPF] 컬럼 리스트 박스 사용하기 (0) | 2017.05.09 |
[C#/WPF] Button 클래스 : 이미지 버튼 사용하기 (0) | 2017.04.02 |
[C#/WPF] GroupBox 클래스 : 그룹 컨트롤 사용하기 (0) | 2017.04.01 |
[C#/WPF] ContentControl 클래스 : 확장/축소 패널 사용하기 (0) | 2017.04.01 |
[C#/WPF] Button 클래스 : 모노 버튼 사용하기 (0) | 2017.04.01 |
[C#/WPF] 원시 DPI 구하기 (0) | 2017.03.19 |
댓글을 달아 주세요