This commit is contained in:
Elie Bariche 2021-01-14 07:53:08 -05:00 коммит произвёл GitHub
Родитель c1c791e6f8
Коммит 4cf0918ee0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
95 изменённых файлов: 40351 добавлений и 20 удалений

63
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

26
.gitignore поставляемый
Просмотреть файл

@ -4,6 +4,7 @@
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
@ -19,6 +20,8 @@
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
@ -52,7 +55,6 @@ BenchmarkDotNet.Artifacts/
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
@ -60,7 +62,7 @@ StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*_h.h
*.ilk
*.meta
*.obj
@ -77,6 +79,7 @@ StyleCopReport.xml
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
@ -208,7 +211,7 @@ _pkginfo.txt
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
!?*.[Cc]ache/
# Others
ClientBin/
@ -221,7 +224,7 @@ ClientBin/
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
@ -252,6 +255,7 @@ ServiceFabricBackup/
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- Backup*.rdl
# Microsoft Fakes
FakesAssemblies/
@ -291,8 +295,8 @@ paket-files/
.idea/
*.sln.iml
# CodeRush
.cr/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
@ -317,7 +321,7 @@ __pycache__/
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
@ -326,5 +330,11 @@ ASALocalRun/
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb

Просмотреть файл

@ -1,18 +1,18 @@
pull_request_rules:
- name: automatic strict merge when CI passes, has 2 reviews, no requests for change and is labeled 'ready-to-merge' unless labelled 'do-not-merge/breaking-change' or 'do-not-merge/work-in-progress'
- name: automatic strict merge when CI passes, has 1 reviews, no requests for change and is labeled 'ready-to-merge' unless labelled 'do-not-merge/breaking-change' or 'do-not-merge/work-in-progress'
conditions:
# Only pull-requests sent to the master branch
- base=master
# All Azure builds should be green:
- status-success=Uno.UI - CI
- status-success=Uno.WinUI3Convert - CI
# CLA check must pass:
#- "status-success=license/cla"
# Note that this only matches people with write / admin access to the repo,
# see <https://doc.mergify.io/conditions.html#attribute-list>
- "#approved-reviews-by>=2"
- "#approved-reviews-by>=1"
- "#changes-requested-reviews-by=0"
# Pull-request must be labeled with:
@ -30,10 +30,3 @@ pull_request_rules:
# https://doc.mergify.io/strict-workflow.html
# https://doc.mergify.io/actions.html#label
strict: smart
- name: automatic merge for allcontributors pull requests
conditions:
- author=allcontributors[bot]
actions:
merge:
method: merge

Просмотреть файл

@ -1,2 +1,29 @@
# template
template for brand new github repositories
# Uno.WinUI3Convert
Migrate UWP projects to WinUI3/NET5.
This tool is commonly used in CI environments to automatically generate a WinUI 3 compatible source tree, built separately from the UWP source tree. This allows for the generation of WinUI 3 compatible nuget packages for libraries without having to maintain two separate codebases.
```
Usage:
winui3convert [options] <source> <destination>
Arguments:
<source> Source directory
<destination> Destination directory
Options:
--overwrite Overwrite destination
--version Show version information
-?, -h, --help Show help and usage information
```
## Installation
dotnet tool install --global uno.winui3convert
## Conversion adjustments
This tool is meant to help migrate your projects by rewriting namespaces and project files. It won't resolve collisions, work around unsupported features or change code in significant ways.
Manual source adjustments are to be expected in some cases.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,78 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization;
namespace Microsoft.Toolkit.Uwp.UI.Data.Utilities
{
internal static class CollectionViewsError
{
public static class CollectionView
{
public static InvalidOperationException EnumeratorVersionChanged()
{
return new InvalidOperationException("Collection was modified; enumeration operation cannot execute.");
}
public static InvalidOperationException MemberNotAllowedDuringAddOrEdit(string paramName)
{
return new InvalidOperationException(Format("'{0}' is not allowed during an AddNew or EditItem transaction.", paramName));
}
public static InvalidOperationException NoAccessWhileChangesAreDeferred()
{
return new InvalidOperationException("This value cannot be accessed while changes are deferred.");
}
public static InvalidOperationException ItemNotAtIndex(string paramName)
{
return new InvalidOperationException(Format("The {0} item is not in the collection.", paramName));
}
}
public static class EnumerableCollectionView
{
public static InvalidOperationException RemovedItemNotFound()
{
return new InvalidOperationException("The removed item is not found in the source collection.");
}
}
public static class ListCollectionView
{
public static InvalidOperationException CollectionChangedOutOfRange()
{
return new InvalidOperationException("The collection change is out of bounds of the original collection.");
}
public static InvalidOperationException AddedItemNotInCollection()
{
return new InvalidOperationException("The added item is not in the collection.");
}
#if FEATURE_IEDITABLECOLLECTIONVIEW
public static InvalidOperationException CancelEditNotSupported()
{
return new InvalidOperationException("CancelEdit is not supported for the current edit item.");
}
public static InvalidOperationException MemberNotAllowedDuringTransaction(string paramName1, string paramName2)
{
return new InvalidOperationException(Format("'{0}' is not allowed during a transaction started by '{1}'.", paramName1, paramName2));
}
public static InvalidOperationException MemberNotAllowedForView(string paramName)
{
return new InvalidOperationException(Format("'{0}' is not allowed for this view.", paramName));
}
#endif
}
private static string Format(string formatString, params object[] args)
{
return string.Format(CultureInfo.CurrentCulture, formatString, args);
}
}
}

Просмотреть файл

@ -0,0 +1,697 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Data.Utilities
{
/// <summary>
/// A collection view implementation that supports an IEnumerable source.
/// </summary>
internal class EnumerableCollectionView : CollectionView
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
// Set up a ListCollectionView over the snapshot.
// We will delegate all CollectionView functionality to this view.
internal EnumerableCollectionView(IEnumerable source)
: base(source)
{
_snapshot = new ObservableCollection<object>();
LoadSnapshotCore(source);
if (_snapshot.Count > 0)
{
SetCurrent(_snapshot[0], 0, 1);
}
else
{
SetCurrent(null, -1, 0);
}
// If the source doesn't raise collection change events, try to detect changes by polling the enumerator.
_pollForChanges = !(source is INotifyCollectionChanged);
_view = new ListCollectionView(_snapshot);
INotifyCollectionChanged incc = _view as INotifyCollectionChanged;
incc.CollectionChanged += new NotifyCollectionChangedEventHandler(EnumerableCollectionView_OnViewChanged);
INotifyPropertyChanged ipc = _view as INotifyPropertyChanged;
ipc.PropertyChanged += new PropertyChangedEventHandler(EnumerableCollectionView_OnPropertyChanged);
_view.CurrentChanging += new CurrentChangingEventHandler(EnumerableCollectionView_OnCurrentChanging);
_view.CurrentChanged += new EventHandler<object>(EnumerableCollectionView_OnCurrentChanged);
}
//------------------------------------------------------
//
// Interfaces
//
//------------------------------------------------------
/// <summary>
/// Gets or sets culture to use during sorting.
/// </summary>
public override CultureInfo Culture
{
get
{
return _view.Culture;
}
set
{
_view.Culture = value;
}
}
/// <summary>
/// Return true if the item belongs to this view. No assumptions are
/// made about the item. This method will behave similarly to IList.Contains().
/// If the caller knows that the item belongs to the
/// underlying collection, it is more efficient to call PassesFilter.
/// </summary>
/// <returns>True if the item belongs to this view.</returns>
public override bool Contains(object item)
{
EnsureSnapshot();
return _view.Contains(item);
}
#if FEATURE_ICOLLECTIONVIEW_FILTER
/// <summary>
/// Set/get a filter callback to filter out items in collection.
/// This property will always accept a filter, but the collection view for the
/// underlying InnerList or ItemsSource may not actually support filtering.
/// Please check <seealso cref="CanFilter"/>
/// </summary>
/// <exception cref="NotSupportedException">
/// Collections assigned to ItemsSource may not support filtering and could throw a NotSupportedException.
/// Use <seealso cref="CanSort"/> property to test if sorting is supported before adding
/// to SortDescriptions.
/// </exception>
public override Predicate<object> Filter
{
get
{
return _view.Filter;
}
set
{
_view.Filter = value;
}
}
/// <summary>
/// Test if this ICollectionView supports filtering before assigning
/// a filter callback to <seealso cref="Filter"/>.
/// </summary>
public override bool CanFilter
{
get
{
return _view.CanFilter;
}
}
#endif
#if FEATURE_ICOLLECTIONVIEW_SORT
/// <summary>
/// Set/get Sort criteria to sort items in collection.
/// </summary>
/// <remarks>
/// <p>
/// Clear a sort criteria by assigning SortDescription.Empty to this property.
/// One or more sort criteria in form of <seealso cref="SortDescription"/>
/// can be used, each specifying a property and direction to sort by.
/// </p>
/// </remarks>
/// <exception cref="NotSupportedException">
/// Simpler implementations do not support sorting and will throw a NotSupportedException.
/// Use <seealso cref="CanSort"/> property to test if sorting is supported before adding
/// to SortDescriptions.
/// </exception>
public override SortDescriptionCollection SortDescriptions
{
get
{
return _view.SortDescriptions;
}
}
/// <summary>
/// Test if this ICollectionView supports sorting before adding
/// to <seealso cref="SortDescriptions"/>.
/// </summary>
public override bool CanSort
{
get
{
return _view.CanSort;
}
}
#endif
#if FEATURE_ICOLLECTIONVIEW_GROUP
/// <summary>
/// Returns true if this view really supports grouping.
/// When this returns false, the rest of the interface is ignored.
/// </summary>
public override bool CanGroup
{
get
{
return _view.CanGroup;
}
}
/// <summary>
/// The description of grouping, indexed by level.
/// </summary>
public override ObservableCollection<GroupDescription> GroupDescriptions
{
get
{
return _view.GroupDescriptions;
}
}
/// <summary>
/// The top-level groups, constructed according to the descriptions
/// given in GroupDescriptions.
/// </summary>
public override ReadOnlyObservableCollection<object> Groups
{
get
{
return _view.Groups;
}
}
#endif
/// <summary>
/// Enter a Defer Cycle.
/// Defer cycles are used to coalesce changes to the ICollectionView.
/// </summary>
/// <returns>An IDisposable deferral object.</returns>
public override IDisposable DeferRefresh()
{
return _view.DeferRefresh();
}
/// <summary>
/// Gets the current item.
/// </summary>
public override object CurrentItem
{
get
{
return _view.CurrentItem;
}
}
/// <summary>
/// Gets the ordinal position of the <seealso cref="CurrentItem"/> within the (optionally
/// sorted and filtered) view.
/// </summary>
public override int CurrentPosition
{
get
{
return _view.CurrentPosition;
}
}
/// <summary>
/// Gets a value indicating whether the currency is beyond the end (End-Of-File).
/// </summary>
public override bool IsCurrentAfterLast
{
get
{
return _view.IsCurrentAfterLast;
}
}
/// <summary>
/// Gets a value indicating whether the currency is before the beginning (Beginning-Of-File).
/// </summary>
public override bool IsCurrentBeforeFirst
{
get
{
return _view.IsCurrentBeforeFirst;
}
}
/// <summary>
/// Move <seealso cref="CurrentItem"/> to the first item.
/// </summary>
/// <returns>True if <seealso cref="CurrentItem"/> points to an item within the view.</returns>
public override bool MoveCurrentToFirst()
{
return _view.MoveCurrentToFirst();
}
/// <summary>
/// Move <seealso cref="CurrentItem"/> to the previous item.
/// </summary>
/// <returns>True if <seealso cref="CurrentItem"/> points to an item within the view.</returns>
public override bool MoveCurrentToPrevious()
{
return _view.MoveCurrentToPrevious();
}
/// <summary>
/// Move <seealso cref="CurrentItem"/> to the next item.
/// </summary>
/// <returns>True if <seealso cref="CurrentItem"/> points to an item within the view.</returns>
public override bool MoveCurrentToNext()
{
return _view.MoveCurrentToNext();
}
/// <summary>
/// Move <seealso cref="CurrentItem"/> to the last item.
/// </summary>
/// <returns>True if <seealso cref="CurrentItem"/> points to an item within the view.</returns>
public override bool MoveCurrentToLast()
{
return _view.MoveCurrentToLast();
}
/// <summary>
/// Move <seealso cref="CurrentItem"/> to the given item.
/// If the item is not found, move to BeforeFirst.
/// </summary>
/// <param name="item">Move CurrentItem to this item.</param>
/// <returns>True if <seealso cref="CurrentItem"/> points to an item within the view.</returns>
public override bool MoveCurrentTo(object item)
{
return _view.MoveCurrentTo(item);
}
/// <summary>
/// Move <seealso cref="CurrentItem"/> to the item at the given index.
/// </summary>
/// <param name="position">Move CurrentItem to this index</param>
/// <returns>True if <seealso cref="CurrentItem"/> points to an item within the view.</returns>
public override bool MoveCurrentToPosition(int position)
{
// If the index is out of range here, I'll let the
// _view be the one to make that determination.
return _view.MoveCurrentToPosition(position);
}
//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------
/// <summary>
/// Gets the number of records (or -1, meaning "don't know").
/// A virtualizing view should return the best estimate it can
/// without de-virtualizing all the data. A non-virtualizing view
/// should return the exact count of its (filtered) data.
/// </summary>
public override int Count
{
get
{
EnsureSnapshot();
return _view.Count;
}
}
public override bool IsEmpty
{
get
{
EnsureSnapshot();
return (_view != null) ? _view.IsEmpty : true;
}
}
/// <summary>
/// Gets a value indicating whether this view needs to be refreshed.
/// </summary>
public override bool NeedsRefresh
{
get
{
return _view.NeedsRefresh;
}
}
//------------------------------------------------------
//
// Public Methods
//
//------------------------------------------------------
/// <summary>
/// Return the index where the given item appears, or -1 if doesn't appear.
/// </summary>
/// <param name="item">data item</param>
/// <returns>The index where the given item belongs, or -1 if this index is unknown.</returns>
public override int IndexOf(object item)
{
EnsureSnapshot();
return _view.IndexOf(item);
}
#if FEATURE_ICOLLECTIONVIEW_FILTER
/// <summary>
/// Return true if the item belongs to this view. The item is assumed to belong to the
/// underlying DataCollection; this method merely takes filters into account.
/// It is commonly used during collection-changed notifications to determine if the added/removed
/// item requires processing.
/// Returns true if no filter is set on collection view.
/// </summary>
/// <returns>True if the item belongs to this view.</returns>
public override bool PassesFilter(object item)
{
if (_view.CanFilter && _view.Filter != null)
{
return _view.Filter(item);
}
return true;
}
#endif
/// <summary>
/// Retrieve item at the given zero-based index in this CollectionView.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if index is out of range
/// </exception>
/// <returns>Item at the given zero-based index in this CollectionView.</returns>
public override object GetItemAt(int index)
{
EnsureSnapshot();
return _view.GetItemAt(index);
}
//------------------------------------------------------
//
// Protected Methods
//
//------------------------------------------------------
/// <summary> Implementation of IEnumerable.GetEnumerator().
/// This provides a way to enumerate the members of the collection
/// without changing the currency.
/// </summary>
/// <returns>IEnumerator object that enumerates the items in this view.</returns>
protected override IEnumerator GetEnumerator()
{
EnsureSnapshot();
return (_view as IEnumerable).GetEnumerator();
}
/// <summary>
/// Re-create the view over the associated IList
/// </summary>
/// <remarks>
/// Any sorting and filtering will take effect during Refresh.
/// </remarks>
protected override void RefreshOverride()
{
LoadSnapshot(SourceCollection);
}
/// <summary>
/// Processes a single collection change on the UI thread.
/// </summary>
/// <param name="args">
/// The NotifyCollectionChangedEventArgs to be processed.
/// </param>
protected override void ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)
{
// Apply the change to the snapshot
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
if (args.NewStartingIndex < 0 || _snapshot.Count <= args.NewStartingIndex)
{ // Append
for (int i = 0; i < args.NewItems.Count; ++i)
{
_snapshot.Add(args.NewItems[i]);
}
}
else
{ // Insert
for (int i = args.NewItems.Count - 1; i >= 0; --i)
{
_snapshot.Insert(args.NewStartingIndex, args.NewItems[i]);
}
}
break;
case NotifyCollectionChangedAction.Remove:
if (args.OldStartingIndex < 0)
{
throw CollectionViewsError.EnumerableCollectionView.RemovedItemNotFound();
}
for (int i = args.OldItems.Count - 1, index = args.OldStartingIndex + i; i >= 0; --i, --index)
{
if (!object.Equals(args.OldItems[i], _snapshot[index]))
{
throw CollectionViewsError.CollectionView.ItemNotAtIndex("removed");
}
_snapshot.RemoveAt(index);
}
break;
case NotifyCollectionChangedAction.Replace:
for (int i = args.NewItems.Count - 1, index = args.NewStartingIndex + i; i >= 0; --i, --index)
{
if (!object.Equals(args.OldItems[i], _snapshot[index]))
{
throw CollectionViewsError.CollectionView.ItemNotAtIndex("replaced");
}
_snapshot[index] = args.NewItems[i];
}
break;
case NotifyCollectionChangedAction.Reset:
LoadSnapshot(SourceCollection);
break;
}
}
//------------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
// Load a snapshot of the contents of the IEnumerable into the ObservableCollection.
private void LoadSnapshot(IEnumerable source)
{
// Force currency off the collection (gives user a chance to save dirty information).
OnCurrentChanging();
// Remember the values of the scalar properties, so that we can restore
// them and raise events after reloading the data
object oldCurrentItem = CurrentItem;
int oldCurrentPosition = CurrentPosition;
bool oldIsCurrentBeforeFirst = IsCurrentBeforeFirst;
bool oldIsCurrentAfterLast = IsCurrentAfterLast;
// Reload the data
LoadSnapshotCore(source);
// Tell listeners everything has changed
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnCurrentChanged();
if (IsCurrentAfterLast != oldIsCurrentAfterLast)
{
OnPropertyChanged(new PropertyChangedEventArgs(IsCurrentAfterLastPropertyName));
}
if (IsCurrentBeforeFirst != oldIsCurrentBeforeFirst)
{
OnPropertyChanged(new PropertyChangedEventArgs(IsCurrentBeforeFirstPropertyName));
}
if (oldCurrentPosition != CurrentPosition)
{
OnPropertyChanged(new PropertyChangedEventArgs(CurrentPositionPropertyName));
}
if (oldCurrentItem != CurrentItem)
{
OnPropertyChanged(new PropertyChangedEventArgs(CurrentItemPropertyName));
}
}
private void LoadSnapshotCore(IEnumerable source)
{
_trackingEnumerator = source.GetEnumerator();
using (IgnoreViewEvents())
{
_snapshot.Clear();
while (_trackingEnumerator.MoveNext())
{
_snapshot.Add(_trackingEnumerator.Current);
}
}
}
// If the IEnumerable has changed, bring the snapshot up to date.
// (This isn't necessary if the IEnumerable is also INotifyCollectionChanged
// because we keep the snapshot in sync incrementally.)
private void EnsureSnapshot()
{
if (_pollForChanges)
{
try
{
_trackingEnumerator.MoveNext();
}
catch (InvalidOperationException)
{
// This "feature" is necessarily incomplete (we cannot detect
// the changes when they happen, only as a side-effect of some
// later operation), and inconsistent (none of the other
// collection views does this). Changing a collection without
// raising a notification is not supported.
// Collection was changed - start over with a new enumerator
LoadSnapshotCore(SourceCollection);
}
}
}
private IDisposable IgnoreViewEvents()
{
return new IgnoreViewEventsHelper(this);
}
private void BeginIgnoreEvents()
{
_ignoreEventsLevel++;
}
private void EndIgnoreEvents()
{
_ignoreEventsLevel--;
}
// forward events from the internal view to our own listeners
private void EnumerableCollectionView_OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (_ignoreEventsLevel != 0)
{
return;
}
#if FEATURE_IEDITABLECOLLECTIONVIEW
// Also ignore ListCollectionView's property change notifications for
// IEditableCollectionView's properties
switch (args.PropertyName)
{
case ListCollectionView.CanAddNewPropertyName:
case ListCollectionView.CanCancelEditPropertyName:
case ListCollectionView.CanRemovePropertyName:
case ListCollectionView.CurrentAddItemPropertyName:
case ListCollectionView.CurrentEditItemPropertyName:
case ListCollectionView.IsAddingNewPropertyName:
case ListCollectionView.IsEditingItemPropertyName:
return;
}
#endif
OnPropertyChanged(args);
}
private void EnumerableCollectionView_OnViewChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if (_ignoreEventsLevel != 0)
{
return;
}
OnCollectionChanged(args);
}
private void EnumerableCollectionView_OnCurrentChanging(object sender, CurrentChangingEventArgs args)
{
if (_ignoreEventsLevel != 0)
{
return;
}
OnCurrentChanging(args);
}
private void EnumerableCollectionView_OnCurrentChanged(object sender, object args)
{
if (_ignoreEventsLevel != 0)
{
return;
}
OnCurrentChanged();
}
//------------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
private ListCollectionView _view;
private ObservableCollection<object> _snapshot;
private IEnumerator _trackingEnumerator;
private int _ignoreEventsLevel;
private bool _pollForChanges;
private class IgnoreViewEventsHelper : IDisposable
{
public IgnoreViewEventsHelper(EnumerableCollectionView parent)
{
_parent = parent;
_parent.BeginIgnoreEvents();
}
public void Dispose()
{
if (_parent != null)
{
_parent.EndIgnoreEvents();
_parent = null;
}
GC.SuppressFinalize(this);
}
private EnumerableCollectionView _parent;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,988 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Automation.Provider;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// Exposes <see cref="DataGrid" /> types to UI Automation.
/// </summary>
public class DataGridAutomationPeer :
FrameworkElementAutomationPeer,
IGridProvider,
IScrollProvider,
ISelectionProvider,
ITableProvider
{
private Dictionary<object, DataGridGroupItemAutomationPeer> _groupItemPeers = new Dictionary<object, DataGridGroupItemAutomationPeer>();
private Dictionary<object, DataGridItemAutomationPeer> _itemPeers = new Dictionary<object, DataGridItemAutomationPeer>();
private bool _oldHorizontallyScrollable;
private double _oldHorizontalScrollPercent;
private double _oldHorizontalViewSize;
private bool _oldVerticallyScrollable;
private double _oldVerticalScrollPercent;
private double _oldVerticalViewSize;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridAutomationPeer"/> class.
/// </summary>
/// <param name="owner">
/// The <see cref="DataGrid" /> that is associated with this <see cref="T:Windows.UI.Xaml.Automation.Peers.DataGridAutomationPeer" />.
/// </param>
public DataGridAutomationPeer(DataGrid owner)
: base(owner)
{
if (this.HorizontallyScrollable)
{
_oldHorizontallyScrollable = true;
_oldHorizontalScrollPercent = this.HorizontalScrollPercent;
_oldHorizontalViewSize = this.HorizontalViewSize;
}
else
{
_oldHorizontallyScrollable = false;
_oldHorizontalScrollPercent = ScrollPatternIdentifiers.NoScroll;
_oldHorizontalViewSize = 100.0;
}
if (this.VerticallyScrollable)
{
_oldVerticallyScrollable = true;
_oldVerticalScrollPercent = this.VerticalScrollPercent;
_oldVerticalViewSize = this.VerticalViewSize;
}
else
{
_oldVerticallyScrollable = false;
_oldVerticalScrollPercent = ScrollPatternIdentifiers.NoScroll;
_oldVerticalViewSize = 100.0;
}
}
private bool HorizontallyScrollable
{
get
{
return OwningDataGrid.HorizontalScrollBar != null && OwningDataGrid.HorizontalScrollBar.Maximum > 0;
}
}
private double HorizontalScrollPercent
{
get
{
if (!this.HorizontallyScrollable)
{
return ScrollPatternIdentifiers.NoScroll;
}
return (double)(this.OwningDataGrid.HorizontalScrollBar.Value * 100.0 / this.OwningDataGrid.HorizontalScrollBar.Maximum);
}
}
private double HorizontalViewSize
{
get
{
if (!this.HorizontallyScrollable || DoubleUtil.IsZero(this.OwningDataGrid.HorizontalScrollBar.Maximum))
{
return 100.0;
}
return (double)(this.OwningDataGrid.HorizontalScrollBar.ViewportSize * 100.0 /
(this.OwningDataGrid.HorizontalScrollBar.ViewportSize + this.OwningDataGrid.HorizontalScrollBar.Maximum));
}
}
private DataGrid OwningDataGrid
{
get
{
return Owner as DataGrid;
}
}
private bool VerticallyScrollable
{
get
{
return OwningDataGrid.VerticalScrollBar != null && OwningDataGrid.VerticalScrollBar.Maximum > 0;
}
}
private double VerticalScrollPercent
{
get
{
if (!this.VerticallyScrollable)
{
return ScrollPatternIdentifiers.NoScroll;
}
return (double)(this.OwningDataGrid.VerticalScrollBar.Value * 100.0 / this.OwningDataGrid.VerticalScrollBar.Maximum);
}
}
private double VerticalViewSize
{
get
{
if (!this.VerticallyScrollable || DoubleUtil.IsZero(this.OwningDataGrid.VerticalScrollBar.Maximum))
{
return 100.0;
}
return (double)(this.OwningDataGrid.VerticalScrollBar.ViewportSize * 100.0 /
(this.OwningDataGrid.VerticalScrollBar.ViewportSize + this.OwningDataGrid.VerticalScrollBar.Maximum));
}
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.DataGrid;
}
/// <summary>
/// Gets the collection of elements that are represented in the UI Automation tree as immediate
/// child elements of the automation peer.
/// </summary>
/// <returns>The children elements.</returns>
protected override IList<AutomationPeer> GetChildrenCore()
{
IList<AutomationPeer> children = base.GetChildrenCore();
if (this.OwningDataGrid != null)
{
children.Remove(ScrollBarAutomationPeer.FromElement(this.OwningDataGrid.HorizontalScrollBar));
children.Remove(ScrollBarAutomationPeer.FromElement(this.OwningDataGrid.VerticalScrollBar));
}
return children;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
Debug.WriteLine("DataGridAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Called by GetName.
/// </summary>
/// <returns>
/// Returns the first of these that is not null or empty:
/// - Value returned by the base implementation
/// - Name of the owning DataGrid
/// - DataGrid class name
/// </returns>
protected override string GetNameCore()
{
string name = base.GetNameCore();
if (string.IsNullOrEmpty(name))
{
if (this.OwningDataGrid != null)
{
name = this.OwningDataGrid.Name;
}
if (string.IsNullOrEmpty(name))
{
name = this.GetClassName();
}
}
#if DEBUG_AUTOMATION
Debug.WriteLine("DataGridAutomationPeer.GetNameCore returns " + name);
#endif
return name;
}
/// <summary>
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
/// </summary>
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
protected override object GetPatternCore(PatternInterface patternInterface)
{
switch (patternInterface)
{
case PatternInterface.Grid:
case PatternInterface.Selection:
case PatternInterface.Table:
return this;
case PatternInterface.Scroll:
{
if (this.HorizontallyScrollable || this.VerticallyScrollable)
{
return this;
}
break;
}
}
return base.GetPatternCore(patternInterface);
}
int IGridProvider.ColumnCount
{
get
{
return this.OwningDataGrid.Columns.Count;
}
}
int IGridProvider.RowCount
{
get
{
return this.OwningDataGrid.DataConnection.Count;
}
}
IRawElementProviderSimple IGridProvider.GetItem(int row, int column)
{
if (this.OwningDataGrid != null &&
this.OwningDataGrid.DataConnection != null &&
row >= 0 && row < this.OwningDataGrid.SlotCount &&
column >= 0 && column < this.OwningDataGrid.Columns.Count)
{
object item = null;
if (!this.OwningDataGrid.IsSlotVisible(this.OwningDataGrid.SlotFromRowIndex(row)))
{
item = this.OwningDataGrid.DataConnection.GetDataItem(row);
}
this.OwningDataGrid.ScrollIntoView(item, this.OwningDataGrid.Columns[column]);
DataGridRow dgr = this.OwningDataGrid.DisplayData.GetDisplayedRow(row);
if (this.OwningDataGrid.ColumnsInternal.RowGroupSpacerColumn.IsRepresented)
{
column++;
}
Debug.Assert(column >= 0, "Expected positive column value.");
Debug.Assert(column < this.OwningDataGrid.ColumnsItemsInternal.Count, "Expected smaller column value.");
DataGridCell cell = dgr.Cells[column];
AutomationPeer peer = CreatePeerForElement(cell);
if (peer != null)
{
return ProviderFromPeer(peer);
}
}
return null;
}
bool IScrollProvider.HorizontallyScrollable
{
get
{
return this.HorizontallyScrollable;
}
}
double IScrollProvider.HorizontalScrollPercent
{
get
{
return this.HorizontalScrollPercent;
}
}
double IScrollProvider.HorizontalViewSize
{
get
{
return this.HorizontalViewSize;
}
}
bool IScrollProvider.VerticallyScrollable
{
get
{
return this.VerticallyScrollable;
}
}
double IScrollProvider.VerticalScrollPercent
{
get
{
return this.VerticalScrollPercent;
}
}
double IScrollProvider.VerticalViewSize
{
get
{
return this.VerticalViewSize;
}
}
void IScrollProvider.Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount)
{
if (!IsEnabled())
{
throw new ElementNotEnabledException();
}
bool scrollHorizontally = horizontalAmount != ScrollAmount.NoAmount;
bool scrollVertically = verticalAmount != ScrollAmount.NoAmount;
if ((scrollHorizontally && !this.HorizontallyScrollable) || (scrollVertically && !this.VerticallyScrollable))
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
switch (horizontalAmount)
{
// In the small increment and decrement calls, ScrollHorizontally will adjust the
// ScrollBar.Value itself, so we don't need to do it here
case ScrollAmount.SmallIncrement:
this.OwningDataGrid.ProcessHorizontalScroll(ScrollEventType.SmallIncrement);
break;
case ScrollAmount.LargeIncrement:
this.OwningDataGrid.HorizontalScrollBar.Value += this.OwningDataGrid.HorizontalScrollBar.LargeChange;
this.OwningDataGrid.ProcessHorizontalScroll(ScrollEventType.LargeIncrement);
break;
case ScrollAmount.SmallDecrement:
this.OwningDataGrid.ProcessHorizontalScroll(ScrollEventType.SmallDecrement);
break;
case ScrollAmount.LargeDecrement:
this.OwningDataGrid.HorizontalScrollBar.Value -= this.OwningDataGrid.HorizontalScrollBar.LargeChange;
this.OwningDataGrid.ProcessHorizontalScroll(ScrollEventType.LargeDecrement);
break;
case ScrollAmount.NoAmount:
break;
default:
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
switch (verticalAmount)
{
// In the small increment and decrement calls, ScrollVertically will adjust the
// ScrollBar.Value itself, so we don't need to do it here
case ScrollAmount.SmallIncrement:
this.OwningDataGrid.ProcessVerticalScroll(ScrollEventType.SmallIncrement);
break;
case ScrollAmount.LargeIncrement:
this.OwningDataGrid.VerticalScrollBar.Value += this.OwningDataGrid.VerticalScrollBar.LargeChange;
this.OwningDataGrid.ProcessVerticalScroll(ScrollEventType.LargeIncrement);
break;
case ScrollAmount.SmallDecrement:
this.OwningDataGrid.ProcessVerticalScroll(ScrollEventType.SmallDecrement);
break;
case ScrollAmount.LargeDecrement:
this.OwningDataGrid.VerticalScrollBar.Value -= this.OwningDataGrid.VerticalScrollBar.LargeChange;
this.OwningDataGrid.ProcessVerticalScroll(ScrollEventType.LargeDecrement);
break;
case ScrollAmount.NoAmount:
break;
default:
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
void IScrollProvider.SetScrollPercent(double horizontalPercent, double verticalPercent)
{
if (!IsEnabled())
{
throw new ElementNotEnabledException();
}
bool scrollHorizontally = horizontalPercent != (double)ScrollPatternIdentifiers.NoScroll;
bool scrollVertically = verticalPercent != (double)ScrollPatternIdentifiers.NoScroll;
if ((scrollHorizontally && !this.HorizontallyScrollable) || (scrollVertically && !this.VerticallyScrollable))
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
if (scrollHorizontally && (horizontalPercent < 0.0 || horizontalPercent > 100.0))
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
if (scrollVertically && (verticalPercent < 0.0 || verticalPercent > 100.0))
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
if (scrollHorizontally)
{
this.OwningDataGrid.HorizontalScrollBar.Value =
(double)(this.OwningDataGrid.HorizontalScrollBar.Maximum * (horizontalPercent / 100.0));
this.OwningDataGrid.ProcessHorizontalScroll(ScrollEventType.ThumbPosition);
}
if (scrollVertically)
{
this.OwningDataGrid.VerticalScrollBar.Value =
(double)(this.OwningDataGrid.VerticalScrollBar.Maximum * (verticalPercent / 100.0));
this.OwningDataGrid.ProcessVerticalScroll(ScrollEventType.ThumbPosition);
}
}
IRawElementProviderSimple[] ISelectionProvider.GetSelection()
{
if (this.OwningDataGrid != null &&
this.OwningDataGrid.SelectedItems != null)
{
List<IRawElementProviderSimple> selectedProviders = new List<IRawElementProviderSimple>();
foreach (object item in this.OwningDataGrid.SelectedItems)
{
DataGridItemAutomationPeer peer = GetOrCreateItemPeer(item);
if (peer != null)
{
selectedProviders.Add(ProviderFromPeer(peer));
}
}
return selectedProviders.ToArray();
}
return null;
}
bool ISelectionProvider.CanSelectMultiple
{
get
{
return this.OwningDataGrid.SelectionMode == DataGridSelectionMode.Extended;
}
}
bool ISelectionProvider.IsSelectionRequired
{
get
{
return false;
}
}
RowOrColumnMajor ITableProvider.RowOrColumnMajor
{
get
{
return RowOrColumnMajor.RowMajor;
}
}
IRawElementProviderSimple[] ITableProvider.GetColumnHeaders()
{
if (this.OwningDataGrid.AreColumnHeadersVisible)
{
List<IRawElementProviderSimple> providers = new List<IRawElementProviderSimple>();
foreach (DataGridColumn column in this.OwningDataGrid.Columns)
{
if (column.HeaderCell != null)
{
AutomationPeer peer = CreatePeerForElement(column.HeaderCell);
if (peer != null)
{
providers.Add(ProviderFromPeer(peer));
}
}
}
if (providers.Count > 0)
{
return providers.ToArray();
}
}
return null;
}
IRawElementProviderSimple[] ITableProvider.GetRowHeaders()
{
if (this.OwningDataGrid.AreRowHeadersVisible)
{
List<IRawElementProviderSimple> providers = new List<IRawElementProviderSimple>();
foreach (DataGridRow row in this.OwningDataGrid.DisplayData.GetScrollingElements(true /*onlyRows*/))
{
if (row.HeaderCell != null)
{
AutomationPeer peer = CreatePeerForElement(row.HeaderCell);
if (peer != null)
{
providers.Add(ProviderFromPeer(peer));
}
}
}
if (providers.Count > 0)
{
return providers.ToArray();
}
}
return null;
}
private AutomationPeer GetCellPeer(int slot, int column)
{
if (slot >= 0 && slot < this.OwningDataGrid.SlotCount &&
column >= 0 && column < this.OwningDataGrid.ColumnsItemsInternal.Count &&
this.OwningDataGrid.IsSlotVisible(slot))
{
DataGridRow row = this.OwningDataGrid.DisplayData.GetDisplayedElement(slot) as DataGridRow;
if (row != null)
{
Debug.Assert(column >= 0, "Expected positive column value.");
Debug.Assert(column < this.OwningDataGrid.ColumnsItemsInternal.Count, "Expected smaller column value.");
DataGridCell cell = row.Cells[column];
return CreatePeerForElement(cell);
}
}
return null;
}
internal static void RaiseAutomationInvokeEvent(UIElement element)
{
if (AutomationPeer.ListenerExists(AutomationEvents.InvokePatternOnInvoked))
{
AutomationPeer peer = FrameworkElementAutomationPeer.FromElement(element);
if (peer != null)
{
#if DEBUG_AUTOMATION
Debug.WriteLine(peer.ToString() + ".RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked)");
#endif
peer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked);
}
}
}
internal List<AutomationPeer> GetChildPeers()
{
List<AutomationPeer> peers = new List<AutomationPeer>();
PopulateGroupItemPeers();
PopulateItemPeers();
if (_groupItemPeers != null && _groupItemPeers.Count > 0)
{
foreach (object group in this.OwningDataGrid.DataConnection.CollectionView.CollectionGroups /*Groups*/)
{
peers.Add(_groupItemPeers[group]);
}
}
else
{
foreach (DataGridItemAutomationPeer itemPeer in _itemPeers.Values)
{
peers.Add(itemPeer);
}
}
return peers;
}
internal DataGridGroupItemAutomationPeer GetOrCreateGroupItemPeer(object group)
{
DataGridGroupItemAutomationPeer peer = null;
if (group != null)
{
if (_groupItemPeers.ContainsKey(group))
{
peer = _groupItemPeers[group];
}
else
{
peer = new DataGridGroupItemAutomationPeer(group as ICollectionViewGroup, this.OwningDataGrid);
_groupItemPeers.Add(group, peer);
}
DataGridRowGroupHeaderAutomationPeer rghPeer = peer.OwningRowGroupHeaderPeer;
if (rghPeer != null)
{
rghPeer.EventsSource = peer;
}
}
return peer;
}
internal DataGridItemAutomationPeer GetOrCreateItemPeer(object item)
{
DataGridItemAutomationPeer peer = null;
if (item != null)
{
if (_itemPeers.ContainsKey(item))
{
peer = _itemPeers[item];
}
else
{
peer = new DataGridItemAutomationPeer(item, this.OwningDataGrid);
_itemPeers.Add(item, peer);
}
DataGridRowAutomationPeer rowPeer = peer.OwningRowPeer;
if (rowPeer != null)
{
rowPeer.EventsSource = peer;
}
}
return peer;
}
internal void PopulateGroupItemPeers()
{
Dictionary<object, DataGridGroupItemAutomationPeer> oldChildren = new Dictionary<object, DataGridGroupItemAutomationPeer>(_groupItemPeers);
_groupItemPeers.Clear();
if (this.OwningDataGrid.DataConnection.CollectionView != null &&
#if FEATURE_ICOLLECTIONVIEW_GROUP
this.OwningDataGrid.DataConnection.CollectionView.CanGroup &&
#endif
this.OwningDataGrid.DataConnection.CollectionView.CollectionGroups != null &&
this.OwningDataGrid.DataConnection.CollectionView.CollectionGroups.Count > 0)
{
List<object> groups = new List<object>(this.OwningDataGrid.DataConnection.CollectionView.CollectionGroups);
while (groups.Count > 0)
{
ICollectionViewGroup cvGroup = groups[0] as ICollectionViewGroup;
groups.RemoveAt(0);
if (cvGroup != null)
{
// Add the group's peer to the collection
DataGridGroupItemAutomationPeer peer = null;
if (oldChildren.ContainsKey(cvGroup))
{
peer = oldChildren[cvGroup] as DataGridGroupItemAutomationPeer;
}
else
{
peer = new DataGridGroupItemAutomationPeer(cvGroup, this.OwningDataGrid);
}
if (peer != null)
{
DataGridRowGroupHeaderAutomationPeer rghPeer = peer.OwningRowGroupHeaderPeer;
if (rghPeer != null)
{
rghPeer.EventsSource = peer;
}
}
// This guards against the addition of duplicate items
if (!_groupItemPeers.ContainsKey(cvGroup))
{
_groupItemPeers.Add(cvGroup, peer);
}
#if FEATURE_ICOLLECTIONVIEW_GROUP
// Look for any sub groups
if (!cvGroup.IsBottomLevel)
{
int position = 0;
foreach (object subGroup in cvGroup.Items)
{
groups.Insert(position, subGroup);
position++;
}
}
#endif
}
}
}
}
internal void PopulateItemPeers()
{
Dictionary<object, DataGridItemAutomationPeer> oldChildren = new Dictionary<object, DataGridItemAutomationPeer>(_itemPeers);
_itemPeers.Clear();
if (this.OwningDataGrid.ItemsSource != null)
{
foreach (object item in this.OwningDataGrid.ItemsSource)
{
if (item != null)
{
DataGridItemAutomationPeer peer;
if (oldChildren.ContainsKey(item))
{
peer = oldChildren[item] as DataGridItemAutomationPeer;
}
else
{
peer = new DataGridItemAutomationPeer(item, this.OwningDataGrid);
}
if (peer != null)
{
DataGridRowAutomationPeer rowPeer = peer.OwningRowPeer;
if (rowPeer != null)
{
rowPeer.EventsSource = peer;
}
}
// This guards against the addition of duplicate items
if (!_itemPeers.ContainsKey(item))
{
_itemPeers.Add(item, peer);
}
}
}
}
}
internal void RaiseAutomationCellSelectedEvent(int slot, int column)
{
AutomationPeer cellPeer = GetCellPeer(slot, column);
if (cellPeer != null)
{
#if DEBUG_AUTOMATION
Debug.WriteLine(cellPeer.ToString() + ".RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementSelected)");
#endif
cellPeer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementSelected);
}
}
internal void RaiseAutomationFocusChangedEvent(int slot, int column)
{
if (slot >= 0 && slot < this.OwningDataGrid.SlotCount &&
column >= 0 && column < this.OwningDataGrid.ColumnsItemsInternal.Count &&
this.OwningDataGrid.IsSlotVisible(slot))
{
if (this.OwningDataGrid.RowGroupHeadersTable.Contains(slot))
{
DataGridRowGroupHeader header = this.OwningDataGrid.DisplayData.GetDisplayedElement(slot) as DataGridRowGroupHeader;
if (header != null)
{
AutomationPeer headerPeer = CreatePeerForElement(header);
if (headerPeer != null)
{
#if DEBUG_AUTOMATION
Debug.WriteLine(headerPeer.ToString() + ".RaiseAutomationEvent(AutomationEvents.AutomationFocusChanged)");
#endif
headerPeer.RaiseAutomationEvent(AutomationEvents.AutomationFocusChanged);
}
}
}
else
{
AutomationPeer cellPeer = GetCellPeer(slot, column);
if (cellPeer != null)
{
#if DEBUG_AUTOMATION
Debug.WriteLine(cellPeer.ToString() + ".RaiseAutomationEvent(AutomationEvents.AutomationFocusChanged)");
#endif
cellPeer.RaiseAutomationEvent(AutomationEvents.AutomationFocusChanged);
}
}
}
}
internal void RaiseAutomationInvokeEvents(DataGridEditingUnit editingUnit, DataGridColumn column, DataGridRow row)
{
switch (editingUnit)
{
case DataGridEditingUnit.Cell:
{
DataGridCell cell = row.Cells[column.Index];
AutomationPeer peer = FromElement(cell);
if (peer != null)
{
peer.InvalidatePeer();
}
else
{
peer = CreatePeerForElement(cell);
}
if (peer != null)
{
#if DEBUG_AUTOMATION
Debug.WriteLine(peer.ToString() + ".RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked)");
#endif
peer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked);
}
break;
}
case DataGridEditingUnit.Row:
{
DataGridItemAutomationPeer peer = GetOrCreateItemPeer(row.DataContext);
#if DEBUG_AUTOMATION
Debug.WriteLine("DataGridItemAutomationPeer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked)");
#endif
peer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked);
break;
}
}
}
internal void RaiseAutomationScrollEvents()
{
IScrollProvider isp = (IScrollProvider)this;
bool newHorizontallyScrollable = isp.HorizontallyScrollable;
double newHorizontalViewSize = isp.HorizontalViewSize;
double newHorizontalScrollPercent = isp.HorizontalScrollPercent;
bool newVerticallyScrollable = isp.VerticallyScrollable;
double newVerticalViewSize = isp.VerticalViewSize;
double newVerticalScrollPercent = isp.VerticalScrollPercent;
if (_oldHorizontallyScrollable != newHorizontallyScrollable)
{
RaisePropertyChangedEvent(
ScrollPatternIdentifiers.HorizontallyScrollableProperty,
_oldHorizontallyScrollable,
newHorizontallyScrollable);
_oldHorizontallyScrollable = newHorizontallyScrollable;
}
if (_oldHorizontalViewSize != newHorizontalViewSize)
{
RaisePropertyChangedEvent(
ScrollPatternIdentifiers.HorizontalViewSizeProperty,
_oldHorizontalViewSize,
newHorizontalViewSize);
_oldHorizontalViewSize = newHorizontalViewSize;
}
if (_oldHorizontalScrollPercent != newHorizontalScrollPercent)
{
RaisePropertyChangedEvent(
ScrollPatternIdentifiers.HorizontalScrollPercentProperty,
_oldHorizontalScrollPercent,
newHorizontalScrollPercent);
_oldHorizontalScrollPercent = newHorizontalScrollPercent;
}
if (_oldVerticallyScrollable != newVerticallyScrollable)
{
RaisePropertyChangedEvent(
ScrollPatternIdentifiers.VerticallyScrollableProperty,
_oldVerticallyScrollable,
newVerticallyScrollable);
_oldVerticallyScrollable = newVerticallyScrollable;
}
if (_oldVerticalViewSize != newVerticalViewSize)
{
RaisePropertyChangedEvent(
ScrollPatternIdentifiers.VerticalViewSizeProperty,
_oldVerticalViewSize,
newVerticalViewSize);
_oldVerticalViewSize = newVerticalViewSize;
}
if (_oldVerticalScrollPercent != newVerticalScrollPercent)
{
RaisePropertyChangedEvent(
ScrollPatternIdentifiers.VerticalScrollPercentProperty,
_oldVerticalScrollPercent,
newVerticalScrollPercent);
_oldVerticalScrollPercent = newVerticalScrollPercent;
}
}
internal void RaiseAutomationSelectionEvents(SelectionChangedEventArgs e)
{
// If the result of an AddToSelection or RemoveFromSelection is a single selected item,
// then all we raise is the ElementSelectedEvent for single item
if (AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected) &&
this.OwningDataGrid.SelectedItems.Count == 1)
{
if (this.OwningDataGrid.SelectedItem != null && _itemPeers.ContainsKey(this.OwningDataGrid.SelectedItem))
{
DataGridItemAutomationPeer peer = _itemPeers[this.OwningDataGrid.SelectedItem];
#if DEBUG_AUTOMATION
Debug.WriteLine("DataGridItemAutomationPeer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementSelected)");
#endif
peer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementSelected);
}
}
else
{
int i;
if (AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementAddedToSelection))
{
for (i = 0; i < e.AddedItems.Count; i++)
{
if (e.AddedItems[i] != null && _itemPeers.ContainsKey(e.AddedItems[i]))
{
DataGridItemAutomationPeer peer = _itemPeers[e.AddedItems[i]];
#if DEBUG_AUTOMATION
Debug.WriteLine("DataGridItemAutomationPeer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementAddedToSelection)");
#endif
peer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementAddedToSelection);
}
}
}
if (AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection))
{
for (i = 0; i < e.RemovedItems.Count; i++)
{
if (e.RemovedItems[i] != null && _itemPeers.ContainsKey(e.RemovedItems[i]))
{
DataGridItemAutomationPeer peer = _itemPeers[e.RemovedItems[i]];
#if DEBUG_AUTOMATION
Debug.WriteLine("DataGridItemAutomationPeer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection)");
#endif
peer.RaiseAutomationEvent(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection);
}
}
}
}
}
internal void UpdateRowGroupHeaderPeerEventsSource(DataGridRowGroupHeader header)
{
object group = header.RowGroupInfo.CollectionViewGroup;
DataGridRowGroupHeaderAutomationPeer peer = DataGridRowGroupHeaderAutomationPeer.FromElement(header) as DataGridRowGroupHeaderAutomationPeer;
if (peer != null && group != null && _groupItemPeers.ContainsKey(group))
{
peer.EventsSource = _groupItemPeers[group];
}
}
internal void UpdateRowPeerEventsSource(DataGridRow row)
{
DataGridRowAutomationPeer peer = FromElement(row) as DataGridRowAutomationPeer;
if (peer != null && row.DataContext != null && _itemPeers.ContainsKey(row.DataContext))
{
peer.EventsSource = _itemPeers[row.DataContext];
}
}
}
}

Просмотреть файл

@ -0,0 +1,403 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Automation.Provider;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for DataGridCell
/// </summary>
public class DataGridCellAutomationPeer : FrameworkElementAutomationPeer,
IGridItemProvider, IInvokeProvider, IScrollItemProvider, ISelectionItemProvider, ITableItemProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridCellAutomationPeer"/> class.
/// </summary>
/// <param name="owner">DataGridCell</param>
public DataGridCellAutomationPeer(DataGridCell owner)
: base(owner)
{
}
private IRawElementProviderSimple ContainingGrid
{
get
{
AutomationPeer peer = CreatePeerForElement(this.OwningGrid);
if (peer != null)
{
return ProviderFromPeer(peer);
}
return null;
}
}
private DataGridCell OwningCell
{
get
{
return Owner as DataGridCell;
}
}
private DataGridColumn OwningColumn
{
get
{
return this.OwningCell.OwningColumn;
}
}
private DataGrid OwningGrid
{
get
{
return this.OwningCell.OwningGrid;
}
}
private DataGridRow OwningRow
{
get
{
return this.OwningCell.OwningRow;
}
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
if (this.OwningColumn != null)
{
if (this.OwningColumn is DataGridCheckBoxColumn)
{
return AutomationControlType.CheckBox;
}
if (this.OwningColumn is DataGridTextColumn)
{
return AutomationControlType.Text;
}
if (this.OwningColumn is DataGridComboBoxColumn)
{
return AutomationControlType.ComboBox;
}
}
return AutomationControlType.Custom;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridCellAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Gets the name of the element.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetNameCore()
{
TextBlock textBlock = this.OwningCell.Content as TextBlock;
if (textBlock != null)
{
return textBlock.Text;
}
TextBox textBox = this.OwningCell.Content as TextBox;
if (textBox != null)
{
return textBox.Text;
}
if (this.OwningColumn != null && this.OwningRow != null)
{
object cellContent = null;
DataGridBoundColumn boundColumn = this.OwningColumn as DataGridBoundColumn;
if (boundColumn != null && boundColumn.Binding != null)
{
cellContent = boundColumn.GetCellValue(this.OwningRow.DataContext, boundColumn.Binding);
}
if (cellContent == null && this.OwningColumn.ClipboardContentBinding != null)
{
cellContent = this.OwningColumn.GetCellValue(this.OwningRow.DataContext, this.OwningColumn.ClipboardContentBinding);
}
if (cellContent != null)
{
string cellName = cellContent.ToString();
if (!string.IsNullOrEmpty(cellName))
{
return cellName;
}
}
}
return base.GetNameCore();
}
/// <summary>
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
/// </summary>
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (this.OwningGrid != null)
{
switch (patternInterface)
{
case PatternInterface.Invoke:
{
if (!this.OwningGrid.IsReadOnly &&
this.OwningColumn != null &&
!this.OwningColumn.IsReadOnly)
{
return this;
}
break;
}
case PatternInterface.ScrollItem:
{
if (this.OwningGrid.HorizontalScrollBar != null &&
this.OwningGrid.HorizontalScrollBar.Maximum > 0)
{
return this;
}
break;
}
case PatternInterface.GridItem:
case PatternInterface.SelectionItem:
case PatternInterface.TableItem:
return this;
}
}
return base.GetPatternCore(patternInterface);
}
/// <summary>
/// Gets a value that indicates whether the element can accept keyboard focus.
/// </summary>
/// <returns>true if the element can accept keyboard focus; otherwise, false</returns>
protected override bool IsKeyboardFocusableCore()
{
return true;
}
int IGridItemProvider.Column
{
get
{
int column = this.OwningCell.ColumnIndex;
if (column >= 0 && this.OwningGrid != null && this.OwningGrid.ColumnsInternal.RowGroupSpacerColumn.IsRepresented)
{
column--;
}
return column;
}
}
int IGridItemProvider.ColumnSpan
{
get
{
return 1;
}
}
IRawElementProviderSimple IGridItemProvider.ContainingGrid
{
get
{
return this.ContainingGrid;
}
}
int IGridItemProvider.Row
{
get
{
return this.OwningCell.RowIndex;
}
}
int IGridItemProvider.RowSpan
{
get
{
return 1;
}
}
void IInvokeProvider.Invoke()
{
EnsureEnabled();
if (this.OwningGrid != null)
{
if (this.OwningGrid.WaitForLostFocus(() => { ((IInvokeProvider)this).Invoke(); }))
{
return;
}
if (this.OwningGrid.EditingRow == this.OwningRow && this.OwningGrid.EditingColumnIndex == this.OwningCell.ColumnIndex)
{
this.OwningGrid.CommitEdit(DataGridEditingUnit.Cell, true /*exitEditingMode*/);
}
else if (this.OwningGrid.UpdateSelectionAndCurrency(this.OwningCell.ColumnIndex, this.OwningRow.Slot, DataGridSelectionAction.SelectCurrent, true))
{
this.OwningGrid.BeginEdit();
}
}
}
void IScrollItemProvider.ScrollIntoView()
{
if (this.OwningGrid != null)
{
this.OwningGrid.ScrollIntoView(this.OwningCell.DataContext, this.OwningColumn);
}
else
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
bool ISelectionItemProvider.IsSelected
{
get
{
if (this.OwningGrid != null && this.OwningRow != null)
{
return this.OwningRow.IsSelected;
}
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
{
get
{
AutomationPeer peer = CreatePeerForElement(this.OwningRow);
if (peer != null)
{
return ProviderFromPeer(peer);
}
return null;
}
}
void ISelectionItemProvider.AddToSelection()
{
EnsureEnabled();
if (this.OwningCell.OwningGrid == null ||
this.OwningCell.OwningGrid.CurrentSlot != this.OwningCell.RowIndex ||
this.OwningCell.OwningGrid.CurrentColumnIndex != this.OwningCell.ColumnIndex)
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
void ISelectionItemProvider.RemoveFromSelection()
{
EnsureEnabled();
if (this.OwningCell.OwningGrid == null ||
(this.OwningCell.OwningGrid.CurrentSlot == this.OwningCell.RowIndex &&
this.OwningCell.OwningGrid.CurrentColumnIndex == this.OwningCell.ColumnIndex))
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
void ISelectionItemProvider.Select()
{
EnsureEnabled();
if (this.OwningGrid != null)
{
if (this.OwningGrid.WaitForLostFocus(() => { ((ISelectionItemProvider)this).Select(); }))
{
return;
}
this.OwningGrid.UpdateSelectionAndCurrency(this.OwningCell.ColumnIndex, this.OwningRow.Slot, DataGridSelectionAction.SelectCurrent, false);
}
}
IRawElementProviderSimple[] ITableItemProvider.GetColumnHeaderItems()
{
if (this.OwningGrid != null &&
this.OwningGrid.AreColumnHeadersVisible &&
this.OwningColumn.HeaderCell != null)
{
AutomationPeer peer = CreatePeerForElement(this.OwningColumn.HeaderCell);
if (peer != null)
{
List<IRawElementProviderSimple> providers = new List<IRawElementProviderSimple>(1);
providers.Add(ProviderFromPeer(peer));
return providers.ToArray();
}
}
return null;
}
IRawElementProviderSimple[] ITableItemProvider.GetRowHeaderItems()
{
if (this.OwningGrid != null &&
this.OwningGrid.AreRowHeadersVisible &&
this.OwningRow.HeaderCell != null)
{
AutomationPeer peer = CreatePeerForElement(this.OwningRow.HeaderCell);
if (peer != null)
{
List<IRawElementProviderSimple> providers = new List<IRawElementProviderSimple>(1);
providers.Add(ProviderFromPeer(peer));
return providers.ToArray();
}
}
return null;
}
private void EnsureEnabled()
{
if (!IsEnabled())
{
throw new ElementNotEnabledException();
}
}
}
}

Просмотреть файл

@ -0,0 +1,200 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Automation.Provider;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for DataGridColumnHeader
/// </summary>
public class DataGridColumnHeaderAutomationPeer : FrameworkElementAutomationPeer,
IInvokeProvider, IScrollItemProvider, ITransformProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridColumnHeaderAutomationPeer"/> class.
/// </summary>
/// <param name="owner">DataGridColumnHeader</param>
public DataGridColumnHeaderAutomationPeer(DataGridColumnHeader owner)
: base(owner)
{
}
private DataGridColumnHeader OwningHeader
{
get
{
return Owner as DataGridColumnHeader;
}
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.HeaderItem;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridColumnHeaderAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Gets the string that describes the functionality of the control that is associated with the automation peer.
/// </summary>
/// <returns>The string that contains the help text.</returns>
protected override string GetHelpTextCore()
{
if (this.OwningHeader.OwningColumn != null && this.OwningHeader.OwningColumn.SortDirection.HasValue)
{
if (this.OwningHeader.OwningColumn.SortDirection.Value == DataGridSortDirection.Ascending)
{
return "Ascending";
}
return "Descending";
}
return base.GetHelpTextCore();
}
/// <summary>
/// Gets the name of the element.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetNameCore()
{
string header = this.OwningHeader.Content as string;
if (header != null)
{
return header;
}
return base.GetNameCore();
}
/// <summary>
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
/// </summary>
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
protected override object GetPatternCore(PatternInterface patternInterface)
{
if (this.OwningHeader.OwningGrid != null)
{
switch (patternInterface)
{
case PatternInterface.Invoke:
// this.OwningHeader.OwningGrid.DataConnection.AllowSort property is ignored because of the DataGrid.Sorting custom sorting capability.
if (this.OwningHeader.OwningGrid.CanUserSortColumns &&
this.OwningHeader.OwningColumn.CanUserSort)
{
return this;
}
break;
case PatternInterface.ScrollItem:
if (this.OwningHeader.OwningGrid.HorizontalScrollBar != null &&
this.OwningHeader.OwningGrid.HorizontalScrollBar.Maximum > 0)
{
return this;
}
break;
case PatternInterface.Transform:
if (this.OwningHeader.OwningColumn != null &&
this.OwningHeader.OwningColumn.ActualCanUserResize)
{
return this;
}
break;
}
}
return base.GetPatternCore(patternInterface);
}
/// <summary>
/// Gets a value that specifies whether the element is a content element.
/// </summary>
/// <returns>True if the element is a content element; otherwise false</returns>
protected override bool IsContentElementCore()
{
return false;
}
void IInvokeProvider.Invoke()
{
this.OwningHeader.InvokeProcessSort();
}
void IScrollItemProvider.ScrollIntoView()
{
this.OwningHeader.OwningGrid.ScrollIntoView(null, this.OwningHeader.OwningColumn);
}
bool ITransformProvider.CanMove
{
get
{
return false;
}
}
bool ITransformProvider.CanResize
{
get
{
return this.OwningHeader.OwningColumn != null && this.OwningHeader.OwningColumn.ActualCanUserResize;
}
}
bool ITransformProvider.CanRotate
{
get
{
return false;
}
}
void ITransformProvider.Move(double x, double y)
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
void ITransformProvider.Resize(double width, double height)
{
if (this.OwningHeader.OwningColumn != null &&
this.OwningHeader.OwningColumn.ActualCanUserResize)
{
this.OwningHeader.OwningColumn.Width = new DataGridLength(width);
}
}
void ITransformProvider.Rotate(double degrees)
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
}

Просмотреть файл

@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Windows.UI.Xaml.Automation.Peers;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for DataGridColumnHeadersPresenter
/// </summary>
public class DataGridColumnHeadersPresenterAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridColumnHeadersPresenterAutomationPeer"/> class.
/// </summary>
/// <param name="owner">DataGridColumnHeadersPresenter</param>
public DataGridColumnHeadersPresenterAutomationPeer(DataGridColumnHeadersPresenter owner)
: base(owner)
{
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Header;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridColumnHeadersPresenterAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Gets a value that specifies whether the element is a content element.
/// </summary>
/// <returns>True if the element is a content element; otherwise false</returns>
protected override bool IsContentElementCore()
{
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Windows.UI.Xaml.Automation.Peers;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for DataGridDetailsPresenter
/// </summary>
public class DataGridDetailsPresenterAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridDetailsPresenterAutomationPeer"/> class.
/// </summary>
/// <param name="owner">DataGridDetailsPresenter</param>
public DataGridDetailsPresenterAutomationPeer(DataGridDetailsPresenter owner)
: base(owner)
{
}
/// <summary>
/// Gets the control type for the DataGridDetailsPresenter element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridDetailsPresenterAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Gets or sets a value indicating whether the DataGridDetailsPresenter associated with this UIElementAutomationPeer
/// is understood by the end user as interactive.
/// </summary>
/// <returns>True if the DataGridDetailsPresenter associated with this UIElementAutomationPeer
/// is understood by the end user as interactive.</returns>
protected override bool IsControlElementCore()
{
return true;
}
/// <summary>
/// Gets a value that specifies whether the element is a content element.
/// </summary>
/// <returns>True if the element is a content element; otherwise false</returns>
protected override bool IsContentElementCore()
{
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,575 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Automation.Provider;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for a group of items in a DataGrid
/// </summary>
public class DataGridGroupItemAutomationPeer : FrameworkElementAutomationPeer,
IExpandCollapseProvider, IGridProvider, IScrollItemProvider, ISelectionProvider
{
private ICollectionViewGroup _group;
private AutomationPeer _dataGridAutomationPeer;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridGroupItemAutomationPeer"/> class.
/// </summary>
public DataGridGroupItemAutomationPeer(ICollectionViewGroup group, DataGrid dataGrid)
: base(dataGrid)
{
if (group == null)
{
throw new ArgumentNullException("group");
}
if (dataGrid == null)
{
throw new ArgumentNullException("dataGrid");
}
_group = group;
_dataGridAutomationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(dataGrid);
}
/// <summary>
/// Gets the owning DataGrid
/// </summary>
private DataGrid OwningDataGrid
{
get
{
DataGridAutomationPeer gridPeer = _dataGridAutomationPeer as DataGridAutomationPeer;
return gridPeer.Owner as DataGrid;
}
}
/// <summary>
/// Gets the owning DataGrid's Automation Peer
/// </summary>
private DataGridAutomationPeer OwningDataGridPeer
{
get
{
return _dataGridAutomationPeer as DataGridAutomationPeer;
}
}
/// <summary>
/// Gets the owning DataGridRowGroupHeader
/// </summary>
private DataGridRowGroupHeader OwningRowGroupHeader
{
get
{
if (this.OwningDataGrid != null)
{
DataGridRowGroupInfo groupInfo = this.OwningDataGrid.RowGroupInfoFromCollectionViewGroup(_group);
if (groupInfo != null && this.OwningDataGrid.IsSlotVisible(groupInfo.Slot))
{
return this.OwningDataGrid.DisplayData.GetDisplayedElement(groupInfo.Slot) as DataGridRowGroupHeader;
}
}
return null;
}
}
/// <summary>
/// Gets the owning DataGridRowGroupHeader's Automation Peer
/// </summary>
internal DataGridRowGroupHeaderAutomationPeer OwningRowGroupHeaderPeer
{
get
{
DataGridRowGroupHeaderAutomationPeer rowGroupHeaderPeer = null;
DataGridRowGroupHeader rowGroupHeader = this.OwningRowGroupHeader;
if (rowGroupHeader != null)
{
rowGroupHeaderPeer = FrameworkElementAutomationPeer.FromElement(rowGroupHeader) as DataGridRowGroupHeaderAutomationPeer;
if (rowGroupHeaderPeer == null)
{
rowGroupHeaderPeer = FrameworkElementAutomationPeer.CreatePeerForElement(rowGroupHeader) as DataGridRowGroupHeaderAutomationPeer;
}
}
return rowGroupHeaderPeer;
}
}
/// <summary>
/// Returns the accelerator key for the UIElement that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>The accelerator key for the UIElement that is associated with this DataGridGroupItemAutomationPeer.</returns>
protected override string GetAcceleratorKeyCore()
{
return (this.OwningRowGroupHeaderPeer != null) ? this.OwningRowGroupHeaderPeer.GetAcceleratorKey() : string.Empty;
}
/// <summary>
/// Returns the access key for the UIElement that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>The access key for the UIElement that is associated with this DataGridGroupItemAutomationPeer.</returns>
protected override string GetAccessKeyCore()
{
return (this.OwningRowGroupHeaderPeer != null) ? this.OwningRowGroupHeaderPeer.GetAccessKey() : string.Empty;
}
/// <summary>
/// Returns the control type for the UIElement that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>The control type for the UIElement that is associated with this DataGridGroupItemAutomationPeer.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Group;
}
/// <summary>
/// Returns the string that uniquely identifies the FrameworkElement that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>The string that uniquely identifies the FrameworkElement that is associated with this DataGridGroupItemAutomationPeer.</returns>
protected override string GetAutomationIdCore()
{
// The AutomationId should be unset for dynamic content.
return string.Empty;
}
/// <summary>
/// Returns the Rect that represents the bounding rectangle of the UIElement that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>The Rect that represents the bounding rectangle of the UIElement that is associated with this DataGridGroupItemAutomationPeer.</returns>
protected override Rect GetBoundingRectangleCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.GetBoundingRectangle() : default(Rect);
}
/// <summary>
/// Returns the collection of elements that are represented in the UI Automation tree as immediate
/// child elements of the automation peer.
/// </summary>
/// <returns>The children elements.</returns>
protected override IList<AutomationPeer> GetChildrenCore()
{
List<AutomationPeer> children = new List<AutomationPeer>();
if (this.OwningRowGroupHeaderPeer != null)
{
this.OwningRowGroupHeaderPeer.InvalidatePeer();
children.AddRange(this.OwningRowGroupHeaderPeer.GetChildren());
}
#if FEATURE_ICOLLECTIONVIEW_GROUP
if (_group.IsBottomLevel)
{
#endif
#pragma warning disable SA1137 // Elements should have the same indentation
foreach (object item in _group.GroupItems /*Items*/)
{
children.Add(this.OwningDataGridPeer.GetOrCreateItemPeer(item));
}
#pragma warning restore SA1137 // Elements should have the same indentation
#if FEATURE_ICOLLECTIONVIEW_GROUP
}
else
{
foreach (object group in _group.Items)
{
children.Add(this.OwningDataGridPeer.GetOrCreateGroupItemPeer(group));
}
}
#endif
return children;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.GetClassName() : string.Empty;
#if DEBUG_AUTOMATION
Debug.WriteLine("DataGridGroupItemAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Returns a Point that represents the clickable space that is on the UIElement that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>A Point that represents the clickable space that is on the UIElement that is associated with this DataGridGroupItemAutomationPeer.</returns>
protected override Point GetClickablePointCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.GetClickablePoint() : new Point(double.NaN, double.NaN);
}
/// <summary>
/// Returns the string that describes the functionality of the control that is associated with the automation peer.
/// </summary>
/// <returns>The string that contains the help text.</returns>
protected override string GetHelpTextCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.GetHelpText() : string.Empty;
}
/// <summary>
/// Returns a string that communicates the visual status of the UIElement that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>A string that communicates the visual status of the UIElement that is associated with this DataGridGroupItemAutomationPeer.</returns>
protected override string GetItemStatusCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.GetItemStatus() : string.Empty;
}
/// <summary>
/// Returns a human-readable string that contains the item type that the UIElement for this DataGridGroupItemAutomationPeer represents.
/// </summary>
/// <returns>A human-readable string that contains the item type that the UIElement for this DataGridGroupItemAutomationPeer represents.</returns>
protected override string GetItemTypeCore()
{
return (this.OwningRowGroupHeaderPeer != null) ? this.OwningRowGroupHeaderPeer.GetItemType() : string.Empty;
}
/// <summary>
/// Returns the AutomationPeer for the element that is targeted to the UIElement for this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>The AutomationPeer for the element that is targeted to the UIElement for this DataGridGroupItemAutomationPeer.</returns>
protected override AutomationPeer GetLabeledByCore()
{
return (this.OwningRowGroupHeaderPeer != null) ? this.OwningRowGroupHeaderPeer.GetLabeledBy() : null;
}
/// <summary>
/// Returns a localized human readable string for this control type.
/// </summary>
/// <returns>A localized human readable string for this control type.</returns>
protected override string GetLocalizedControlTypeCore()
{
return (this.OwningRowGroupHeaderPeer != null) ? this.OwningRowGroupHeaderPeer.GetLocalizedControlType() : string.Empty;
}
/// <summary>
/// Returns the string that describes the functionality of the control that is associated with this DataGridGroupItemAutomationPeer.
/// </summary>
/// <returns>The string that contains the help text.</returns>
protected override string GetNameCore()
{
#if FEATURE_ICOLLECTIONVIEW_GROUP
if (_group.Name != null)
{
string name = _group.Name.ToString();
if (!string.IsNullOrEmpty(name))
{
return name;
}
}
#endif
return base.GetNameCore();
}
/// <summary>
/// Returns a value indicating whether the element associated with this DataGridGroupItemAutomationPeer is laid out in a specific direction.
/// </summary>
/// <returns>A value indicating whether the element associated with this DataGridGroupItemAutomationPeer is laid out in a specific direction.</returns>
protected override AutomationOrientation GetOrientationCore()
{
return (this.OwningRowGroupHeaderPeer != null) ? this.OwningRowGroupHeaderPeer.GetOrientation() : AutomationOrientation.None;
}
/// <summary>
/// Gets the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
/// </summary>
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
protected override object GetPatternCore(PatternInterface patternInterface)
{
switch (patternInterface)
{
case PatternInterface.ExpandCollapse:
case PatternInterface.Grid:
case PatternInterface.Selection:
case PatternInterface.Table:
return this;
case PatternInterface.ScrollItem:
{
if (this.OwningDataGrid.VerticalScrollBar != null &&
this.OwningDataGrid.VerticalScrollBar.Maximum > 0)
{
return this;
}
break;
}
}
return base.GetPatternCore(patternInterface);
}
/// <summary>
/// Returns a value indicating whether the UIElement associated with this DataGridGroupItemAutomationPeer can accept keyboard focus.
/// </summary>
/// <returns>True if the element is focusable by the keyboard; otherwise false.</returns>
protected override bool HasKeyboardFocusCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.HasKeyboardFocus() : false;
}
/// <summary>
/// Returns a value indicating whether the element associated with this DataGridGroupItemAutomationPeer is an element that contains data that is presented to the user.
/// </summary>
/// <returns>True if the element contains data for the user to read; otherwise, false.</returns>
protected override bool IsContentElementCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.IsContentElement() : true;
}
/// <summary>
/// Gets or sets a value indicating whether the UIElement associated with this DataGridGroupItemAutomationPeer
/// is understood by the end user as interactive.
/// </summary>
/// <returns>True if the UIElement associated with this DataGridGroupItemAutomationPeer
/// is understood by the end user as interactive.</returns>
protected override bool IsControlElementCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.IsControlElement() : true;
}
/// <summary>
/// Gets a value indicating whether this DataGridGroupItemAutomationPeer can receive and send events to the associated element.
/// </summary>
/// <returns>True if this DataGridGroupItemAutomationPeer can receive and send events; otherwise, false.</returns>
protected override bool IsEnabledCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.IsEnabled() : false;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridGroupItemAutomationPeer can accept keyboard focus.
/// </summary>
/// <returns>True if the UIElement associated with this DataGridGroupItemAutomationPeer can accept keyboard focus.</returns>
protected override bool IsKeyboardFocusableCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.IsKeyboardFocusable() : false;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridGroupItemAutomationPeer is off the screen.
/// </summary>
/// <returns>True if the element is not on the screen; otherwise, false.</returns>
protected override bool IsOffscreenCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.IsOffscreen() : true;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridGroupItemAutomationPeer contains protected content.
/// </summary>
/// <returns>True if the UIElement contains protected content.</returns>
protected override bool IsPasswordCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.IsPassword() : false;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridGroupItemAutomationPeer is required to be completed on a form.
/// </summary>
/// <returns>True if the UIElement is required to be completed on a form.</returns>
protected override bool IsRequiredForFormCore()
{
return this.OwningRowGroupHeaderPeer != null ? this.OwningRowGroupHeaderPeer.IsRequiredForForm() : false;
}
/// <summary>
/// Sets the keyboard input focus on the UIElement associated with this DataGridGroupItemAutomationPeer.
/// </summary>
protected override void SetFocusCore()
{
if (this.OwningRowGroupHeaderPeer != null)
{
this.OwningRowGroupHeaderPeer.SetFocus();
}
}
void IExpandCollapseProvider.Collapse()
{
EnsureEnabled();
if (this.OwningDataGrid != null)
{
this.OwningDataGrid.CollapseRowGroup(_group, false /*collapseAllSubgroups*/);
}
}
void IExpandCollapseProvider.Expand()
{
EnsureEnabled();
if (this.OwningDataGrid != null)
{
this.OwningDataGrid.ExpandRowGroup(_group, false /*expandAllSubgroups*/);
}
}
ExpandCollapseState IExpandCollapseProvider.ExpandCollapseState
{
get
{
if (this.OwningDataGrid != null)
{
DataGridRowGroupInfo groupInfo = this.OwningDataGrid.RowGroupInfoFromCollectionViewGroup(_group);
if (groupInfo != null && groupInfo.Visibility == Visibility.Visible)
{
return ExpandCollapseState.Expanded;
}
}
return ExpandCollapseState.Collapsed;
}
}
int IGridProvider.ColumnCount
{
get
{
if (this.OwningDataGrid != null)
{
return this.OwningDataGrid.Columns.Count;
}
return 0;
}
}
IRawElementProviderSimple IGridProvider.GetItem(int row, int column)
{
EnsureEnabled();
if (this.OwningDataGrid != null &&
this.OwningDataGrid.DataConnection != null &&
row >= 0 && row < _group.GroupItems.Count /*ItemCount*/ &&
column >= 0 && column < this.OwningDataGrid.Columns.Count)
{
DataGridRowGroupInfo groupInfo = this.OwningDataGrid.RowGroupInfoFromCollectionViewGroup(_group);
if (groupInfo != null)
{
// Adjust the row index to be relative to the DataGrid instead of the group
row = groupInfo.Slot - this.OwningDataGrid.RowGroupHeadersTable.GetIndexCount(0, groupInfo.Slot) + row + 1;
Debug.Assert(row >= 0, "Expected positive row.");
Debug.Assert(row < this.OwningDataGrid.DataConnection.Count, "Expected row smaller than this.OwningDataGrid.DataConnection.Count.");
int slot = this.OwningDataGrid.SlotFromRowIndex(row);
if (!this.OwningDataGrid.IsSlotVisible(slot))
{
object item = this.OwningDataGrid.DataConnection.GetDataItem(row);
this.OwningDataGrid.ScrollIntoView(item, this.OwningDataGrid.Columns[column]);
}
Debug.Assert(this.OwningDataGrid.IsSlotVisible(slot), "Expected OwningDataGrid.IsSlotVisible(slot) is true.");
DataGridRow dgr = this.OwningDataGrid.DisplayData.GetDisplayedElement(slot) as DataGridRow;
// the first cell is always the indentation filler cell if grouping is enabled, so skip it
Debug.Assert(column + 1 < dgr.Cells.Count, "Expected column + 1 smaller than dgr.Cells.Count.");
DataGridCell cell = dgr.Cells[column + 1];
AutomationPeer peer = CreatePeerForElement(cell);
if (peer != null)
{
return ProviderFromPeer(peer);
}
}
}
return null;
}
int IGridProvider.RowCount
{
get
{
return _group.GroupItems.Count /*ItemCount*/;
}
}
void IScrollItemProvider.ScrollIntoView()
{
EnsureEnabled();
if (this.OwningDataGrid != null)
{
DataGridRowGroupInfo groupInfo = this.OwningDataGrid.RowGroupInfoFromCollectionViewGroup(_group);
if (groupInfo != null)
{
this.OwningDataGrid.ScrollIntoView(groupInfo.CollectionViewGroup, null);
}
}
}
IRawElementProviderSimple[] ISelectionProvider.GetSelection()
{
EnsureEnabled();
if (this.OwningDataGrid != null &&
this.OwningDataGridPeer != null &&
this.OwningDataGrid.SelectedItems != null &&
_group.GroupItems.Count /*ItemCount*/ > 0)
{
DataGridRowGroupInfo groupInfo = this.OwningDataGrid.RowGroupInfoFromCollectionViewGroup(_group);
if (groupInfo != null)
{
// See which of the selected items are contained within this group
List<IRawElementProviderSimple> selectedProviders = new List<IRawElementProviderSimple>();
int startRowIndex = groupInfo.Slot - this.OwningDataGrid.RowGroupHeadersTable.GetIndexCount(0, groupInfo.Slot) + 1;
foreach (object item in this.OwningDataGrid.GetSelectionInclusive(startRowIndex, startRowIndex + _group.GroupItems.Count /*ItemCount*/ - 1))
{
DataGridItemAutomationPeer peer = this.OwningDataGridPeer.GetOrCreateItemPeer(item);
if (peer != null)
{
selectedProviders.Add(ProviderFromPeer(peer));
}
}
return selectedProviders.ToArray();
}
}
return null;
}
bool ISelectionProvider.CanSelectMultiple
{
get
{
return this.OwningDataGrid != null && this.OwningDataGrid.SelectionMode == DataGridSelectionMode.Extended;
}
}
bool ISelectionProvider.IsSelectionRequired
{
get
{
return false;
}
}
private void EnsureEnabled()
{
if (!_dataGridAutomationPeer.IsEnabled())
{
throw new ElementNotEnabledException();
}
}
}
}

Просмотреть файл

@ -0,0 +1,541 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Microsoft.Toolkit.Uwp.UI.Controls;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Windows.Foundation;
using Windows.UI.Xaml.Automation;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Automation.Provider;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for an item in a DataGrid
/// </summary>
public class DataGridItemAutomationPeer : FrameworkElementAutomationPeer,
IInvokeProvider, IScrollItemProvider, ISelectionItemProvider, ISelectionProvider
{
private object _item;
private AutomationPeer _dataGridAutomationPeer;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridItemAutomationPeer"/> class.
/// </summary>
public DataGridItemAutomationPeer(object item, DataGrid dataGrid)
: base(dataGrid)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
if (dataGrid == null)
{
throw new ArgumentNullException("dataGrid");
}
_item = item;
_dataGridAutomationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(dataGrid);
}
private DataGrid OwningDataGrid
{
get
{
DataGridAutomationPeer gridPeer = _dataGridAutomationPeer as DataGridAutomationPeer;
return gridPeer.Owner as DataGrid;
}
}
private DataGridRow OwningRow
{
get
{
int index = this.OwningDataGrid.DataConnection.IndexOf(_item);
int slot = this.OwningDataGrid.SlotFromRowIndex(index);
if (this.OwningDataGrid.IsSlotVisible(slot))
{
return this.OwningDataGrid.DisplayData.GetDisplayedElement(slot) as DataGridRow;
}
return null;
}
}
internal DataGridRowAutomationPeer OwningRowPeer
{
get
{
DataGridRowAutomationPeer rowPeer = null;
DataGridRow row = this.OwningRow;
if (row != null)
{
rowPeer = FrameworkElementAutomationPeer.CreatePeerForElement(row) as DataGridRowAutomationPeer;
}
return rowPeer;
}
}
/// <summary>
/// Returns the accelerator key for the UIElement that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>The accelerator key for the UIElement that is associated with this DataGridItemAutomationPeer.</returns>
protected override string GetAcceleratorKeyCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetAcceleratorKey() : string.Empty;
}
/// <summary>
/// Returns the access key for the UIElement that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>The access key for the UIElement that is associated with this DataGridItemAutomationPeer.</returns>
protected override string GetAccessKeyCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetAccessKey() : string.Empty;
}
/// <summary>
/// Returns the control type for the UIElement that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>The control type for the UIElement that is associated with this DataGridItemAutomationPeer.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.DataItem;
}
/// <summary>
/// Returns the string that uniquely identifies the FrameworkElement that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>The string that uniquely identifies the FrameworkElement that is associated with this DataGridItemAutomationPeer.</returns>
protected override string GetAutomationIdCore()
{
// The AutomationId should be unset for dynamic content.
return string.Empty;
}
/// <summary>
/// Returns the Rect that represents the bounding rectangle of the UIElement that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>The Rect that represents the bounding rectangle of the UIElement that is associated with this DataGridItemAutomationPeer.</returns>
protected override Rect GetBoundingRectangleCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetBoundingRectangle() : default(Rect);
}
/// <summary>
/// Returns the collection of elements that are represented in the UI Automation tree as immediate
/// child elements of the automation peer.
/// </summary>
/// <returns>The children elements.</returns>
protected override IList<AutomationPeer> GetChildrenCore()
{
if (this.OwningRowPeer != null)
{
this.OwningRowPeer.InvalidatePeer();
return this.OwningRowPeer.GetChildren();
}
return new List<AutomationPeer>();
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = (this.OwningRowPeer != null) ? this.OwningRowPeer.GetClassName() : string.Empty;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridItemAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Returns a Point that represents the clickable space that is on the UIElement that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>A Point that represents the clickable space that is on the UIElement that is associated with this DataGridItemAutomationPeer.</returns>
protected override Point GetClickablePointCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetClickablePoint() : new Point(double.NaN, double.NaN);
}
/// <summary>
/// Returns the string that describes the functionality of the control that is associated with the automation peer.
/// </summary>
/// <returns>The string that contains the help text.</returns>
protected override string GetHelpTextCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetHelpText() : string.Empty;
}
/// <summary>
/// Returns a string that communicates the visual status of the UIElement that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>A string that communicates the visual status of the UIElement that is associated with this DataGridItemAutomationPeer.</returns>
protected override string GetItemStatusCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetItemStatus() : string.Empty;
}
/// <summary>
/// Returns a human-readable string that contains the item type that the UIElement for this DataGridItemAutomationPeer represents.
/// </summary>
/// <returns>A human-readable string that contains the item type that the UIElement for this DataGridItemAutomationPeer represents.</returns>
protected override string GetItemTypeCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetItemType() : string.Empty;
}
/// <summary>
/// Returns the AutomationPeer for the element that is targeted to the UIElement for this DataGridItemAutomationPeer.
/// </summary>
/// <returns>The AutomationPeer for the element that is targeted to the UIElement for this DataGridItemAutomationPeer.</returns>
protected override AutomationPeer GetLabeledByCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetLabeledBy() : null;
}
/// <summary>
/// Returns a localized human readable string for this control type.
/// </summary>
/// <returns>A localized human readable string for this control type.</returns>
protected override string GetLocalizedControlTypeCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetLocalizedControlType() : string.Empty;
}
/// <summary>
/// Returns the string that describes the functionality of the control that is associated with this DataGridItemAutomationPeer.
/// </summary>
/// <returns>The string that contains the help text.</returns>
protected override string GetNameCore()
{
if (this.OwningRowPeer != null)
{
string owningRowPeerName = this.OwningRowPeer.GetName();
if (!string.IsNullOrEmpty(owningRowPeerName))
{
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridItemAutomationPeer.GetNameCore returns " + owningRowPeerName);
#endif
return owningRowPeerName;
}
}
string name = UI.Controls.Properties.Resources.DataGridRowAutomationPeer_ItemType;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridItemAutomationPeer.GetNameCore returns " + name);
#endif
return name;
}
/// <summary>
/// Returns a value indicating whether the element associated with this DataGridItemAutomationPeer is laid out in a specific direction.
/// </summary>
/// <returns>A value indicating whether the element associated with this DataGridItemAutomationPeer is laid out in a specific direction.</returns>
protected override AutomationOrientation GetOrientationCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.GetOrientation() : AutomationOrientation.None;
}
/// <summary>
/// Returns the control pattern that is associated with the specified Windows.UI.Xaml.Automation.Peers.PatternInterface.
/// </summary>
/// <param name="patternInterface">A value from the Windows.UI.Xaml.Automation.Peers.PatternInterface enumeration.</param>
/// <returns>The object that supports the specified pattern, or null if unsupported.</returns>
protected override object GetPatternCore(PatternInterface patternInterface)
{
switch (patternInterface)
{
case PatternInterface.Invoke:
{
if (!this.OwningDataGrid.IsReadOnly)
{
return this;
}
break;
}
case PatternInterface.ScrollItem:
{
if (this.OwningDataGrid.VerticalScrollBar != null &&
this.OwningDataGrid.VerticalScrollBar.Maximum > 0)
{
return this;
}
break;
}
case PatternInterface.Selection:
case PatternInterface.SelectionItem:
return this;
}
return base.GetPatternCore(patternInterface);
}
/// <summary>
/// Returns a value indicating whether the UIElement associated with this DataGridItemAutomationPeer can accept keyboard focus.
/// </summary>
/// <returns>True if the element is focusable by the keyboard; otherwise false.</returns>
protected override bool HasKeyboardFocusCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.HasKeyboardFocus() : false;
}
/// <summary>
/// Returns a value indicating whether the element associated with this DataGridItemAutomationPeer is an element that contains data that is presented to the user.
/// </summary>
/// <returns>True if the element contains data for the user to read; otherwise, false.</returns>
protected override bool IsContentElementCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.IsContentElement() : true;
}
/// <summary>
/// Gets or sets a value indicating whether the UIElement associated with this DataGridItemAutomationPeer
/// is understood by the end user as interactive.
/// </summary>
/// <returns>True if the UIElement associated with this DataGridItemAutomationPeer
/// is understood by the end user as interactive.</returns>
protected override bool IsControlElementCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.IsControlElement() : true;
}
/// <summary>
/// Gets a value indicating whether this DataGridItemAutomationPeer can receive and send events to the associated element.
/// </summary>
/// <returns>True if this DataGridItemAutomationPeer can receive and send events; otherwise, false.</returns>
protected override bool IsEnabledCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.IsEnabled() : false;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridItemAutomationPeer can accept keyboard focus.
/// </summary>
/// <returns>True if the UIElement associated with this DataGridItemAutomationPeer can accept keyboard focus.</returns>
protected override bool IsKeyboardFocusableCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.IsKeyboardFocusable() : false;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridItemAutomationPeer is off the screen.
/// </summary>
/// <returns>True if the element is not on the screen; otherwise, false.</returns>
protected override bool IsOffscreenCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.IsOffscreen() : true;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridItemAutomationPeer contains protected content.
/// </summary>
/// <returns>True if the UIElement contains protected content.</returns>
protected override bool IsPasswordCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.IsPassword() : false;
}
/// <summary>
/// Gets a value indicating whether the UIElement associated with this DataGridItemAutomationPeer is required to be completed on a form.
/// </summary>
/// <returns>True if the UIElement is required to be completed on a form.</returns>
protected override bool IsRequiredForFormCore()
{
return this.OwningRowPeer != null ? this.OwningRowPeer.IsRequiredForForm() : false;
}
/// <summary>
/// Sets the keyboard input focus on the UIElement associated with this DataGridItemAutomationPeer.
/// </summary>
protected override void SetFocusCore()
{
if (this.OwningRowPeer != null)
{
this.OwningRowPeer.SetFocus();
}
}
void IInvokeProvider.Invoke()
{
EnsureEnabled();
if (this.OwningRowPeer == null)
{
this.OwningDataGrid.ScrollIntoView(_item, null);
}
bool success = false;
if (this.OwningRow != null)
{
if (this.OwningDataGrid.WaitForLostFocus(() => { ((IInvokeProvider)this).Invoke(); }))
{
return;
}
if (this.OwningDataGrid.EditingRow == this.OwningRow)
{
success = this.OwningDataGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/);
}
else if (this.OwningDataGrid.UpdateSelectionAndCurrency(this.OwningDataGrid.CurrentColumnIndex, this.OwningRow.Slot, DataGridSelectionAction.SelectCurrent, false))
{
success = this.OwningDataGrid.BeginEdit();
}
}
}
void IScrollItemProvider.ScrollIntoView()
{
this.OwningDataGrid.ScrollIntoView(_item, null);
}
bool ISelectionItemProvider.IsSelected
{
get
{
return this.OwningDataGrid.SelectedItems.Contains(_item);
}
}
IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
{
get
{
return ProviderFromPeer(_dataGridAutomationPeer);
}
}
void ISelectionItemProvider.AddToSelection()
{
EnsureEnabled();
if (this.OwningDataGrid.SelectionMode == DataGridSelectionMode.Single &&
this.OwningDataGrid.SelectedItems.Count > 0 &&
!this.OwningDataGrid.SelectedItems.Contains(_item))
{
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
int index = this.OwningDataGrid.DataConnection.IndexOf(_item);
if (index != -1)
{
this.OwningDataGrid.SetRowSelection(this.OwningDataGrid.SlotFromRowIndex(index), true, false);
return;
}
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
void ISelectionItemProvider.RemoveFromSelection()
{
EnsureEnabled();
int index = this.OwningDataGrid.DataConnection.IndexOf(_item);
if (index != -1)
{
bool success = true;
if (this.OwningDataGrid.EditingRow != null && this.OwningDataGrid.EditingRow.Index == index)
{
if (this.OwningDataGrid.WaitForLostFocus(() => { ((ISelectionItemProvider)this).RemoveFromSelection(); }))
{
return;
}
success = this.OwningDataGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/);
}
if (success)
{
this.OwningDataGrid.SetRowSelection(this.OwningDataGrid.SlotFromRowIndex(index), false, false);
return;
}
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
void ISelectionItemProvider.Select()
{
EnsureEnabled();
int index = this.OwningDataGrid.DataConnection.IndexOf(_item);
if (index != -1)
{
bool success = true;
if (this.OwningDataGrid.EditingRow != null && this.OwningDataGrid.EditingRow.Index != index)
{
if (this.OwningDataGrid.WaitForLostFocus(() => { ((ISelectionItemProvider)this).Select(); }))
{
return;
}
success = this.OwningDataGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/);
}
if (success)
{
// Clear all the other selected items and select this one
int slot = this.OwningDataGrid.SlotFromRowIndex(index);
this.OwningDataGrid.UpdateSelectionAndCurrency(this.OwningDataGrid.CurrentColumnIndex, slot, DataGridSelectionAction.SelectCurrent, false);
return;
}
throw DataGridError.DataGridAutomationPeer.OperationCannotBePerformed();
}
}
bool ISelectionProvider.CanSelectMultiple
{
get
{
return false;
}
}
bool ISelectionProvider.IsSelectionRequired
{
get
{
return false;
}
}
IRawElementProviderSimple[] ISelectionProvider.GetSelection()
{
if (this.OwningRow != null &&
this.OwningDataGrid.IsSlotVisible(this.OwningRow.Slot) &&
this.OwningDataGrid.CurrentSlot == this.OwningRow.Slot)
{
DataGridCell cell = this.OwningRow.Cells[this.OwningRow.OwningGrid.CurrentColumnIndex];
AutomationPeer peer = FrameworkElementAutomationPeer.CreatePeerForElement(cell);
if (peer != null)
{
return new IRawElementProviderSimple[] { ProviderFromPeer(peer) };
}
}
return null;
}
private void EnsureEnabled()
{
if (!_dataGridAutomationPeer.IsEnabled())
{
throw new ElementNotEnabledException();
}
}
}
}

Просмотреть файл

@ -0,0 +1,62 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.UI.Xaml.Automation.Peers;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for DataGridRow
/// </summary>
public class DataGridRowAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowAutomationPeer"/> class.
/// </summary>
/// <param name="owner">DataGridRow</param>
public DataGridRowAutomationPeer(DataGridRow owner)
: base(owner)
{
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.DataItem;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridRowAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Returns a human-readable string that contains the item type that the UIElement for this DataGridRowAutomationPeer represents.
/// </summary>
/// <returns>A human-readable string that contains the item type that the UIElement for this DataGridRowAutomationPeer represents.</returns>
protected override string GetItemTypeCore()
{
string itemType = base.GetItemTypeCore();
if (!string.IsNullOrEmpty(itemType))
{
return itemType;
}
return UI.Controls.Properties.Resources.DataGridRowAutomationPeer_ItemType;
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.UI.Xaml.Automation.Peers;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for DataGridRowGroupHeader
/// </summary>
public class DataGridRowGroupHeaderAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowGroupHeaderAutomationPeer"/> class.
/// </summary>
/// <param name="owner">DataGridRowGroupHeader</param>
public DataGridRowGroupHeaderAutomationPeer(DataGridRowGroupHeader owner)
: base(owner)
{
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Group;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridRowGroupHeaderAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
}
}

Просмотреть файл

@ -0,0 +1,73 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Windows.UI.Xaml.Automation.Peers;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for DataGridRowHeader
/// </summary>
public class DataGridRowHeaderAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowHeaderAutomationPeer"/> class.
/// </summary>
/// <param name="owner">DataGridRowHeader</param>
public DataGridRowHeaderAutomationPeer(DataGridRowHeader owner)
: base(owner)
{
}
private DataGridRowHeader OwningHeader
{
get
{
return (DataGridRowHeader)Owner;
}
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.HeaderItem;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridRowHeaderAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Gets the name of the element.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetNameCore()
{
return (this.OwningHeader.Content as string) ?? base.GetNameCore();
}
/// <summary>
/// Gets a value that specifies whether the element is a content element.
/// </summary>
/// <returns>True if the element is a content element; otherwise false</returns>
protected override bool IsContentElementCore()
{
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,93 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Windows.UI.Xaml.Automation.Peers;
namespace Microsoft.Toolkit.Uwp.UI.Automation.Peers
{
/// <summary>
/// AutomationPeer for the <see cref="DataGridRowsPresenter"/> class.
/// </summary>
public class DataGridRowsPresenterAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowsPresenterAutomationPeer"/> class.
/// </summary>
/// <param name="owner">Owning DataGridRowsPresenter</param>
public DataGridRowsPresenterAutomationPeer(DataGridRowsPresenter owner)
: base(owner)
{
}
private DataGridAutomationPeer GridPeer
{
get
{
if (this.OwningRowsPresenter.OwningGrid != null)
{
return CreatePeerForElement(this.OwningRowsPresenter.OwningGrid) as DataGridAutomationPeer;
}
return null;
}
}
private DataGridRowsPresenter OwningRowsPresenter
{
get
{
return Owner as DataGridRowsPresenter;
}
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Custom;
}
/// <summary>
/// Gets the collection of elements that are represented in the UI Automation tree as immediate
/// child elements of the automation peer.
/// </summary>
/// <returns>The children elements.</returns>
protected override IList<AutomationPeer> GetChildrenCore()
{
if (this.OwningRowsPresenter.OwningGrid == null)
{
return new List<AutomationPeer>();
}
return this.GridPeer.GetChildPeers();
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("DataGridRowsPresenterAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Gets a value that specifies whether the element is a content element.
/// </summary>
/// <returns>True if the element is a content element; otherwise false</returns>
protected override bool IsContentElementCore()
{
return false;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,969 @@
<!--
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
-->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:localprimitives="using:Microsoft.Toolkit.Uwp.UI.Controls.Primitives">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="InvalidBrush" Color="#FFFF00"/>
<SolidColorBrush x:Key="FillerGridLinesBrush" Color="Transparent"/>
<StaticResource x:Key="ScrollBarsSeparatorBackground" ResourceKey="SystemControlPageBackgroundChromeLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderForegroundBrush" ResourceKey="SystemControlForegroundBaseMediumBrush"/>
<StaticResource x:Key="DataGridColumnHeaderBackgroundColor" ResourceKey="SystemAltHighColor"/>
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{StaticResource DataGridColumnHeaderBackgroundColor}"/>
<StaticResource x:Key="DataGridColumnHeaderHoveredBackgroundColor" ResourceKey="SystemListLowColor"/>
<StaticResource x:Key="DataGridColumnHeaderPressedBackgroundColor" ResourceKey="SystemListMediumColor"/>
<StaticResource x:Key="DataGridColumnHeaderDraggedBackgroundBrush" ResourceKey="SystemControlBackgroundChromeMediumLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderPointerOverBrush" ResourceKey="SystemControlHighlightListLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderPressedBrush" ResourceKey="SystemControlHighlightListMediumBrush"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="InvalidBrush" Color="#FFFF00"/>
<SolidColorBrush x:Key="FillerGridLinesBrush" Color="Transparent"/>
<StaticResource x:Key="ScrollBarsSeparatorBackground" ResourceKey="SystemControlPageBackgroundChromeLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderForegroundBrush" ResourceKey="SystemControlForegroundBaseMediumBrush"/>
<StaticResource x:Key="DataGridColumnHeaderBackgroundColor" ResourceKey="SystemAltHighColor"/>
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{StaticResource DataGridColumnHeaderBackgroundColor}"/>
<StaticResource x:Key="DataGridColumnHeaderHoveredBackgroundColor" ResourceKey="SystemListLowColor"/>
<StaticResource x:Key="DataGridColumnHeaderPressedBackgroundColor" ResourceKey="SystemListMediumColor"/>
<StaticResource x:Key="DataGridColumnHeaderDraggedBackgroundBrush" ResourceKey="SystemControlBackgroundChromeMediumLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderPointerOverBrush" ResourceKey="SystemControlHighlightListLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderPressedBrush" ResourceKey="SystemControlHighlightListMediumBrush"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="InvalidBrush" Color="#C50500"/>
<SolidColorBrush x:Key="FillerGridLinesBrush" Color="Transparent"/>
<SolidColorBrush x:Key="ScrollBarsSeparatorBackground" Color="{StaticResource SystemChromeMediumColor}" Opacity="0.9"/>
<StaticResource x:Key="DataGridColumnHeaderForegroundBrush" ResourceKey="SystemControlForegroundBaseMediumBrush"/>
<StaticResource x:Key="DataGridColumnHeaderBackgroundColor" ResourceKey="SystemAltHighColor"/>
<SolidColorBrush x:Key="DataGridColumnHeaderBackgroundBrush" Color="{StaticResource DataGridColumnHeaderBackgroundColor}"/>
<StaticResource x:Key="DataGridColumnHeaderHoveredBackgroundColor" ResourceKey="SystemListLowColor"/>
<StaticResource x:Key="DataGridColumnHeaderPressedBackgroundColor" ResourceKey="SystemListMediumColor"/>
<StaticResource x:Key="DataGridColumnHeaderDraggedBackgroundBrush" ResourceKey="SystemControlBackgroundChromeMediumLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderPointerOverBrush" ResourceKey="SystemControlHighlightListLowBrush"/>
<StaticResource x:Key="DataGridColumnHeaderPressedBrush" ResourceKey="SystemControlHighlightListMediumBrush"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<SolidColorBrush x:Key="SystemControlGridLinesBaseMediumLowBrush" Color="{StaticResource SystemBaseMediumLowColor}" Opacity="0.4"/>
<SolidColorBrush x:Key="SystemControlRowGroupHeaderBackgroundMediumBrush" Color="{StaticResource SystemChromeMediumColor}"/>
<SolidColorBrush x:Key="DataGridCurrencyVisualPrimaryBrush" Color="Transparent"/>
<x:String x:Key="SortIconAscending">&#xE74A;</x:String>
<x:String x:Key="SortIconDescending">&#xE74B;</x:String>
<x:String x:Key="RowGroupHeaderIconClosed">&#xE0E3;</x:String>
<x:String x:Key="RowGroupHeaderIconOpened">&#xE0E5;</x:String>
<x:String x:Key="ScrollBarsSeparatorExpandBeginTime">00:00:00.40</x:String>
<x:String x:Key="ScrollBarsSeparatorExpandDuration">00:00:00.1</x:String>
<x:String x:Key="ScrollBarsSeparatorContractBeginTime">00:00:02.00</x:String>
<x:String x:Key="ScrollBarsSeparatorContractDelay">00:00:02</x:String>
<x:String x:Key="ScrollBarsSeparatorContractDuration">00:00:00.1</x:String>
<x:String x:Key="ScrollBarsSeparatorContractFinalKeyframe">00:00:02.1</x:String>
<x:String x:Key="ScrollBarsSeparatorNoTouchDuration">00:00:00.5</x:String>
<x:Double x:Key="ListAccentLowOpacity">0.6</x:Double>
<x:Double x:Key="ListAccentMediumOpacity">0.8</x:Double>
<StaticResource x:Key="GridLinesBrush" ResourceKey="SystemControlGridLinesBaseMediumLowBrush"/>
<StaticResource x:Key="DataGridDetailsPresenterBackgroundBrush" ResourceKey="SystemControlBackgroundChromeMediumLowBrush"/>
<StaticResource x:Key="DataGridFillerColumnGridLinesBrush" ResourceKey="FillerGridLinesBrush"/>
<StaticResource x:Key="DataGridRowSelectedBackgroundColor" ResourceKey="SystemAccentColor"/>
<StaticResource x:Key="DataGridRowSelectedBackgroundOpacity" ResourceKey="ListAccentLowOpacity"/>
<StaticResource x:Key="DataGridRowSelectedHoveredBackgroundColor" ResourceKey="SystemAccentColor"/>
<StaticResource x:Key="DataGridRowSelectedHoveredBackgroundOpacity" ResourceKey="ListAccentMediumOpacity"/>
<StaticResource x:Key="DataGridRowSelectedUnfocusedBackgroundColor" ResourceKey="SystemAccentColor"/>
<StaticResource x:Key="DataGridRowSelectedUnfocusedBackgroundOpacity" ResourceKey="ListAccentLowOpacity"/>
<StaticResource x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundColor" ResourceKey="SystemAccentColor"/>
<StaticResource x:Key="DataGridRowSelectedHoveredUnfocusedBackgroundOpacity" ResourceKey="ListAccentMediumOpacity"/>
<StaticResource x:Key="DataGridRowHeaderForegroundBrush" ResourceKey="SystemControlForegroundBaseMediumBrush"/>
<StaticResource x:Key="DataGridRowHeaderBackgroundBrush" ResourceKey="SystemControlBackgroundAltHighBrush"/>
<StaticResource x:Key="DataGridRowGroupHeaderBackgroundBrush" ResourceKey="SystemControlBackgroundChromeMediumBrush"/>
<StaticResource x:Key="DataGridRowGroupHeaderHoveredBackgroundBrush" ResourceKey="SystemControlBackgroundListLowBrush"/>
<StaticResource x:Key="DataGridRowGroupHeaderPressedBackgroundBrush" ResourceKey="SystemControlBackgroundListMediumBrush"/>
<StaticResource x:Key="DataGridRowGroupHeaderForegroundBrush" ResourceKey="SystemControlForegroundBaseHighBrush"/>
<StaticResource x:Key="DataGridRowInvalidBrush" ResourceKey="InvalidBrush"/>
<StaticResource x:Key="DataGridCellBackgroundBrush" ResourceKey="SystemControlTransparentBrush"/>
<StaticResource x:Key="DataGridCellFocusVisualPrimaryBrush" ResourceKey="SystemControlFocusVisualPrimaryBrush"/>
<StaticResource x:Key="DataGridCellFocusVisualSecondaryBrush" ResourceKey="SystemControlFocusVisualSecondaryBrush"/>
<StaticResource x:Key="DataGridCellInvalidBrush" ResourceKey="InvalidBrush"/>
<Style TargetType="local:DataGrid">
<Setter Property="DragIndicatorStyle">
<Setter.Value>
<Style TargetType="ContentControl">
<Setter Property="Foreground" Value="{ThemeResource DataGridColumnHeaderForegroundBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid Background="{ThemeResource DataGridColumnHeaderDraggedBackgroundBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SortStates">
<VisualState x:Name="Unsorted"/>
<VisualState x:Name="SortAscending">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SortIcon" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
</Storyboard>
</VisualState>
<VisualState x:Name="SortDescending">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SortIcon" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
</Storyboard>
<VisualState.Setters>
<Setter Target="SortIcon.Glyph" Value="{ThemeResource SortIconDescending}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MinWidth="32" Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentPresenter Content="{TemplateBinding Content}"/>
<FontIcon x:Name="SortIcon" Grid.Column="1" FontFamily="{ThemeResource SymbolThemeFontFamily}" Glyph="{ThemeResource SortIconAscending}"
FontSize="12" Foreground="{ThemeResource DataGridColumnHeaderForegroundBrush}"
HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="DropLocationIndicatorStyle">
<Setter.Value>
<Style TargetType="Control">
<Setter Property="Background" Value="#FF3F4346"/>
<Setter Property="Width" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Control">
<Rectangle Fill="{TemplateBinding Background}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="HorizontalGridLinesBrush" Value="{ThemeResource GridLinesBrush}"/>
<Setter Property="UseSystemFocusVisuals" Value="False"/>
<Setter Property="IsTabStop" Value="True"/>
<Setter Property="VerticalGridLinesBrush" Value="{ThemeResource GridLinesBrush}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DataGrid">
<Grid x:Name="Root" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Disabled">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ScrollBarsStates">
<VisualStateGroup.Transitions>
<VisualTransition From="MouseIndicator" To="NoIndicator">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorContractDelay}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorContractDelay}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="MouseIndicatorFull" To="NoIndicator">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorContractDelay}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorContractDelay}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="MouseIndicatorFull" To="MouseIndicator">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorContractDelay}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorContractDelay}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="TouchIndicator" To="NoIndicator">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorNoTouchDuration}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="{ThemeResource ScrollBarsSeparatorNoTouchDuration}">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="NoIndicator"/>
<VisualState x:Name="TouchIndicator">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseIndicator">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseIndicatorFull">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ScrollBarsSeparatorStates">
<VisualStateGroup.Transitions>
<VisualTransition From="SeparatorExpanded" To="SeparatorCollapsed">
<Storyboard>
<DoubleAnimation Duration="{ThemeResource ScrollBarsSeparatorContractDuration}"
BeginTime="{ThemeResource ScrollBarsSeparatorContractBeginTime}"
Storyboard.TargetName="BottomRightCorner"
Storyboard.TargetProperty="Opacity"
To="0"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="SeparatorCollapsed"/>
<VisualState x:Name="SeparatorExpanded">
<Storyboard>
<DoubleAnimation Duration="{ThemeResource ScrollBarsSeparatorExpandDuration}"
BeginTime="{ThemeResource ScrollBarsSeparatorExpandBeginTime}"
Storyboard.TargetName="BottomRightCorner"
Storyboard.TargetProperty="Opacity"
To="1"/>
</Storyboard>
</VisualState>
<VisualState x:Name="SeparatorExpandedWithoutAnimation">
<Storyboard>
<DoubleAnimation Duration="0"
BeginTime="{ThemeResource ScrollBarsSeparatorExpandBeginTime}"
Storyboard.TargetName="BottomRightCorner"
Storyboard.TargetProperty="Opacity"
To="1"/>
</Storyboard>
</VisualState>
<VisualState x:Name="SeparatorCollapsedWithoutAnimation" >
<Storyboard>
<DoubleAnimation Duration="0"
BeginTime="{ThemeResource ScrollBarsSeparatorContractBeginTime}"
Storyboard.TargetName="BottomRightCorner"
Storyboard.TargetProperty="Opacity"
To="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="{TemplateBinding Background}">
<Grid.Resources>
<!--Start: TopLeftHeaderTemplate-->
<ControlTemplate x:Key="TopLeftHeaderTemplate" TargetType="localprimitives:DataGridColumnHeader">
<Grid x:Name="TopLeftHeaderRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border BorderThickness="0,0,1,0" BorderBrush="{ThemeResource GridLinesBrush}" Grid.RowSpan="2"/>
<Rectangle VerticalAlignment="Bottom" Width="Auto" StrokeThickness="1" Height="1" Fill="{ThemeResource GridLinesBrush}" Grid.RowSpan="2"/>
</Grid>
</ControlTemplate>
<!--End: TopLeftHeaderTemplate-->
<!--Start: TopRightHeaderTemplate-->
<ControlTemplate x:Key="TopRightHeaderTemplate" TargetType="localprimitives:DataGridColumnHeader">
<Grid x:Name="RootElement"/>
</ControlTemplate>
<!--End: TopRightHeaderTemplate-->
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<!-- For ValidationSummary addition
<RowDefinition Height="Auto"/>
-->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<localprimitives:DataGridColumnHeader x:Name="TopLeftCornerHeader" Template="{StaticResource TopLeftHeaderTemplate}"/>
<localprimitives:DataGridColumnHeadersPresenter x:Name="ColumnHeadersPresenter" Grid.Column="1" Grid.ColumnSpan="2"
AutomationProperties.AccessibilityView="Raw"/>
<!-- Use TopRightCornerHeader when ColumnHeadersPresenter's Grid.ColumnSpan is 1 and the vertical ScrollBar does not paint on top of the cells -->
<!--<localprimitives:DataGridColumnHeader x:Name="TopRightCornerHeader" Grid.Column="2" Template="{StaticResource TopRightHeaderTemplate}"/>-->
<Rectangle x:Name="ColumnHeadersAndRowsSeparator" Grid.ColumnSpan="3" VerticalAlignment="Bottom" Width="Auto" StrokeThickness="1" Height="1" Fill="{ThemeResource GridLinesBrush}"/>
<localprimitives:DataGridRowsPresenter x:Name="RowsPresenter" Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="2"
AutomationProperties.AccessibilityView="Raw"/>
<Rectangle x:Name="BottomRightCorner" Fill="{ThemeResource ScrollBarsSeparatorBackground}" Opacity="0" Grid.Row="2" Grid.Column="2"/>
<!-- Use BottomLeftCorner when RowsPresenter's Grid.RowSpan is 1 and the horizontal ScrollBar does not paint on top of the cells -->
<!--<Rectangle x:Name="BottomLeftCorner" Fill="#FFE9EEF4" Grid.Row="2" Grid.ColumnSpan="2"/>-->
<ScrollBar x:Name="VerticalScrollBar" Orientation="Vertical" Visibility="Collapsed" Grid.Column="2" Grid.Row="1"/>
<Grid Grid.Column="1" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="FrozenColumnScrollBarSpacer"/>
<ScrollBar x:Name="HorizontalScrollBar" Grid.Column="1" Orientation="Horizontal" Visibility="Collapsed"/>
</Grid>
<!--<dataInput:ValidationSummary x:Name="ValidationSummary" Grid.Row="3" Grid.ColumnSpan="3" MaxHeight="90"/>-->
</Grid>
<Border x:Name="DisabledVisualElement" IsHitTestVisible="False" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" CornerRadius="2" Background="#8CFFFFFF" Opacity="0"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:DataGridCell">
<Setter Property="Background" Value="{ThemeResource DataGridCellBackgroundBrush}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="MinHeight" Value="32"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DataGridCell">
<Grid x:Name="CellRoot" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CurrentStates">
<VisualState x:Name="Regular"/>
<VisualState x:Name="Current">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CurrencyVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="CurrentWithFocus">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CurrencyVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid"/>
<VisualState x:Name="Invalid">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="InvalidVisualElement" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="CurrencyVisual" Stroke="{ThemeResource DataGridCurrencyVisualPrimaryBrush}" StrokeThickness="1" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False" Opacity="0"/>
<Grid x:Name="FocusVisual" IsHitTestVisible="False" Opacity="0">
<Rectangle Stroke="{ThemeResource DataGridCellFocusVisualPrimaryBrush}" StrokeThickness="2" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False"/>
<Rectangle Stroke="{ThemeResource DataGridCellFocusVisualSecondaryBrush}" StrokeThickness="1" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False" Margin="2"/>
</Grid>
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
<Rectangle x:Name="InvalidVisualElement" IsHitTestVisible="False" StrokeThickness="1" Stroke="{ThemeResource DataGridCellInvalidBrush}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0"/>
<Rectangle x:Name="RightGridLine" Grid.Column="1" VerticalAlignment="Stretch" Width="1" Fill="{ThemeResource DataGridFillerColumnGridLinesBrush}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="localprimitives:DataGridColumnHeader">
<Setter Property="Foreground" Value="{ThemeResource DataGridColumnHeaderForegroundBrush}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="SeparatorBrush" Value="{ThemeResource GridLinesBrush}"/>
<Setter Property="Padding" Value="12,0,0,0"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="MinHeight" Value="32"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="localprimitives:DataGridColumnHeader">
<Grid x:Name="ColumnHeaderRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridColumnHeaderBackgroundColor}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridColumnHeaderHoveredBackgroundColor}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridColumnHeaderPressedBackgroundColor}"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="Focused">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="SortStates">
<VisualState x:Name="Unsorted"/>
<VisualState x:Name="SortAscending">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SortIcon" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
</Storyboard>
</VisualState>
<VisualState x:Name="SortDescending">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SortIcon" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
</Storyboard>
<VisualState.Setters>
<Setter Target="SortIcon.Glyph" Value="{ThemeResource SortIconDescending}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="BackgroundRectangle" Stretch="Fill" Fill="{ThemeResource DataGridColumnHeaderBackgroundBrush}" Grid.ColumnSpan="2"/>
<Grid HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MinWidth="32" Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<FontIcon Grid.Column="1" x:Name="SortIcon" FontFamily="{ThemeResource SymbolThemeFontFamily}" Glyph="{ThemeResource SortIconAscending}" FontSize="12"
Foreground="{ThemeResource DataGridColumnHeaderForegroundBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0"/>
</Grid>
<Rectangle x:Name="VerticalSeparator" Grid.Column="1" Width="1" VerticalAlignment="Stretch" Fill="{TemplateBinding SeparatorBrush}" Visibility="{TemplateBinding SeparatorVisibility}"/>
<Grid x:Name="FocusVisual" IsHitTestVisible="False" Opacity="0">
<Rectangle x:Name="FocusVisualPrimary" Stroke="{ThemeResource DataGridCellFocusVisualPrimaryBrush}" StrokeThickness="2" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False"/>
<Rectangle x:Name="FocusVisualSecondary" Stroke="{ThemeResource DataGridCellFocusVisualSecondaryBrush}" StrokeThickness="1" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False" Margin="2"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:DataGridRow">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DataGridRow">
<localprimitives:DataGridFrozenGrid x:Name="RowRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="NormalAlternatingRow"/>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource SystemListLowColor}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="NormalSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverUnfocusedSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="UnfocusedSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedUnfocusedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedUnfocusedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid"/>
<VisualState x:Name="Invalid">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="InvalidVisualElement" Storyboard.TargetProperty="Opacity" Duration="0" To="0.4"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="BackgroundRectangle" Grid.ColumnSpan="2" Fill="{ThemeResource SystemControlTransparentBrush}"/>
<Rectangle x:Name="InvalidVisualElement" Grid.ColumnSpan="2" Opacity="0" Fill="{ThemeResource DataGridRowInvalidBrush}"/>
<localprimitives:DataGridRowHeader x:Name="RowHeader" Grid.RowSpan="3" localprimitives:DataGridFrozenGrid.IsFrozen="True"/>
<localprimitives:DataGridCellsPresenter x:Name="CellsPresenter" Grid.Column="1"
localprimitives:DataGridFrozenGrid.IsFrozen="True" MinHeight="32"
AutomationProperties.AccessibilityView="Raw"/>
<localprimitives:DataGridDetailsPresenter x:Name="DetailsPresenter" Grid.Row="1" Grid.Column="1"
Background="{ThemeResource DataGridDetailsPresenterBackgroundBrush}"
AutomationProperties.AccessibilityView="Raw"/>
<Rectangle x:Name="BottomGridLine" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Stretch" Height="1"/>
</localprimitives:DataGridFrozenGrid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="localprimitives:DataGridRowHeader">
<Setter Property="Background" Value="{ThemeResource DataGridRowHeaderBackgroundBrush}"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="SeparatorBrush" Value="{ThemeResource GridLinesBrush}"/>
<Setter Property="SeparatorVisibility" Value="Collapsed"/>
<Setter Property="AutomationProperties.AccessibilityView" Value="Raw"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="localprimitives:DataGridRowHeader">
<Grid x:Name="RowHeaderRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="NormalCurrentRow">
<!-- For optional row currency and editing glyphs
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
<DoubleAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
</Storyboard>
-->
</VisualState>
<VisualState x:Name="NormalSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedBackgroundOpacity}"/>
<!-- For optional row currency and editing glyphs
<DoubleAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
<DoubleAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
-->
</Storyboard>
</VisualState>
<VisualState x:Name="NormalEditingRow">
<!-- For optional row currency and editing glyphs
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
<DoubleAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
</Storyboard>
-->
</VisualState>
<VisualState x:Name="NormalCurrentRowSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource SystemListLowColor}"/>
<!-- For optional row currency and editing glyphs
<DoubleAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
<DoubleAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
-->
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverCurrentRow">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource SystemListLowColor}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverUnfocusedEditingRow">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource SystemListLowColor}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverEditingRow">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource SystemListLowColor}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverUnfocusedSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverUnfocusedCurrentRowSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverCurrentRowSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredBackgroundOpacity}"/>
<!-- For optional row currency and editing glyphs
<DoubleAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="1"/>
<DoubleAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
-->
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOverSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedHoveredBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="UnfocusedEditingRow">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedBackgroundColor}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="UnfocusedSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedUnfocusedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedUnfocusedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
<VisualState x:Name="UnfocusedCurrentRowSelected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Duration="0" To="{ThemeResource DataGridRowSelectedUnfocusedBackgroundColor}"/>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="{ThemeResource DataGridRowSelectedUnfocusedBackgroundOpacity}"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="RowValid"/>
<VisualState x:Name="RowInvalid">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BackgroundRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="0"/>
<DoubleAnimation Storyboard.TargetName="RowInvalidVisualElement" Storyboard.TargetProperty="Opacity" Duration="0" To="0.4"/>
<!-- For optional row currency and editing glyphs
<ColorAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Duration="0" To="#FFDC000C"/>
<ColorAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Duration="0" To="#FFDC000C"/>
<ColorAnimation Storyboard.TargetName="CurrentRowGlyph" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Duration="0" To="#FFDC000C"/>
<ColorAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Duration="0" To="#FFDC000C"/>
<ColorAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Duration="0" To="#FFDC000C"/>
<ColorAnimation Storyboard.TargetName="EditingRowGlyph" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Duration="0" To="#FFDC000C"/>
-->
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="{TemplateBinding SeparatorBrush}" BorderThickness="0,0,1,0" Grid.RowSpan="3" Grid.ColumnSpan="2">
<Grid Background="{TemplateBinding Background}">
<Rectangle x:Name="RowInvalidVisualElement" Stretch="Fill" Fill="{ThemeResource DataGridRowInvalidBrush}" Opacity="0"/>
<Rectangle x:Name="BackgroundRectangle" Stretch="Fill" Fill="Transparent"/>
</Grid>
</Border>
<Rectangle x:Name="HorizontalSeparator" Grid.ColumnSpan="2" Grid.Row="2" Height="1" Margin="1,0,1,0" HorizontalAlignment="Stretch" Fill="{TemplateBinding SeparatorBrush}" Visibility="{TemplateBinding SeparatorVisibility}"/>
<ContentPresenter Content="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center" Grid.Column="1" Grid.RowSpan="2"/>
<!-- For optional row currency glyph
<Path x:Name="CurrentRowGlyph" VerticalAlignment="Center" HorizontalAlignment="Center" Width="6" Height="10" Margin="8,0,8,0" Grid.RowSpan="2" Stretch="Fill" Opacity="0" Data="F1 M 511.047,352.682L 511.047,342.252L 517.145,347.467L 511.047,352.682 Z ">
<Path.Fill>
<LinearGradientBrush StartPoint="0,-.15" EndPoint="0,1.75">
<GradientStop Color="#FF84E3FF" Offset="0"/>
<GradientStop Color="#FF6ABFD8" Offset="0.5"/>
<GradientStop Color="#FF5297AB" Offset="1"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
-->
<!-- For optional row editing glyph
<Path x:Name="EditingRowGlyph" VerticalAlignment="Center" HorizontalAlignment="Center" Width="6" Height="10" Margin="8,0,8,0" Grid.RowSpan="2" Stretch="Fill" Opacity="0" Data="F1 M 511.047,352.682L 511.047,342.252L 517.145,347.467L 511.047,352.682 Z ">
<Path.Fill>
<LinearGradientBrush StartPoint="0,-.15" EndPoint="0,1.75">
<GradientStop Color="#FF84E3FF" Offset="0"/>
<GradientStop Color="#FF6ABFD8" Offset="0.5"/>
<GradientStop Color="#FF5297AB" Offset="1"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
-->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:DataGridRowGroupHeader">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Foreground" Value="{ThemeResource DataGridRowGroupHeaderForegroundBrush}"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="MinHeight" Value="32"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DataGridRowGroupHeader">
<localprimitives:DataGridFrozenGrid x:Name="RowGroupHeaderRoot" Background="{ThemeResource DataGridRowGroupHeaderBackgroundBrush}" MinHeight="{TemplateBinding MinHeight}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="RowGroupHeaderRoot.Background" Value="{ThemeResource DataGridRowGroupHeaderHoveredBackgroundBrush}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="RowGroupHeaderRoot.Background" Value="{ThemeResource DataGridRowGroupHeaderPressedBackgroundBrush}"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CurrentStates">
<VisualState x:Name="Regular"/>
<VisualState x:Name="Current">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CurrencyVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Opacity" To="0" Duration="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="CurrentWithFocus">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="CurrencyVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<localprimitives:DataGridFrozenGrid.Resources>
<ControlTemplate x:Key="ToggleButtonTemplate" TargetType="ToggleButton">
<Grid Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Target="Arrow.Glyph" Value="{ThemeResource RowGroupHeaderIconClosed}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="Arrow.Glyph" Value="{ThemeResource RowGroupHeaderIconClosed}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="Arrow.Glyph" Value="{ThemeResource RowGroupHeaderIconClosed}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Target="Arrow.Glyph" Value="{ThemeResource RowGroupHeaderIconClosed}"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Checked"/>
<VisualState x:Name="CheckedPointerOver"/>
<VisualState x:Name="CheckedPressed"/>
<VisualState x:Name="CheckedDisabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<FontIcon x:Name="Arrow" FontFamily="{ThemeResource SymbolThemeFontFamily}" Glyph="{ThemeResource RowGroupHeaderIconOpened}"
FontSize="12" Foreground="{ThemeResource DataGridRowGroupHeaderForegroundBrush}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</localprimitives:DataGridFrozenGrid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Rectangle x:Name="IndentSpacer" Grid.Column="1"/>
<ToggleButton x:Name="ExpanderButton" Grid.Column="2" Height="12" Width="12" Template="{StaticResource ToggleButtonTemplate}"
IsTabStop="False" Margin="12,0,0,0" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}"/>
<StackPanel Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Center" Margin="12,0,0,0">
<TextBlock x:Name="PropertyNameElement" Margin="4,0,0,0" Visibility="{TemplateBinding PropertyNameVisibility}" Style="{ThemeResource BodyTextBlockStyle}" Foreground="{TemplateBinding Foreground}"/>
<TextBlock x:Name="PropertyValueElement" Margin="4,0,0,0" Style="{ThemeResource BodyTextBlockStyle}" Foreground="{TemplateBinding Foreground}"/>
<TextBlock x:Name="ItemCountElement" Margin="4,0,0,0" Visibility="{TemplateBinding ItemCountVisibility}" Style="{ThemeResource BodyTextBlockStyle}" Foreground="{TemplateBinding Foreground}"/>
</StackPanel>
<Rectangle x:Name="CurrencyVisual" Grid.ColumnSpan="5"
Stroke="{ThemeResource DataGridCurrencyVisualPrimaryBrush}" StrokeThickness="1" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False" Opacity="0"/>
<Grid x:Name="FocusVisual" Grid.ColumnSpan="5" IsHitTestVisible="False" Opacity="0">
<Rectangle Stroke="{ThemeResource DataGridCellFocusVisualPrimaryBrush}" StrokeThickness="2" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False"/>
<Rectangle Stroke="{ThemeResource DataGridCellFocusVisualSecondaryBrush}" StrokeThickness="1" Fill="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="False" Margin="2"/>
</Grid>
<localprimitives:DataGridRowHeader x:Name="RowHeader" Grid.RowSpan="2" localprimitives:DataGridFrozenGrid.IsFrozen="True"/>
<Rectangle x:Name="BottomGridLine" Grid.ColumnSpan="5" Height="1" Grid.Row="1"/>
</localprimitives:DataGridFrozenGrid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -0,0 +1,61 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ComponentModel;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides data for the <see cref="E:Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.AutoGeneratingColumn" /> event.
/// </summary>
public class DataGridAutoGeneratingColumnEventArgs : CancelEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridAutoGeneratingColumnEventArgs"/> class.
/// </summary>
/// <param name="propertyName">
/// The name of the property bound to the generated column.
/// </param>
/// <param name="propertyType">
/// The <see cref="T:System.Type" /> of the property bound to the generated column.
/// </param>
/// <param name="column">
/// The generated column.
/// </param>
public DataGridAutoGeneratingColumnEventArgs(string propertyName, Type propertyType, DataGridColumn column)
{
this.Column = column;
this.PropertyName = propertyName;
this.PropertyType = propertyType;
}
/// <summary>
/// Gets or sets the generated column.
/// </summary>
public DataGridColumn Column
{
get;
set;
}
/// <summary>
/// Gets the name of the property bound to the generated column.
/// </summary>
public string PropertyName
{
get;
private set;
}
/// <summary>
/// Gets the <see cref="T:System.Type"/> of the property bound to the generated column.
/// </summary>
public Type PropertyType
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,64 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides data for the <see cref="E:Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.BeginningEdit" /> event.
/// </summary>
public class DataGridBeginningEditEventArgs : CancelEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridBeginningEditEventArgs"/> class.
/// </summary>
/// <param name="column">
/// The column that contains the cell to be edited.
/// </param>
/// <param name="row">
/// The row that contains the cell to be edited.
/// </param>
/// <param name="editingEventArgs">
/// Information about the user gesture that caused the cell to enter edit mode.
/// </param>
public DataGridBeginningEditEventArgs(
DataGridColumn column,
DataGridRow row,
RoutedEventArgs editingEventArgs)
{
this.Column = column;
this.Row = row;
this.EditingEventArgs = editingEventArgs;
}
/// <summary>
/// Gets the column that contains the cell to be edited.
/// </summary>
public DataGridColumn Column
{
get;
private set;
}
/// <summary>
/// Gets information about the user gesture that caused the cell to enter edit mode.
/// </summary>
public RoutedEventArgs EditingEventArgs
{
get;
private set;
}
/// <summary>
/// Gets the row that contains the cell to be edited.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,212 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.UI.Data.Utilities;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Represents a <see cref="DataGrid"/> column that can
/// bind to a property in the grid's data source.
/// </summary>
[StyleTypedProperty(Property = "ElementStyle", StyleTargetType = typeof(FrameworkElement))]
[StyleTypedProperty(Property = "EditingElementStyle", StyleTargetType = typeof(FrameworkElement))]
public abstract class DataGridBoundColumn : DataGridColumn
{
private Binding _binding;
private Style _elementStyle;
private Style _editingElementStyle;
/// <summary>
/// Gets or sets the binding that associates the column with a property in the data source.
/// </summary>
public virtual Binding Binding
{
get
{
return _binding;
}
set
{
if (_binding != value)
{
if (this.OwningGrid != null && !this.OwningGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
{
// Edited value couldn't be committed, so we force a CancelEdit
this.OwningGrid.CancelEdit(DataGridEditingUnit.Row, false /*raiseEvents*/);
}
_binding = value;
if (_binding != null)
{
// Force the TwoWay binding mode if there is a Path present. TwoWay binding requires a Path.
if (_binding.Path != null && !string.IsNullOrEmpty(_binding.Path.Path))
{
_binding.Mode = BindingMode.TwoWay;
}
if (_binding.Converter == null)
{
_binding.Converter = new DataGridValueConverter();
}
// Setup the binding for validation
// Todo: WinUI3, can this be reenabled now?
// _binding.ValidatesOnDataErrors = true;
// _binding.ValidatesOnExceptions = true;
// _binding.NotifyOnValidationError = true;
_binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
// Apply the new Binding to existing rows in the DataGrid
if (this.OwningGrid != null)
{
// TODO: We want to clear the Bindings if Binding is set to null
// but there's no way to do that right now. Revisit this if UWP
// implements the equivalent of BindingOperations.ClearBinding.
this.OwningGrid.OnColumnBindingChanged(this);
}
}
this.RemoveEditingElement();
}
}
}
/// <summary>
/// Gets or sets the binding that will be used to get or set cell content for the clipboard.
/// If the base ClipboardContentBinding is not explicitly set, this will return the value of Binding.
/// </summary>
public override Binding ClipboardContentBinding
{
get
{
return base.ClipboardContentBinding ?? this.Binding;
}
set
{
base.ClipboardContentBinding = value;
}
}
/// <summary>
/// Gets or sets the style that is used when rendering the element that the column displays for a cell in editing mode.
/// </summary>
public Style EditingElementStyle
{
get
{
return _editingElementStyle;
}
set
{
if (_editingElementStyle != value)
{
_editingElementStyle = value;
// We choose not to update the elements already editing in the Grid here.
// They will get the EditingElementStyle next time they go into edit mode.
}
}
}
/// <summary>
/// Gets or sets the style that is used when rendering the element that the column displays for a cell that is not in editing mode.
/// </summary>
public Style ElementStyle
{
get
{
return _elementStyle;
}
set
{
if (_elementStyle != value)
{
_elementStyle = value;
if (this.OwningGrid != null)
{
this.OwningGrid.OnColumnElementStyleChanged(this);
}
}
}
}
internal DependencyProperty BindingTarget { get; set; }
internal override List<string> CreateBindingPaths()
{
if (this.Binding != null && this.Binding.Path != null)
{
return new List<string>() { this.Binding.Path.Path };
}
return base.CreateBindingPaths();
}
internal override List<BindingInfo> CreateBindings(FrameworkElement element, object dataItem, bool twoWay)
{
BindingInfo bindingData = new BindingInfo();
if (twoWay && this.BindingTarget != null)
{
bindingData.BindingExpression = element.GetBindingExpression(this.BindingTarget);
if (bindingData.BindingExpression != null)
{
bindingData.BindingTarget = this.BindingTarget;
bindingData.Element = element;
return new List<BindingInfo> { bindingData };
}
}
foreach (DependencyProperty bindingTarget in element.GetDependencyProperties(false))
{
bindingData.BindingExpression = element.GetBindingExpression(bindingTarget);
if (bindingData.BindingExpression != null
&& bindingData.BindingExpression.ParentBinding == this.Binding)
{
this.BindingTarget = bindingTarget;
bindingData.BindingTarget = this.BindingTarget;
bindingData.Element = element;
return new List<BindingInfo> { bindingData };
}
}
return base.CreateBindings(element, dataItem, twoWay);
}
#if FEATURE_ICOLLECTIONVIEW_SORT
internal override string GetSortPropertyName()
{
if (string.IsNullOrEmpty(this.SortMemberPath) && this.Binding != null && this.Binding.Path != null)
{
return this.Binding.Path.Path;
}
return this.SortMemberPath;
}
#endif
internal void SetHeaderFromBinding()
{
if (this.OwningGrid != null && this.OwningGrid.DataConnection.DataType != null &&
this.Header == null && this.Binding != null && this.Binding.Path != null)
{
string header = this.OwningGrid.DataConnection.DataType.GetDisplayName(this.Binding.Path.Path);
if (header != null)
{
this.Header = header;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,470 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.UI.Controls.Utilities;
using Microsoft.Toolkit.Uwp.UI.Utilities;
using Windows.Devices.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Shapes;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Represents an individual <see cref="DataGrid"/> cell.
/// </summary>
[TemplatePart(Name = DATAGRIDCELL_elementRightGridLine, Type = typeof(Rectangle))]
[TemplateVisualState(Name = VisualStates.StateNormal, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = VisualStates.StatePointerOver, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = VisualStates.StateUnselected, GroupName = VisualStates.GroupSelection)]
[TemplateVisualState(Name = VisualStates.StateSelected, GroupName = VisualStates.GroupSelection)]
[TemplateVisualState(Name = VisualStates.StateRegular, GroupName = VisualStates.GroupCurrent)]
[TemplateVisualState(Name = VisualStates.StateCurrent, GroupName = VisualStates.GroupCurrent)]
[TemplateVisualState(Name = VisualStates.StateCurrentWithFocus, GroupName = VisualStates.GroupCurrent)]
[TemplateVisualState(Name = VisualStates.StateDisplay, GroupName = VisualStates.GroupInteraction)]
[TemplateVisualState(Name = VisualStates.StateEditing, GroupName = VisualStates.GroupInteraction)]
[TemplateVisualState(Name = VisualStates.StateInvalid, GroupName = VisualStates.GroupValidation)]
[TemplateVisualState(Name = VisualStates.StateValid, GroupName = VisualStates.GroupValidation)]
public sealed partial class DataGridCell : ContentControl
{
private const string DATAGRIDCELL_elementRightGridLine = "RightGridLine";
private Rectangle _rightGridLine;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridCell"/> class.
/// </summary>
public DataGridCell()
{
this.IsTapEnabled = true;
this.AddHandler(UIElement.TappedEvent, new TappedEventHandler(DataGridCell_PointerTapped), true /*handledEventsToo*/);
this.PointerCanceled += new PointerEventHandler(DataGridCell_PointerCanceled);
this.PointerCaptureLost += new PointerEventHandler(DataGridCell_PointerCaptureLost);
this.PointerPressed += new PointerEventHandler(DataGridCell_PointerPressed);
this.PointerReleased += new PointerEventHandler(DataGridCell_PointerReleased);
this.PointerEntered += new PointerEventHandler(DataGridCell_PointerEntered);
this.PointerExited += new PointerEventHandler(DataGridCell_PointerExited);
this.PointerMoved += new PointerEventHandler(DataGridCell_PointerMoved);
DefaultStyleKey = typeof(DataGridCell);
}
/// <summary>
/// Gets a value indicating whether the data in a cell is valid.
/// </summary>
public bool IsValid
{
get
{
return (bool)GetValue(IsValidProperty);
}
internal set
{
this.SetValueNoCallback(IsValidProperty, value);
}
}
/// <summary>
/// Identifies the IsValid dependency property.
/// </summary>
public static readonly DependencyProperty IsValidProperty =
DependencyProperty.Register(
"IsValid",
typeof(bool),
typeof(DataGridCell),
new PropertyMetadata(true, OnIsValidPropertyChanged));
/// <summary>
/// IsValidProperty property changed handler.
/// </summary>
/// <param name="d">DataGridCell that changed its IsValid.</param>
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
private static void OnIsValidPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridCell dataGridCell = d as DataGridCell;
if (!dataGridCell.IsHandlerSuspended(e.Property))
{
dataGridCell.SetValueNoCallback(DataGridCell.IsValidProperty, e.OldValue);
throw DataGridError.DataGrid.UnderlyingPropertyIsReadOnly("IsValid");
}
}
internal double ActualRightGridLineWidth
{
get
{
if (_rightGridLine != null)
{
return _rightGridLine.ActualWidth;
}
return 0;
}
}
internal int ColumnIndex
{
get
{
if (this.OwningColumn == null)
{
return -1;
}
return this.OwningColumn.Index;
}
}
internal bool IsCurrent
{
get
{
Debug.Assert(this.OwningGrid != null && this.OwningColumn != null && this.OwningRow != null, "Expected non-null owning DataGrid, DataGridColumn and DataGridRow.");
return this.OwningGrid.CurrentColumnIndex == this.OwningColumn.Index &&
this.OwningGrid.CurrentSlot == this.OwningRow.Slot;
}
}
internal bool IsPointerOver
{
get
{
return this.InteractionInfo != null && this.InteractionInfo.IsPointerOver;
}
set
{
if (value && this.InteractionInfo == null)
{
this.InteractionInfo = new DataGridInteractionInfo();
}
if (this.InteractionInfo != null)
{
this.InteractionInfo.IsPointerOver = value;
}
ApplyCellState(true /*animate*/);
}
}
internal DataGridColumn OwningColumn
{
get;
set;
}
internal DataGrid OwningGrid
{
get
{
if (this.OwningRow != null && this.OwningRow.OwningGrid != null)
{
return this.OwningRow.OwningGrid;
}
if (this.OwningColumn != null)
{
return this.OwningColumn.OwningGrid;
}
return null;
}
}
internal DataGridRow OwningRow
{
get;
set;
}
internal int RowIndex
{
get
{
if (this.OwningRow == null)
{
return -1;
}
return this.OwningRow.Index;
}
}
private DataGridInteractionInfo InteractionInfo
{
get;
set;
}
private bool IsEdited
{
get
{
Debug.Assert(this.OwningGrid != null, "Expected non-null owning DataGrid.");
return this.OwningGrid.EditingRow == this.OwningRow &&
this.OwningGrid.EditingColumnIndex == this.ColumnIndex;
}
}
/// <summary>
/// Builds the visual tree for the row header when a new template is applied.
/// </summary>
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
ApplyCellState(false /*animate*/);
_rightGridLine = GetTemplateChild(DATAGRIDCELL_elementRightGridLine) as Rectangle;
if (_rightGridLine != null && this.OwningColumn == null)
{
// Turn off the right GridLine for filler cells
_rightGridLine.Visibility = Visibility.Collapsed;
}
else
{
EnsureGridLine(null);
}
}
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="DataGridCell"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
if (this.OwningGrid != null &&
this.OwningColumn != null &&
this.OwningColumn != this.OwningGrid.ColumnsInternal.FillerColumn)
{
return new DataGridCellAutomationPeer(this);
}
return base.OnCreateAutomationPeer();
}
internal void ApplyCellState(bool animate)
{
if (this.OwningGrid == null || this.OwningColumn == null || this.OwningRow == null || this.OwningRow.Visibility == Visibility.Collapsed || this.OwningRow.Slot == -1)
{
return;
}
// CommonStates
if (this.IsPointerOver)
{
VisualStates.GoToState(this, animate, VisualStates.StatePointerOver, VisualStates.StateNormal);
}
else
{
VisualStates.GoToState(this, animate, VisualStates.StateNormal);
}
// SelectionStates
if (this.OwningRow.IsSelected)
{
VisualStates.GoToState(this, animate, VisualStates.StateSelected, VisualStates.StateUnselected);
}
else
{
VisualStates.GoToState(this, animate, VisualStates.StateUnselected);
}
// CurrentStates
if (this.IsCurrent && !this.OwningGrid.ColumnHeaderHasFocus)
{
if (this.OwningGrid.ContainsFocus)
{
VisualStates.GoToState(this, animate, VisualStates.StateCurrentWithFocus, VisualStates.StateCurrent, VisualStates.StateRegular);
}
else
{
VisualStates.GoToState(this, animate, VisualStates.StateCurrent, VisualStates.StateRegular);
}
}
else
{
VisualStates.GoToState(this, animate, VisualStates.StateRegular);
}
// Interaction states
if (this.IsEdited)
{
VisualStates.GoToState(this, animate, VisualStates.StateEditing, VisualStates.StateDisplay);
}
else
{
VisualStates.GoToState(this, animate, VisualStates.StateDisplay);
}
// Validation states
if (this.IsValid)
{
VisualStates.GoToState(this, animate, VisualStates.StateValid);
}
else
{
VisualStates.GoToState(this, animate, VisualStates.StateInvalid, VisualStates.StateValid);
}
}
// Makes sure the right gridline has the proper stroke and visibility. If lastVisibleColumn is specified, the
// right gridline will be collapsed if this cell belongs to the lastVisibileColumn and there is no filler column
internal void EnsureGridLine(DataGridColumn lastVisibleColumn)
{
if (this.OwningGrid != null && _rightGridLine != null)
{
if (!(this.OwningColumn is DataGridFillerColumn) && this.OwningGrid.VerticalGridLinesBrush != null && this.OwningGrid.VerticalGridLinesBrush != _rightGridLine.Fill)
{
_rightGridLine.Fill = this.OwningGrid.VerticalGridLinesBrush;
}
Visibility newVisibility =
(this.OwningGrid.GridLinesVisibility == DataGridGridLinesVisibility.Vertical || this.OwningGrid.GridLinesVisibility == DataGridGridLinesVisibility.All) &&
(this.OwningGrid.ColumnsInternal.FillerColumn.IsActive || this.OwningColumn != lastVisibleColumn)
? Visibility.Visible : Visibility.Collapsed;
if (newVisibility != _rightGridLine.Visibility)
{
_rightGridLine.Visibility = newVisibility;
}
}
}
/// <summary>
/// Ensures that the correct Style is applied to this object.
/// </summary>
/// <param name="previousStyle">Caller's previous associated Style</param>
internal void EnsureStyle(Style previousStyle)
{
if (this.Style != null &&
(this.OwningColumn == null || this.Style != this.OwningColumn.CellStyle) &&
(this.OwningGrid == null || this.Style != this.OwningGrid.CellStyle) &&
this.Style != previousStyle)
{
return;
}
Style style = null;
if (this.OwningColumn != null)
{
style = this.OwningColumn.CellStyle;
}
if (style == null && this.OwningGrid != null)
{
style = this.OwningGrid.CellStyle;
}
this.SetStyleWithType(style);
}
internal void Recycle()
{
this.InteractionInfo = null;
}
private void CancelPointer(PointerRoutedEventArgs e)
{
if (this.InteractionInfo != null && this.InteractionInfo.CapturedPointerId == e.Pointer.PointerId)
{
this.InteractionInfo.CapturedPointerId = 0u;
}
this.IsPointerOver = false;
}
private void DataGridCell_PointerCanceled(object sender, PointerRoutedEventArgs e)
{
CancelPointer(e);
}
private void DataGridCell_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
CancelPointer(e);
}
private void DataGridCell_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == PointerDeviceType.Touch &&
this.OwningGrid != null &&
this.OwningGrid.AllowsManipulation &&
(this.InteractionInfo == null || this.InteractionInfo.CapturedPointerId == 0u) &&
this.CapturePointer(e.Pointer))
{
if (this.InteractionInfo == null)
{
this.InteractionInfo = new DataGridInteractionInfo();
}
this.InteractionInfo.CapturedPointerId = e.Pointer.PointerId;
}
}
private void DataGridCell_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (this.InteractionInfo != null && this.InteractionInfo.CapturedPointerId == e.Pointer.PointerId)
{
ReleasePointerCapture(e.Pointer);
}
}
private void DataGridCell_PointerEntered(object sender, PointerRoutedEventArgs e)
{
UpdateIsPointerOver(true);
}
private void DataGridCell_PointerExited(object sender, PointerRoutedEventArgs e)
{
UpdateIsPointerOver(false);
}
private void DataGridCell_PointerMoved(object sender, PointerRoutedEventArgs e)
{
UpdateIsPointerOver(true);
}
private void DataGridCell_PointerTapped(object sender, TappedRoutedEventArgs e)
{
// OwningGrid is null for TopLeftHeaderCell and TopRightHeaderCell because they have no OwningRow
if (this.OwningGrid != null && !this.OwningGrid.HasColumnUserInteraction)
{
if (!e.Handled && this.OwningGrid.IsTabStop)
{
bool success = this.OwningGrid.Focus(FocusState.Programmatic);
Debug.Assert(success, "Expected successful focus change.");
}
if (this.OwningRow != null)
{
Debug.Assert(sender is DataGridCell, "Expected sender is DataGridCell.");
Debug.Assert(sender as ContentControl == this, "Expected sender is this.");
e.Handled = this.OwningGrid.UpdateStateOnTapped(e, this.ColumnIndex, this.OwningRow.Slot, !e.Handled /*allowEdit*/);
this.OwningGrid.UpdatedStateOnTapped = true;
}
}
}
private void UpdateIsPointerOver(bool isPointerOver)
{
if (this.InteractionInfo != null && this.InteractionInfo.CapturedPointerId != 0u)
{
return;
}
this.IsPointerOver = isPointerOver;
}
}
}

Просмотреть файл

@ -0,0 +1,79 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
internal class DataGridCellCollection
{
private List<DataGridCell> _cells;
private DataGridRow _owningRow;
internal event EventHandler<DataGridCellEventArgs> CellAdded;
internal event EventHandler<DataGridCellEventArgs> CellRemoved;
public DataGridCellCollection(DataGridRow owningRow)
{
_owningRow = owningRow;
_cells = new List<DataGridCell>();
}
public int Count
{
get
{
return _cells.Count;
}
}
public IEnumerator GetEnumerator()
{
return _cells.GetEnumerator();
}
public void Insert(int cellIndex, DataGridCell cell)
{
Debug.Assert(cellIndex >= 0 && cellIndex <= _cells.Count, "Expected cellIndex between 0 and _cells.Count inclusive.");
Debug.Assert(cell != null, "Expected non-null cell.");
cell.OwningRow = _owningRow;
_cells.Insert(cellIndex, cell);
if (CellAdded != null)
{
CellAdded(this, new DataGridCellEventArgs(cell));
}
}
public void RemoveAt(int cellIndex)
{
DataGridCell dataGridCell = _cells[cellIndex];
_cells.RemoveAt(cellIndex);
dataGridCell.OwningRow = null;
if (CellRemoved != null)
{
CellRemoved(this, new DataGridCellEventArgs(dataGridCell));
}
}
public DataGridCell this[int index]
{
get
{
if (index < 0 || index >= _cells.Count)
{
throw DataGridError.DataGrid.ValueMustBeBetween("index", "Index", 0, true, _cells.Count, false);
}
return _cells[index];
}
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Globalization;
namespace Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals
{
internal class DataGridCellCoordinates
{
public DataGridCellCoordinates(int columnIndex, int slot)
{
this.ColumnIndex = columnIndex;
this.Slot = slot;
}
public DataGridCellCoordinates(DataGridCellCoordinates dataGridCellCoordinates)
: this(dataGridCellCoordinates.ColumnIndex, dataGridCellCoordinates.Slot)
{
}
public int ColumnIndex
{
get;
set;
}
public int Slot
{
get;
set;
}
public override bool Equals(object o)
{
DataGridCellCoordinates dataGridCellCoordinates = o as DataGridCellCoordinates;
if (dataGridCellCoordinates != null)
{
return dataGridCellCoordinates.ColumnIndex == this.ColumnIndex && dataGridCellCoordinates.Slot == this.Slot;
}
return false;
}
// Avoiding build warning CS0659: 'DataGridCellCoordinates' overrides Object.Equals(object o) but does not override Object.GetHashCode()
public override int GetHashCode()
{
return base.GetHashCode();
}
#if DEBUG
public override string ToString()
{
return "DataGridCellCoordinates {ColumnIndex = " + this.ColumnIndex.ToString(CultureInfo.CurrentCulture) +
", Slot = " + this.Slot.ToString(CultureInfo.CurrentCulture) + "}";
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides information just after a cell has exited editing mode.
/// </summary>
public class DataGridCellEditEndedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridCellEditEndedEventArgs"/> class.
/// </summary>
/// <param name="column">The column of the cell that has just exited edit mode.</param>
/// <param name="row">The row container of the cell container that has just exited edit mode.</param>
/// <param name="editAction">The editing action that has been taken.</param>
public DataGridCellEditEndedEventArgs(DataGridColumn column, DataGridRow row, DataGridEditAction editAction)
{
this.Column = column;
this.Row = row;
this.EditAction = editAction;
}
/// <summary>
/// Gets the column of the cell that has just exited edit mode.
/// </summary>
public DataGridColumn Column
{
get;
private set;
}
/// <summary>
/// Gets the edit action taken when leaving edit mode.
/// </summary>
public DataGridEditAction EditAction
{
get;
private set;
}
/// <summary>
/// Gets the row container of the cell container that has just exited edit mode.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,70 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides information just before a cell exits editing mode.
/// </summary>
public class DataGridCellEditEndingEventArgs : CancelEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridCellEditEndingEventArgs"/> class.
/// </summary>
/// <param name="column">The column of the cell that is about to exit edit mode.</param>
/// <param name="row">The row container of the cell container that is about to exit edit mode.</param>
/// <param name="editingElement">The editing element within the cell.</param>
/// <param name="editAction">The editing action that will be taken.</param>
public DataGridCellEditEndingEventArgs(
DataGridColumn column,
DataGridRow row,
FrameworkElement editingElement,
DataGridEditAction editAction)
{
this.Column = column;
this.Row = row;
this.EditingElement = editingElement;
this.EditAction = editAction;
}
/// <summary>
/// Gets the column of the cell that is about to exit edit mode.
/// </summary>
public DataGridColumn Column
{
get;
private set;
}
/// <summary>
/// Gets the edit action to take when leaving edit mode.
/// </summary>
public DataGridEditAction EditAction
{
get;
private set;
}
/// <summary>
/// Gets the editing element within the cell.
/// </summary>
public FrameworkElement EditingElement
{
get;
private set;
}
/// <summary>
/// Gets the row container of the cell container that is about to exit edit mode.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
internal class DataGridCellEventArgs : EventArgs
{
internal DataGridCellEventArgs(DataGridCell dataGridCell)
{
Debug.Assert(dataGridCell != null, "Expected non-null dataGridCell parameter.");
this.Cell = dataGridCell;
}
internal DataGridCell Cell
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,338 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Primitives
{
/// <summary>
/// Used within the template of a <see cref="DataGrid"/>
/// to specify the location in the control's visual tree where the cells are to be added.
/// </summary>
public sealed class DataGridCellsPresenter : Panel
{
private double _fillerLeftEdge;
// The desired height needs to be cached due to column virtualization; otherwise, the cells
// would grow and shrink as the DataGrid scrolls horizontally
private double DesiredHeight
{
get;
set;
}
private DataGrid OwningGrid
{
get
{
if (this.OwningRow != null)
{
return this.OwningRow.OwningGrid;
}
return null;
}
}
internal DataGridRow OwningRow
{
get;
set;
}
/// <summary>
/// Arranges the content of the <see cref="T:System.Windows.Controls.Primitives.DataGridCellsPresenter"/>.
/// </summary>
/// <returns>
/// The actual size used by the <see cref="T:System.Windows.Controls.Primitives.DataGridCellsPresenter"/>.
/// </returns>
/// <param name="finalSize">
/// The final area within the parent that this element should use to arrange itself and its children.
/// </param>
protected override Size ArrangeOverride(Size finalSize)
{
if (this.OwningGrid == null)
{
return base.ArrangeOverride(finalSize);
}
if (this.OwningGrid.AutoSizingColumns)
{
// When we initially load an auto-column, we have to wait for all the rows to be measured
// before we know its final desired size. We need to trigger a new round of measures now
// that the final sizes have been calculated.
this.OwningGrid.AutoSizingColumns = false;
return base.ArrangeOverride(finalSize);
}
double frozenLeftEdge = 0;
double scrollingLeftEdge = -this.OwningGrid.HorizontalOffset;
double cellLeftEdge;
foreach (DataGridColumn column in this.OwningGrid.ColumnsInternal.GetVisibleColumns())
{
DataGridCell cell = this.OwningRow.Cells[column.Index];
Debug.Assert(cell.OwningColumn == column, "Expected column owner.");
Debug.Assert(column.IsVisible, "Expected visible column.");
if (column.IsFrozen)
{
cellLeftEdge = frozenLeftEdge;
// This can happen before or after clipping because frozen cells aren't clipped
frozenLeftEdge += column.ActualWidth;
}
else
{
cellLeftEdge = scrollingLeftEdge;
}
if (cell.Visibility == Visibility.Visible)
{
cell.Arrange(new Rect(cellLeftEdge, 0, column.LayoutRoundedWidth, finalSize.Height));
EnsureCellClip(cell, column.ActualWidth, finalSize.Height, frozenLeftEdge, scrollingLeftEdge);
}
scrollingLeftEdge += column.ActualWidth;
column.IsInitialDesiredWidthDetermined = true;
}
_fillerLeftEdge = scrollingLeftEdge;
// FillerColumn.Width == 0 when the filler column is not active
this.OwningRow.FillerCell.Arrange(new Rect(_fillerLeftEdge, 0, this.OwningGrid.ColumnsInternal.FillerColumn.FillerWidth, finalSize.Height));
return finalSize;
}
private static void EnsureCellClip(DataGridCell cell, double width, double height, double frozenLeftEdge, double cellLeftEdge)
{
// Clip the cell only if it's scrolled under frozen columns. Unfortunately, we need to clip in this case
// because cells could be transparent
if (!cell.OwningColumn.IsFrozen && frozenLeftEdge > cellLeftEdge)
{
RectangleGeometry rg = new RectangleGeometry();
double xClip = Math.Round(Math.Min(width, frozenLeftEdge - cellLeftEdge));
rg.Rect = new Rect(xClip, 0, Math.Max(0, width - xClip), height);
cell.Clip = rg;
}
else
{
cell.Clip = null;
}
}
private static void EnsureCellDisplay(DataGridCell cell, bool displayColumn)
{
if (cell.IsCurrent)
{
if (displayColumn)
{
cell.Visibility = Visibility.Visible;
cell.Clip = null;
}
else
{
// Clip
RectangleGeometry rg = new RectangleGeometry();
rg.Rect = Rect.Empty;
cell.Clip = rg;
}
}
else
{
cell.Visibility = displayColumn ? Visibility.Visible : Visibility.Collapsed;
}
}
internal void EnsureFillerVisibility()
{
DataGridFillerColumn fillerColumn = this.OwningGrid.ColumnsInternal.FillerColumn;
Visibility newVisibility = fillerColumn.IsActive ? Visibility.Visible : Visibility.Collapsed;
if (this.OwningRow.FillerCell.Visibility != newVisibility)
{
this.OwningRow.FillerCell.Visibility = newVisibility;
if (newVisibility == Visibility.Visible)
{
this.OwningRow.FillerCell.Arrange(new Rect(_fillerLeftEdge, 0, fillerColumn.FillerWidth, this.ActualHeight));
}
}
// This must be done after the Filler visibility is determined. This also must be done
// regardless of whether or not the filler visibility actually changed values because
// we could scroll in a cell that didn't have EnsureGridLine called yet
DataGridColumn lastVisibleColumn = this.OwningGrid.ColumnsInternal.LastVisibleColumn;
if (lastVisibleColumn != null)
{
DataGridCell cell = this.OwningRow.Cells[lastVisibleColumn.Index];
cell.EnsureGridLine(lastVisibleColumn);
}
}
/// <summary>
/// Measures the children of a <see cref="T:System.Windows.Controls.Primitives.DataGridCellsPresenter"/> to
/// prepare for arranging them during the <see cref="M:System.Windows.FrameworkElement.ArrangeOverride(System.Windows.Size)"/> pass.
/// </summary>
/// <param name="availableSize">
/// The available size that this element can give to child elements. Indicates an upper limit that child elements should not exceed.
/// </param>
/// <returns>
/// The size that the <see cref="T:System.Windows.Controls.Primitives.DataGridCellsPresenter"/> determines it needs during layout, based on its calculations of child object allocated sizes.
/// </returns>
protected override Size MeasureOverride(Size availableSize)
{
if (this.OwningGrid == null)
{
return base.MeasureOverride(availableSize);
}
bool autoSizeHeight;
double measureHeight;
if (double.IsNaN(this.OwningGrid.RowHeight))
{
// No explicit height values were set so we can autosize
autoSizeHeight = true;
measureHeight = double.PositiveInfinity;
}
else
{
this.DesiredHeight = this.OwningGrid.RowHeight;
measureHeight = this.DesiredHeight;
autoSizeHeight = false;
}
double frozenLeftEdge = 0;
double totalDisplayWidth = 0;
double scrollingLeftEdge = -this.OwningGrid.HorizontalOffset;
this.OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
DataGridColumn lastVisibleColumn = this.OwningGrid.ColumnsInternal.LastVisibleColumn;
foreach (DataGridColumn column in this.OwningGrid.ColumnsInternal.GetVisibleColumns())
{
DataGridCell cell = this.OwningRow.Cells[column.Index];
// Measure the entire first row to make the horizontal scrollbar more accurate
bool shouldDisplayCell = ShouldDisplayCell(column, frozenLeftEdge, scrollingLeftEdge) || this.OwningRow.Index == 0;
EnsureCellDisplay(cell, shouldDisplayCell);
if (shouldDisplayCell)
{
DataGridLength columnWidth = column.Width;
bool autoGrowWidth = columnWidth.IsSizeToCells || columnWidth.IsAuto;
if (column != lastVisibleColumn)
{
cell.EnsureGridLine(lastVisibleColumn);
}
// If we're not using star sizing or the current column can't be resized,
// then just set the display width according to the column's desired width
if (!this.OwningGrid.UsesStarSizing || (!column.ActualCanUserResize && !column.Width.IsStar))
{
// In the edge-case where we're given infinite width and we have star columns, the
// star columns grow to their predefined limit of 10,000 (or their MaxWidth)
double newDisplayWidth = column.Width.IsStar ?
Math.Min(column.ActualMaxWidth, DataGrid.DATAGRID_maximumStarColumnWidth) :
Math.Max(column.ActualMinWidth, Math.Min(column.ActualMaxWidth, column.Width.DesiredValue));
column.SetWidthDisplayValue(newDisplayWidth);
}
// If we're auto-growing the column based on the cell content, we want to measure it at its maximum value
if (autoGrowWidth)
{
cell.Measure(new Size(column.ActualMaxWidth, measureHeight));
this.OwningGrid.AutoSizeColumn(column, cell.DesiredSize.Width);
column.ComputeLayoutRoundedWidth(totalDisplayWidth);
}
else if (!this.OwningGrid.UsesStarSizing)
{
column.ComputeLayoutRoundedWidth(scrollingLeftEdge);
cell.Measure(new Size(column.LayoutRoundedWidth, measureHeight));
}
// We need to track the largest height in order to auto-size
if (autoSizeHeight)
{
this.DesiredHeight = Math.Max(this.DesiredHeight, cell.DesiredSize.Height);
}
}
if (column.IsFrozen)
{
frozenLeftEdge += column.ActualWidth;
}
scrollingLeftEdge += column.ActualWidth;
totalDisplayWidth += column.ActualWidth;
}
// If we're using star sizing (and we're not waiting for an auto-column to finish growing)
// then we will resize all the columns to fit the available space.
if (this.OwningGrid.UsesStarSizing && !this.OwningGrid.AutoSizingColumns)
{
double adjustment = this.OwningGrid.CellsWidth - totalDisplayWidth;
this.OwningGrid.AdjustColumnWidths(0, adjustment, false);
// Since we didn't know the final widths of the columns until we resized,
// we waited until now to measure each cell
double leftEdge = 0;
foreach (DataGridColumn column in this.OwningGrid.ColumnsInternal.GetVisibleColumns())
{
DataGridCell cell = this.OwningRow.Cells[column.Index];
column.ComputeLayoutRoundedWidth(leftEdge);
cell.Measure(new Size(column.LayoutRoundedWidth, measureHeight));
if (autoSizeHeight)
{
this.DesiredHeight = Math.Max(this.DesiredHeight, cell.DesiredSize.Height);
}
leftEdge += column.ActualWidth;
}
}
// Measure FillerCell, we're doing it unconditionally here because we don't know if we'll need the filler
// column and we don't want to cause another Measure if we do
this.OwningRow.FillerCell.Measure(new Size(double.PositiveInfinity, this.DesiredHeight));
this.OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
return new Size(this.OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth, this.DesiredHeight);
}
internal void Recycle()
{
// Clear out the cached desired height so it is not reused for other rows
this.DesiredHeight = 0;
if (this.OwningGrid != null && this.OwningRow != null)
{
foreach (DataGridColumn column in this.OwningGrid.ColumnsInternal)
{
this.OwningRow.Cells[column.Index].Recycle();
}
}
}
private bool ShouldDisplayCell(DataGridColumn column, double frozenLeftEdge, double scrollingLeftEdge)
{
Debug.Assert(this.OwningGrid != null, "Expected non-null owning DataGrid.");
Debug.Assert(this.OwningGrid.HorizontalAdjustment >= 0, "Expected owning positive DataGrid.HorizontalAdjustment.");
Debug.Assert(this.OwningGrid.HorizontalAdjustment <= this.OwningGrid.HorizontalOffset, "Expected owning DataGrid.HorizontalAdjustment smaller than or equal to DataGrid.HorizontalOffset.");
if (column.Visibility != Visibility.Visible)
{
return false;
}
scrollingLeftEdge += this.OwningGrid.HorizontalAdjustment;
double leftEdge = column.IsFrozen ? frozenLeftEdge : scrollingLeftEdge;
double rightEdge = leftEdge + column.ActualWidth;
return DoubleUtil.GreaterThan(rightEdge, 0) &&
DoubleUtil.LessThanOrClose(leftEdge, this.OwningGrid.CellsWidth) &&
DoubleUtil.GreaterThan(rightEdge, frozenLeftEdge); // scrolling column covered up by frozen column(s)
}
}
}

Просмотреть файл

@ -0,0 +1,361 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Specialized;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Represents a <see cref="DataGrid"/> column that hosts
/// <see cref="T:System.Windows.Controls.CheckBox"/> controls in its cells.
/// </summary>
[StyleTypedProperty(Property = "ElementStyle", StyleTargetType = typeof(CheckBox))]
[StyleTypedProperty(Property = "EditingElementStyle", StyleTargetType = typeof(CheckBox))]
public class DataGridCheckBoxColumn : DataGridBoundColumn
{
private const string DATAGRIDCHECKBOXCOLUMN_isThreeStateName = "IsThreeState";
private const double DATAGRIDCHECKBOXCOLUMN_leftMargin = 12.0;
private bool _beganEditWithKeyboard;
private bool _isThreeState;
private CheckBox _currentCheckBox;
private DataGrid _owningGrid;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridCheckBoxColumn"/> class.
/// </summary>
public DataGridCheckBoxColumn()
{
this.BindingTarget = CheckBox.IsCheckedProperty;
}
/// <summary>
/// Gets or sets a value indicating whether the hosted <see cref="T:System.Windows.Controls.CheckBox"/> controls allow three states or two.
/// </summary>
/// <returns>
/// true if the hosted controls support three states; false if they support two states. The default is false.
/// </returns>
public bool IsThreeState
{
get
{
return _isThreeState;
}
set
{
if (_isThreeState != value)
{
_isThreeState = value;
NotifyPropertyChanged(DATAGRIDCHECKBOXCOLUMN_isThreeStateName);
}
}
}
/// <summary>
/// Causes the column cell being edited to revert to the specified value.
/// </summary>
/// <param name="editingElement">
/// The element that the column displays for a cell in editing mode.
/// </param>
/// <param name="uneditedValue">
/// The previous, unedited value in the cell being edited.
/// </param>
protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
{
CheckBox editingCheckBox = editingElement as CheckBox;
if (editingCheckBox != null)
{
editingCheckBox.IsChecked = (bool?)uneditedValue;
}
}
/// <summary>
/// Gets a <see cref="T:System.Windows.Controls.CheckBox"/> control that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </summary>
/// <param name="cell">
/// The cell that will contain the generated element.
/// </param>
/// <param name="dataItem">
/// The data item represented by the row that contains the intended cell.
/// </param>
/// <returns>
/// A new <see cref="T:System.Windows.Controls.CheckBox"/> control that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </returns>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
CheckBox checkBox = new CheckBox();
ConfigureCheckBox(checkBox, (cell != null & cell.OwningRow != null) ? cell.OwningRow.ComputedForeground : null);
return checkBox;
}
/// <summary>
/// Gets a read-only <see cref="T:System.Windows.Controls.CheckBox"/> control that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </summary>
/// <param name="cell">
/// The cell that will contain the generated element.
/// </param>
/// <param name="dataItem">
/// The data item represented by the row that contains the intended cell.
/// </param>
/// <returns>
/// A new, read-only <see cref="T:System.Windows.Controls.CheckBox"/> control that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </returns>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
bool isEnabled = false;
CheckBox checkBoxElement = new CheckBox();
if (EnsureOwningGrid())
{
if (cell.RowIndex != -1 && cell.ColumnIndex != -1 &&
cell.OwningRow != null &&
cell.OwningRow.Slot == this.OwningGrid.CurrentSlot &&
cell.ColumnIndex == this.OwningGrid.CurrentColumnIndex)
{
isEnabled = true;
if (_currentCheckBox != null)
{
_currentCheckBox.IsEnabled = false;
}
_currentCheckBox = checkBoxElement;
}
}
checkBoxElement.IsEnabled = isEnabled;
checkBoxElement.IsHitTestVisible = false;
checkBoxElement.IsTabStop = false;
ConfigureCheckBox(checkBoxElement, (cell != null & cell.OwningRow != null) ? cell.OwningRow.ComputedForeground : null);
return checkBoxElement;
}
/// <summary>
/// Called when a cell in the column enters editing mode.
/// </summary>
/// <param name="editingElement">
/// The element that the column displays for a cell in editing mode.
/// </param>
/// <param name="editingEventArgs">
/// Information about the user gesture that is causing a cell to enter editing mode.
/// </param>
/// <returns>
/// The unedited value.
/// </returns>
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
CheckBox editingCheckBox = editingElement as CheckBox;
if (editingCheckBox != null)
{
bool? uneditedValue = editingCheckBox.IsChecked;
PointerRoutedEventArgs pointerEventArgs = editingEventArgs as PointerRoutedEventArgs;
bool editValue = false;
if (pointerEventArgs != null)
{
// Editing was triggered by a mouse click
Point position = pointerEventArgs.GetCurrentPoint(editingCheckBox).Position;
Rect rect = new Rect(0, 0, editingCheckBox.ActualWidth, editingCheckBox.ActualHeight);
editValue = rect.Contains(position);
}
else if (_beganEditWithKeyboard)
{
// Editing began by a user pressing spacebar
editValue = true;
_beganEditWithKeyboard = false;
}
if (editValue)
{
// User clicked the checkbox itself or pressed space, let's toggle the IsChecked value
if (editingCheckBox.IsThreeState)
{
switch (editingCheckBox.IsChecked)
{
case false:
editingCheckBox.IsChecked = true;
break;
case true:
editingCheckBox.IsChecked = null;
break;
case null:
editingCheckBox.IsChecked = false;
break;
}
}
else
{
editingCheckBox.IsChecked = !editingCheckBox.IsChecked;
}
}
return uneditedValue;
}
return false;
}
/// <summary>
/// Called by the DataGrid control when this column asks for its elements to be
/// updated, because its CheckBoxContent or IsThreeState property changed.
/// </summary>
protected internal override void RefreshCellContent(FrameworkElement element, Brush computedRowForeground, string propertyName)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
CheckBox checkBox = element as CheckBox;
if (checkBox == null)
{
throw DataGridError.DataGrid.ValueIsNotAnInstanceOf("element", typeof(CheckBox));
}
if (propertyName == DATAGRIDCHECKBOXCOLUMN_isThreeStateName)
{
checkBox.IsThreeState = this.IsThreeState;
}
else
{
checkBox.IsThreeState = this.IsThreeState;
checkBox.Foreground = computedRowForeground;
}
}
/// <summary>
/// Called when the computed foreground of a row changed.
/// </summary>
protected internal override void RefreshForeground(FrameworkElement element, Brush computedRowForeground)
{
CheckBox checkBox = element as CheckBox;
if (checkBox != null)
{
checkBox.Foreground = computedRowForeground;
}
}
private void Columns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (this.OwningGrid == null && _owningGrid != null)
{
_owningGrid.Columns.CollectionChanged -= new NotifyCollectionChangedEventHandler(Columns_CollectionChanged);
_owningGrid.CurrentCellChanged -= new EventHandler<EventArgs>(OwningGrid_CurrentCellChanged);
_owningGrid.KeyDown -= new KeyEventHandler(OwningGrid_KeyDown);
_owningGrid.LoadingRow -= new EventHandler<DataGridRowEventArgs>(OwningGrid_LoadingRow);
_owningGrid = null;
}
}
private void ConfigureCheckBox(CheckBox checkBox, Brush computedRowForeground)
{
checkBox.Margin = new Thickness(DATAGRIDCHECKBOXCOLUMN_leftMargin, 0.0, 0.0, 0.0);
checkBox.HorizontalAlignment = HorizontalAlignment.Left;
checkBox.VerticalAlignment = VerticalAlignment.Center;
checkBox.IsThreeState = this.IsThreeState;
checkBox.UseSystemFocusVisuals = false;
checkBox.Foreground = computedRowForeground;
if (this.Binding != null)
{
checkBox.SetBinding(this.BindingTarget, this.Binding);
}
}
private bool EnsureOwningGrid()
{
if (this.OwningGrid != null)
{
if (this.OwningGrid != _owningGrid)
{
_owningGrid = this.OwningGrid;
_owningGrid.Columns.CollectionChanged += new NotifyCollectionChangedEventHandler(Columns_CollectionChanged);
_owningGrid.CurrentCellChanged += new EventHandler<EventArgs>(OwningGrid_CurrentCellChanged);
_owningGrid.KeyDown += new KeyEventHandler(OwningGrid_KeyDown);
_owningGrid.LoadingRow += new EventHandler<DataGridRowEventArgs>(OwningGrid_LoadingRow);
}
return true;
}
return false;
}
private void OwningGrid_CurrentCellChanged(object sender, EventArgs e)
{
if (_currentCheckBox != null)
{
_currentCheckBox.IsEnabled = false;
}
if (this.OwningGrid != null && this.OwningGrid.CurrentColumn == this &&
this.OwningGrid.IsSlotVisible(this.OwningGrid.CurrentSlot))
{
DataGridRow row = this.OwningGrid.DisplayData.GetDisplayedElement(this.OwningGrid.CurrentSlot) as DataGridRow;
if (row != null)
{
CheckBox checkBox = this.GetCellContent(row) as CheckBox;
if (checkBox != null)
{
checkBox.IsEnabled = true;
}
_currentCheckBox = checkBox;
}
}
}
private void OwningGrid_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Space &&
this.OwningGrid != null &&
this.OwningGrid.CurrentColumn == this)
{
DataGridRow row = this.OwningGrid.DisplayData.GetDisplayedElement(this.OwningGrid.CurrentSlot) as DataGridRow;
if (row != null)
{
CheckBox checkBox = this.GetCellContent(row) as CheckBox;
if (checkBox == _currentCheckBox)
{
_beganEditWithKeyboard = true;
this.OwningGrid.BeginEdit();
return;
}
}
}
_beganEditWithKeyboard = false;
}
private void OwningGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
if (this.OwningGrid != null)
{
CheckBox checkBox = this.GetCellContent(e.Row) as CheckBox;
if (checkBox != null)
{
if (this.OwningGrid.CurrentColumnIndex == this.Index && this.OwningGrid.CurrentSlot == e.Row.Slot)
{
if (_currentCheckBox != null)
{
_currentCheckBox.IsEnabled = false;
}
checkBox.IsEnabled = true;
_currentCheckBox = checkBox;
}
else
{
checkBox.IsEnabled = false;
}
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,114 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// This structure encapsulate the cell information necessary when clipboard content is prepared.
/// </summary>
public struct DataGridClipboardCellContent
{
private DataGridColumn _column;
private object _content;
private object _item;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridClipboardCellContent"/> struct.
/// </summary>
/// <param name="item">DataGrid row item containing the cell.</param>
/// <param name="column">DataGridColumn containing the cell.</param>
/// <param name="content">DataGrid cell value.</param>
public DataGridClipboardCellContent(object item, DataGridColumn column, object content)
{
_item = item;
_column = column;
_content = content;
}
/// <summary>
/// Gets the <see cref="DataGridColumn"/> column containing the cell.
/// </summary>
public DataGridColumn Column
{
get
{
return _column;
}
}
/// <summary>
/// Gets the <see cref="DataGridCell"/> cell content.
/// </summary>
public object Content
{
get
{
return _content;
}
}
/// <summary>
/// Gets the <see cref="DataGridRow"/> row item containing the cell.
/// </summary>
public object Item
{
get
{
return _item;
}
}
/// <summary>
/// Field-by-field comparison to avoid reflection-based ValueType.Equals.
/// </summary>
/// <param name="obj">DataGridClipboardCellContent to compare.</param>
/// <returns>True if this and data are equal</returns>
public override bool Equals(object obj)
{
if (!(obj is DataGridClipboardCellContent))
{
return false;
}
DataGridClipboardCellContent clipboardCellContent = (DataGridClipboardCellContent)obj;
return _column == clipboardCellContent._column && _content == clipboardCellContent._content && _item == clipboardCellContent._item;
}
/// <summary>
/// Returns a deterministic hash code.
/// </summary>
/// <returns>Hash value.</returns>
public override int GetHashCode()
{
return (_column.GetHashCode() ^ _content.GetHashCode()) ^ _item.GetHashCode();
}
/// <summary>
/// Field-by-field comparison to avoid reflection-based ValueType.Equals.
/// </summary>
/// <param name="clipboardCellContent1">The first DataGridClipboardCellContent.</param>
/// <param name="clipboardCellContent2">The second DataGridClipboardCellContent.</param>
/// <returns>True if and only if clipboardCellContent1 and clipboardCellContent2 are equal.</returns>
public static bool operator ==(DataGridClipboardCellContent clipboardCellContent1, DataGridClipboardCellContent clipboardCellContent2)
{
return clipboardCellContent1._column == clipboardCellContent2._column && clipboardCellContent1._content == clipboardCellContent2._content && clipboardCellContent1._item == clipboardCellContent2._item;
}
/// <summary>
/// Field-by-field comparison to avoid reflection-based ValueType.Equals.
/// </summary>
/// <param name="clipboardCellContent1">The first DataGridClipboardCellContent.</param>
/// <param name="clipboardCellContent2">The second DataGridClipboardCellContent.</param>
/// <returns>True if clipboardCellContent1 and clipboardCellContent2 are NOT equal.</returns>
public static bool operator !=(DataGridClipboardCellContent clipboardCellContent1, DataGridClipboardCellContent clipboardCellContent2)
{
if (clipboardCellContent1._column == clipboardCellContent2._column && clipboardCellContent1._content == clipboardCellContent2._content)
{
return clipboardCellContent1._item != clipboardCellContent2._item;
}
return true;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,659 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
internal class DataGridColumnCollection : ObservableCollection<DataGridColumn>
{
private DataGrid _owningGrid;
public DataGridColumnCollection(DataGrid owningGrid)
{
_owningGrid = owningGrid;
this.ItemsInternal = new List<DataGridColumn>();
this.FillerColumn = new DataGridFillerColumn(owningGrid);
this.DisplayIndexMap = new List<int>();
this.RowGroupSpacerColumn = new DataGridFillerColumn(owningGrid);
}
internal int AutogeneratedColumnCount
{
get;
set;
}
internal List<int> DisplayIndexMap
{
get;
set;
}
internal DataGridFillerColumn FillerColumn
{
get;
private set;
}
internal DataGridColumn FirstColumn
{
get
{
return GetFirstColumn(null /*isVisible*/, null /*isFrozen*/, null /*isReadOnly*/);
}
}
internal DataGridColumn FirstVisibleColumn
{
get
{
return GetFirstColumn(true /*isVisible*/, null /*isFrozen*/, null /*isReadOnly*/);
}
}
internal DataGridColumn FirstVisibleNonFillerColumn
{
get
{
DataGridColumn dataGridColumn = this.FirstVisibleColumn;
if (dataGridColumn == this.RowGroupSpacerColumn)
{
dataGridColumn = GetNextVisibleColumn(dataGridColumn);
}
return dataGridColumn;
}
}
internal DataGridColumn FirstVisibleWritableColumn
{
get
{
return GetFirstColumn(true /*isVisible*/, null /*isFrozen*/, false /*isReadOnly*/);
}
}
internal DataGridColumn FirstVisibleScrollingColumn
{
get
{
return GetFirstColumn(true /*isVisible*/, false /*isFrozen*/, null /*isReadOnly*/);
}
}
internal List<DataGridColumn> ItemsInternal
{
get;
private set;
}
internal DataGridColumn LastVisibleColumn
{
get
{
return GetLastColumn(true /*isVisible*/, null /*isFrozen*/, null /*isReadOnly*/);
}
}
internal DataGridColumn LastVisibleScrollingColumn
{
get
{
return GetLastColumn(true /*isVisible*/, false /*isFrozen*/, null /*isReadOnly*/);
}
}
internal DataGridColumn LastVisibleWritableColumn
{
get
{
return GetLastColumn(true /*isVisible*/, null /*isFrozen*/, false /*isReadOnly*/);
}
}
internal DataGridFillerColumn RowGroupSpacerColumn
{
get;
private set;
}
internal int VisibleColumnCount
{
get
{
int visibleColumnCount = 0;
for (int columnIndex = 0; columnIndex < this.ItemsInternal.Count; columnIndex++)
{
if (this.ItemsInternal[columnIndex].IsVisible)
{
visibleColumnCount++;
}
}
return visibleColumnCount;
}
}
internal double VisibleEdgedColumnsWidth
{
get;
private set;
}
/// <summary>
/// Gets the number of star columns that are currently visible.
/// NOTE: Requires that EnsureVisibleEdgedColumnsWidth has been called.
/// </summary>
internal int VisibleStarColumnCount
{
get;
private set;
}
protected override void ClearItems()
{
Debug.Assert(_owningGrid != null, "Expected non-null owning DataGrid.");
try
{
_owningGrid.NoCurrentCellChangeCount++;
if (this.ItemsInternal.Count > 0)
{
if (_owningGrid.InDisplayIndexAdjustments)
{
// We are within columns display indexes adjustments. We do not allow changing the column collection while adjusting display indexes.
throw DataGridError.DataGrid.CannotChangeColumnCollectionWhileAdjustingDisplayIndexes();
}
_owningGrid.OnClearingColumns();
for (int columnIndex = 0; columnIndex < this.ItemsInternal.Count; columnIndex++)
{
// Detach the column...
this.ItemsInternal[columnIndex].OwningGrid = null;
}
this.ItemsInternal.Clear();
this.DisplayIndexMap.Clear();
this.AutogeneratedColumnCount = 0;
_owningGrid.OnColumnCollectionChanged_PreNotification(false /*columnsGrew*/);
base.ClearItems();
this.VisibleEdgedColumnsWidth = 0;
_owningGrid.OnColumnCollectionChanged_PostNotification(false /*columnsGrew*/);
}
}
finally
{
_owningGrid.NoCurrentCellChangeCount--;
}
}
protected override void InsertItem(int columnIndex, DataGridColumn dataGridColumn)
{
Debug.Assert(_owningGrid != null, "Expected non-null owning DataGrid.");
try
{
_owningGrid.NoCurrentCellChangeCount++;
if (_owningGrid.InDisplayIndexAdjustments)
{
// We are within columns display indexes adjustments. We do not allow changing the column collection while adjusting display indexes.
throw DataGridError.DataGrid.CannotChangeColumnCollectionWhileAdjustingDisplayIndexes();
}
if (dataGridColumn == null)
{
throw new ArgumentNullException("dataGridColumn");
}
int columnIndexWithFiller = columnIndex;
if (dataGridColumn != this.RowGroupSpacerColumn && this.RowGroupSpacerColumn.IsRepresented)
{
columnIndexWithFiller++;
}
// get the new current cell coordinates
DataGridCellCoordinates newCurrentCellCoordinates = _owningGrid.OnInsertingColumn(columnIndex, dataGridColumn);
// insert the column into our internal list
this.ItemsInternal.Insert(columnIndexWithFiller, dataGridColumn);
dataGridColumn.Index = columnIndexWithFiller;
dataGridColumn.OwningGrid = _owningGrid;
dataGridColumn.RemoveEditingElement();
if (dataGridColumn.IsVisible)
{
this.VisibleEdgedColumnsWidth += dataGridColumn.ActualWidth;
}
// continue with the base insert
_owningGrid.OnInsertedColumn_PreNotification(dataGridColumn);
_owningGrid.OnColumnCollectionChanged_PreNotification(true /*columnsGrew*/);
if (dataGridColumn != this.RowGroupSpacerColumn)
{
base.InsertItem(columnIndex, dataGridColumn);
}
_owningGrid.OnInsertedColumn_PostNotification(newCurrentCellCoordinates, dataGridColumn.DisplayIndex);
_owningGrid.OnColumnCollectionChanged_PostNotification(true /*columnsGrew*/);
}
finally
{
_owningGrid.NoCurrentCellChangeCount--;
}
}
protected override void RemoveItem(int columnIndex)
{
RemoveItemPrivate(columnIndex, false /*isSpacer*/);
}
protected override void SetItem(int columnIndex, DataGridColumn dataGridColumn)
{
throw new NotSupportedException();
}
internal bool DisplayInOrder(int columnIndex1, int columnIndex2)
{
int displayIndex1 = ((DataGridColumn)this.ItemsInternal[columnIndex1]).DisplayIndexWithFiller;
int displayIndex2 = ((DataGridColumn)this.ItemsInternal[columnIndex2]).DisplayIndexWithFiller;
return displayIndex1 < displayIndex2;
}
internal bool EnsureRowGrouping(bool rowGrouping)
{
// The insert below could cause the first column to be added. That causes a refresh
// which re-enters this method so instead of checking RowGroupSpacerColumn.IsRepresented,
// we need to check to see if it's actually in our collection instead.
bool spacerRepresented = (this.ItemsInternal.Count > 0) && (this.ItemsInternal[0] == this.RowGroupSpacerColumn);
if (rowGrouping && !spacerRepresented)
{
this.Insert(0, this.RowGroupSpacerColumn);
this.RowGroupSpacerColumn.IsRepresented = true;
return true;
}
else if (!rowGrouping && spacerRepresented)
{
Debug.Assert(this.ItemsInternal[0] == this.RowGroupSpacerColumn, "Unexpected RowGroupSpacerColumn value.");
// We need to set IsRepresented to false before removing the RowGroupSpacerColumn
// otherwise, we'll remove the column after it
this.RowGroupSpacerColumn.IsRepresented = false;
RemoveItemPrivate(0, true /*isSpacer*/);
Debug.Assert(this.DisplayIndexMap.Count == this.ItemsInternal.Count, "Unexpected DisplayIndexMap.Count value.");
return true;
}
return false;
}
/// <summary>
/// In addition to ensuring that column widths are valid, this method updates the values of
/// VisibleEdgedColumnsWidth and VisibleStarColumnCount.
/// </summary>
internal void EnsureVisibleEdgedColumnsWidth()
{
this.VisibleStarColumnCount = 0;
this.VisibleEdgedColumnsWidth = 0;
for (int columnIndex = 0; columnIndex < this.ItemsInternal.Count; columnIndex++)
{
if (this.ItemsInternal[columnIndex].IsVisible)
{
this.ItemsInternal[columnIndex].EnsureWidth();
if (this.ItemsInternal[columnIndex].Width.IsStar)
{
this.VisibleStarColumnCount++;
}
this.VisibleEdgedColumnsWidth += this.ItemsInternal[columnIndex].ActualWidth;
}
}
}
internal DataGridColumn GetColumnAtDisplayIndex(int displayIndex)
{
if (displayIndex < 0 || displayIndex >= this.ItemsInternal.Count || displayIndex >= this.DisplayIndexMap.Count)
{
return null;
}
int columnIndex = this.DisplayIndexMap[displayIndex];
return this.ItemsInternal[columnIndex];
}
internal int GetColumnCount(bool isVisible, bool isFrozen, int fromColumnIndex, int toColumnIndex)
{
Debug.Assert(DisplayInOrder(fromColumnIndex, toColumnIndex), "Unexpected column display order.");
Debug.Assert(this.ItemsInternal[toColumnIndex].IsVisible == isVisible, "Unexpected column visibility state.");
Debug.Assert(this.ItemsInternal[toColumnIndex].IsFrozen == isFrozen, "Unexpected column frozen state.");
int columnCount = 0;
DataGridColumn dataGridColumn = this.ItemsInternal[fromColumnIndex];
while (dataGridColumn != this.ItemsInternal[toColumnIndex])
{
dataGridColumn = GetNextColumn(dataGridColumn, isVisible, isFrozen, null /*isReadOnly*/);
Debug.Assert(dataGridColumn != null, "Expected non-null dataGridColumn.");
columnCount++;
}
return columnCount;
}
internal IEnumerable<DataGridColumn> GetDisplayedColumns()
{
Debug.Assert(this.ItemsInternal.Count == this.DisplayIndexMap.Count, "Unexpected DisplayIndexMap.Count value.");
foreach (int columnIndex in this.DisplayIndexMap)
{
yield return this.ItemsInternal[columnIndex];
}
}
/// <summary>
/// Returns an enumeration of all columns that meet the criteria of the filter predicate.
/// </summary>
/// <param name="filter">Criteria for inclusion.</param>
/// <returns>Columns that meet the criteria, in ascending DisplayIndex order.</returns>
internal IEnumerable<DataGridColumn> GetDisplayedColumns(Predicate<DataGridColumn> filter)
{
Debug.Assert(filter != null, "Expected non-null filter.");
Debug.Assert(this.ItemsInternal.Count == this.DisplayIndexMap.Count, "Unexpected DisplayIndexMap.Count value.");
foreach (int columnIndex in this.DisplayIndexMap)
{
DataGridColumn column = this.ItemsInternal[columnIndex];
if (filter(column))
{
yield return column;
}
}
}
/// <summary>
/// Returns an enumeration of all columns that meet the criteria of the filter predicate.
/// The columns are returned in the order specified by the reverse flag.
/// </summary>
/// <param name="reverse">Whether or not to return the columns in descending DisplayIndex order.</param>
/// <param name="filter">Criteria for inclusion.</param>
/// <returns>Columns that meet the criteria, in the order specified by the reverse flag.</returns>
internal IEnumerable<DataGridColumn> GetDisplayedColumns(bool reverse, Predicate<DataGridColumn> filter)
{
return reverse ? GetDisplayedColumnsReverse(filter) : GetDisplayedColumns(filter);
}
/// <summary>
/// Returns an enumeration of all columns that meet the criteria of the filter predicate.
/// The columns are returned in descending DisplayIndex order.
/// </summary>
/// <param name="filter">Criteria for inclusion.</param>
/// <returns>Columns that meet the criteria, in descending DisplayIndex order.</returns>
internal IEnumerable<DataGridColumn> GetDisplayedColumnsReverse(Predicate<DataGridColumn> filter)
{
Debug.Assert(filter != null, "Expected non-null filter.");
Debug.Assert(this.ItemsInternal.Count == this.DisplayIndexMap.Count, "Unexpected DisplayIndexMap.Count value.");
for (int displayIndex = this.DisplayIndexMap.Count - 1; displayIndex >= 0; displayIndex--)
{
DataGridColumn column = this.ItemsInternal[this.DisplayIndexMap[displayIndex]];
if (filter(column))
{
yield return column;
}
}
}
internal DataGridColumn GetFirstColumn(bool? isVisible, bool? isFrozen, bool? isReadOnly)
{
Debug.Assert(this.ItemsInternal.Count == this.DisplayIndexMap.Count, "Unexpected DisplayIndexMap.Count value.");
int index = 0;
while (index < this.DisplayIndexMap.Count)
{
DataGridColumn dataGridColumn = GetColumnAtDisplayIndex(index);
if ((isVisible == null || dataGridColumn.IsVisible == isVisible) &&
(isFrozen == null || dataGridColumn.IsFrozen == isFrozen) &&
(isReadOnly == null || dataGridColumn.IsReadOnly == isReadOnly))
{
return dataGridColumn;
}
index++;
}
return null;
}
internal DataGridColumn GetLastColumn(bool? isVisible, bool? isFrozen, bool? isReadOnly)
{
Debug.Assert(this.ItemsInternal.Count == this.DisplayIndexMap.Count, "Unexpected DisplayIndexMap.Count value.");
int index = this.DisplayIndexMap.Count - 1;
while (index >= 0)
{
DataGridColumn dataGridColumn = GetColumnAtDisplayIndex(index);
if ((isVisible == null || dataGridColumn.IsVisible == isVisible) &&
(isFrozen == null || dataGridColumn.IsFrozen == isFrozen) &&
(isReadOnly == null || dataGridColumn.IsReadOnly == isReadOnly))
{
return dataGridColumn;
}
index--;
}
return null;
}
internal DataGridColumn GetNextColumn(DataGridColumn dataGridColumnStart)
{
return GetNextColumn(dataGridColumnStart, null /*isVisible*/, null /*isFrozen*/, null /*isReadOnly*/);
}
internal DataGridColumn GetNextColumn(
DataGridColumn dataGridColumnStart,
bool? isVisible,
bool? isFrozen,
bool? isReadOnly)
{
Debug.Assert(dataGridColumnStart != null, "Expected non-null dataGridColumnStart.");
Debug.Assert(this.ItemsInternal.Contains(dataGridColumnStart), "Expected dataGridColumnStart in ItemsInternal.");
Debug.Assert(this.ItemsInternal.Count == this.DisplayIndexMap.Count, "Unexpected DisplayIndexMap.Count value.");
int index = dataGridColumnStart.DisplayIndexWithFiller + 1;
while (index < this.DisplayIndexMap.Count)
{
DataGridColumn dataGridColumn = GetColumnAtDisplayIndex(index);
if ((isVisible == null || dataGridColumn.IsVisible == isVisible) &&
(isFrozen == null || dataGridColumn.IsFrozen == isFrozen) &&
(isReadOnly == null || dataGridColumn.IsReadOnly == isReadOnly))
{
return dataGridColumn;
}
index++;
}
return null;
}
internal DataGridColumn GetNextVisibleColumn(DataGridColumn dataGridColumnStart)
{
return GetNextColumn(dataGridColumnStart, true /*isVisible*/, null /*isFrozen*/, null /*isReadOnly*/);
}
internal DataGridColumn GetNextVisibleFrozenColumn(DataGridColumn dataGridColumnStart)
{
return GetNextColumn(dataGridColumnStart, true /*isVisible*/, true /*isFrozen*/, null /*isReadOnly*/);
}
internal DataGridColumn GetNextVisibleWritableColumn(DataGridColumn dataGridColumnStart)
{
return GetNextColumn(dataGridColumnStart, true /*isVisible*/, null /*isFrozen*/, false /*isReadOnly*/);
}
internal DataGridColumn GetPreviousColumn(
DataGridColumn dataGridColumnStart,
bool? isVisible,
bool? isFrozen,
bool? isReadOnly)
{
Debug.Assert(dataGridColumnStart != null, "Expected non-null dataGridColumnStart.");
Debug.Assert(this.ItemsInternal.Contains(dataGridColumnStart), "Expected dataGridColumnStart in ItemsInternal.");
Debug.Assert(this.ItemsInternal.Count == this.DisplayIndexMap.Count, "Unexpected DisplayIndexMap.Count value.");
int index = dataGridColumnStart.DisplayIndexWithFiller - 1;
while (index >= 0)
{
DataGridColumn dataGridColumn = GetColumnAtDisplayIndex(index);
if ((isVisible == null || dataGridColumn.IsVisible == isVisible) &&
(isFrozen == null || dataGridColumn.IsFrozen == isFrozen) &&
(isReadOnly == null || dataGridColumn.IsReadOnly == isReadOnly))
{
return dataGridColumn;
}
index--;
}
return null;
}
internal DataGridColumn GetPreviousVisibleNonFillerColumn(DataGridColumn dataGridColumnStart)
{
DataGridColumn column = GetPreviousColumn(dataGridColumnStart, true /*isVisible*/, null /*isFrozen*/, null /*isReadOnly*/);
return (column is DataGridFillerColumn) ? null : column;
}
internal DataGridColumn GetPreviousVisibleScrollingColumn(DataGridColumn dataGridColumnStart)
{
return GetPreviousColumn(dataGridColumnStart, true /*isVisible*/, false /*isFrozen*/, null /*isReadOnly*/);
}
internal DataGridColumn GetPreviousVisibleWritableColumn(DataGridColumn dataGridColumnStart)
{
return GetPreviousColumn(dataGridColumnStart, true /*isVisible*/, null /*isFrozen*/, false /*isReadOnly*/);
}
internal int GetVisibleColumnCount(int fromColumnIndex, int toColumnIndex)
{
Debug.Assert(DisplayInOrder(fromColumnIndex, toColumnIndex), "Unexpected column display order.");
Debug.Assert(this.ItemsInternal[toColumnIndex].IsVisible, "Unexpected column visibility state.");
int columnCount = 0;
DataGridColumn dataGridColumn = this.ItemsInternal[fromColumnIndex];
while (dataGridColumn != this.ItemsInternal[toColumnIndex])
{
dataGridColumn = GetNextVisibleColumn(dataGridColumn);
Debug.Assert(dataGridColumn != null, "Expected non-null dataGridColumn.");
columnCount++;
}
return columnCount;
}
internal IEnumerable<DataGridColumn> GetVisibleColumns()
{
Predicate<DataGridColumn> filter = column => column.IsVisible;
return GetDisplayedColumns(filter);
}
internal IEnumerable<DataGridColumn> GetVisibleFrozenColumns()
{
Predicate<DataGridColumn> filter = column => column.IsVisible && column.IsFrozen;
return GetDisplayedColumns(filter);
}
internal double GetVisibleFrozenEdgedColumnsWidth()
{
double visibleFrozenColumnsWidth = 0;
for (int columnIndex = 0; columnIndex < this.ItemsInternal.Count; columnIndex++)
{
if (this.ItemsInternal[columnIndex].IsVisible && this.ItemsInternal[columnIndex].IsFrozen)
{
visibleFrozenColumnsWidth += this.ItemsInternal[columnIndex].ActualWidth;
}
}
return visibleFrozenColumnsWidth;
}
internal IEnumerable<DataGridColumn> GetVisibleScrollingColumns()
{
Predicate<DataGridColumn> filter = column => column.IsVisible && !column.IsFrozen;
return GetDisplayedColumns(filter);
}
private void RemoveItemPrivate(int columnIndex, bool isSpacer)
{
Debug.Assert(_owningGrid != null, "Expected non-null owning DataGrid.");
try
{
_owningGrid.NoCurrentCellChangeCount++;
if (_owningGrid.InDisplayIndexAdjustments)
{
// We are within columns display indexes adjustments. We do not allow changing the column collection while adjusting display indexes.
throw DataGridError.DataGrid.CannotChangeColumnCollectionWhileAdjustingDisplayIndexes();
}
int columnIndexWithFiller = columnIndex;
if (!isSpacer && this.RowGroupSpacerColumn.IsRepresented)
{
columnIndexWithFiller++;
}
Debug.Assert(columnIndexWithFiller >= 0 && columnIndexWithFiller < this.ItemsInternal.Count, "Unexpected columnIndexWithFiller value.");
DataGridColumn dataGridColumn = this.ItemsInternal[columnIndexWithFiller];
DataGridCellCoordinates newCurrentCellCoordinates = _owningGrid.OnRemovingColumn(dataGridColumn);
this.ItemsInternal.RemoveAt(columnIndexWithFiller);
if (dataGridColumn.IsVisible)
{
this.VisibleEdgedColumnsWidth -= dataGridColumn.ActualWidth;
}
dataGridColumn.OwningGrid = null;
dataGridColumn.RemoveEditingElement();
// continue with the base remove
_owningGrid.OnRemovedColumn_PreNotification(dataGridColumn);
_owningGrid.OnColumnCollectionChanged_PreNotification(false /*columnsGrew*/);
if (!isSpacer)
{
base.RemoveItem(columnIndex);
}
_owningGrid.OnRemovedColumn_PostNotification(newCurrentCellCoordinates);
_owningGrid.OnColumnCollectionChanged_PostNotification(false /*columnsGrew*/);
}
finally
{
_owningGrid.NoCurrentCellChangeCount--;
}
}
#if DEBUG
internal bool Debug_VerifyColumnDisplayIndexes()
{
for (int columnDisplayIndex = 0; columnDisplayIndex < this.ItemsInternal.Count; columnDisplayIndex++)
{
if (GetColumnAtDisplayIndex(columnDisplayIndex) == null)
{
return false;
}
}
return true;
}
internal void Debug_PrintColumns()
{
foreach (DataGridColumn column in this.ItemsInternal)
{
Debug.WriteLine(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0} {1} {2}", column.Header, column.Index, column.DisplayIndex));
}
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides data for <see cref="DataGrid"/> column-related events.
/// </summary>
public class DataGridColumnEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridColumnEventArgs"/> class.
/// </summary>
/// <param name="column">The column that the event occurs for.</param>
public DataGridColumnEventArgs(DataGridColumn column)
{
if (column == null)
{
throw new ArgumentNullException("column");
}
this.Column = column;
}
/// <summary>
/// Gets the column that the event occurs for.
/// </summary>
public DataGridColumn Column
{
get;
private set;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,93 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.Foundation;
using Windows.UI.Core;
using Windows.UI.Xaml.Input;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Primitives
{
internal class DataGridColumnHeaderInteractionInfo
{
internal Pointer CapturedPointer
{
get;
set;
}
internal DataGridColumn DragColumn
{
get;
set;
}
internal DataGridColumnHeader.DragMode DragMode
{
get;
set;
}
internal uint DragPointerId
{
get;
set;
}
internal Point? DragStart
{
get;
set;
}
internal double FrozenColumnsWidth
{
get;
set;
}
internal bool HasUserInteraction
{
get
{
return this.DragMode != DataGridColumnHeader.DragMode.None;
}
}
internal Point? LastPointerPositionHeaders
{
get;
set;
}
internal CoreCursor OriginalCursor
{
get;
set;
}
internal double OriginalHorizontalOffset
{
get;
set;
}
internal double OriginalWidth
{
get;
set;
}
internal Point? PressedPointerPositionHeaders
{
get;
set;
}
internal uint ResizePointerId
{
get;
set;
}
}
}

Просмотреть файл

@ -0,0 +1,419 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Primitives
{
/// <summary>
/// Used within the template of a <see cref="DataGrid"/> to specify the
/// location in the control's visual tree where the column headers are to be added.
/// </summary>
public sealed class DataGridColumnHeadersPresenter : Panel
{
private Control _dragIndicator;
private Control _dropLocationIndicator;
/// <summary>
/// Gets or sets which column is currently being dragged.
/// </summary>
internal DataGridColumn DragColumn
{
get;
set;
}
/// <summary>
/// Gets or sets the current drag indicator control. This value is null if no column is being dragged.
/// </summary>
internal Control DragIndicator
{
get
{
return _dragIndicator;
}
set
{
if (value != _dragIndicator)
{
if (this.Children.Contains(_dragIndicator))
{
this.Children.Remove(_dragIndicator);
}
_dragIndicator = value;
if (_dragIndicator != null)
{
this.Children.Add(_dragIndicator);
}
}
}
}
/// <summary>
/// Gets or sets the distance, in pixels, that the DragIndicator should be positioned away from the corresponding DragColumn.
/// </summary>
internal double DragIndicatorOffset
{
get;
set;
}
/// <summary>
/// Gets or sets the drop location indicator control. This value is null if no column is being dragged.
/// </summary>
internal Control DropLocationIndicator
{
get
{
return _dropLocationIndicator;
}
set
{
if (value != _dropLocationIndicator)
{
if (this.Children.Contains(_dropLocationIndicator))
{
this.Children.Remove(_dropLocationIndicator);
}
_dropLocationIndicator = value;
if (_dropLocationIndicator != null)
{
this.Children.Add(_dropLocationIndicator);
}
}
}
}
/// <summary>
/// Gets or sets the distance, in pixels, that the drop location indicator should be positioned away from the left edge
/// of the ColumnsHeaderPresenter.
/// </summary>
internal double DropLocationIndicatorOffset
{
get;
set;
}
internal DataGrid OwningGrid
{
get;
set;
}
/// <summary>
/// Arranges the content of the <see cref="DataGridColumnHeadersPresenter"/>.
/// </summary>
/// <returns>
/// The actual size used by the <see cref="DataGridColumnHeadersPresenter"/>.
/// </returns>
/// <param name="finalSize">
/// The final area within the parent that this element should use to arrange itself and its children.
/// </param>
protected override Size ArrangeOverride(Size finalSize)
{
if (this.OwningGrid == null)
{
return base.ArrangeOverride(finalSize);
}
if (this.OwningGrid.AutoSizingColumns)
{
// When we initially load an auto-column, we have to wait for all the rows to be measured
// before we know its final desired size. We need to trigger a new round of measures now
// that the final sizes have been calculated.
this.OwningGrid.AutoSizingColumns = false;
return base.ArrangeOverride(finalSize);
}
double dragIndicatorLeftEdge = 0;
double frozenLeftEdge = 0;
double scrollingLeftEdge = -this.OwningGrid.HorizontalOffset;
foreach (DataGridColumn dataGridColumn in this.OwningGrid.ColumnsInternal.GetVisibleColumns())
{
DataGridColumnHeader columnHeader = dataGridColumn.HeaderCell;
Debug.Assert(columnHeader.OwningColumn == dataGridColumn, "Expected columnHeader owned by dataGridColumn.");
if (dataGridColumn.IsFrozen)
{
columnHeader.Arrange(new Rect(frozenLeftEdge, 0, dataGridColumn.LayoutRoundedWidth, finalSize.Height));
columnHeader.Clip = null; // The layout system could have clipped this because it's not aware of our render transform
if (this.DragColumn == dataGridColumn && this.DragIndicator != null)
{
dragIndicatorLeftEdge = frozenLeftEdge + this.DragIndicatorOffset;
}
frozenLeftEdge += dataGridColumn.ActualWidth;
}
else
{
columnHeader.Arrange(new Rect(scrollingLeftEdge, 0, dataGridColumn.LayoutRoundedWidth, finalSize.Height));
EnsureColumnHeaderClip(columnHeader, dataGridColumn.ActualWidth, finalSize.Height, frozenLeftEdge, scrollingLeftEdge);
if (this.DragColumn == dataGridColumn && this.DragIndicator != null)
{
dragIndicatorLeftEdge = scrollingLeftEdge + this.DragIndicatorOffset;
}
}
scrollingLeftEdge += dataGridColumn.ActualWidth;
}
if (this.DragColumn != null)
{
if (this.DragIndicator != null)
{
this.EnsureColumnReorderingClip(this.DragIndicator, finalSize.Height, frozenLeftEdge, dragIndicatorLeftEdge);
this.DragIndicator.Arrange(new Rect(dragIndicatorLeftEdge, 0, this.DragIndicator.ActualWidth, this.DragIndicator.ActualHeight));
}
if (this.DropLocationIndicator != null)
{
this.EnsureColumnReorderingClip(this.DropLocationIndicator, finalSize.Height, frozenLeftEdge, this.DropLocationIndicatorOffset);
this.DropLocationIndicator.Arrange(new Rect(this.DropLocationIndicatorOffset, 0, this.DropLocationIndicator.ActualWidth, this.DropLocationIndicator.ActualHeight));
}
}
// Arrange filler
this.OwningGrid.OnFillerColumnWidthNeeded(finalSize.Width);
DataGridFillerColumn fillerColumn = this.OwningGrid.ColumnsInternal.FillerColumn;
if (fillerColumn.FillerWidth > 0)
{
fillerColumn.HeaderCell.Visibility = Visibility.Visible;
fillerColumn.HeaderCell.Arrange(new Rect(scrollingLeftEdge, 0, fillerColumn.FillerWidth, finalSize.Height));
}
else
{
fillerColumn.HeaderCell.Visibility = Visibility.Collapsed;
}
// This needs to be updated after the filler column is configured
DataGridColumn lastVisibleColumn = this.OwningGrid.ColumnsInternal.LastVisibleColumn;
if (lastVisibleColumn != null)
{
lastVisibleColumn.HeaderCell.UpdateSeparatorVisibility(lastVisibleColumn);
}
return finalSize;
}
private static void EnsureColumnHeaderClip(DataGridColumnHeader columnHeader, double width, double height, double frozenLeftEdge, double columnHeaderLeftEdge)
{
// Clip the cell only if it's scrolled under frozen columns. Unfortunately, we need to clip in this case
// because cells could be transparent
if (frozenLeftEdge > columnHeaderLeftEdge)
{
RectangleGeometry rg = new RectangleGeometry();
double xClip = Math.Min(width, frozenLeftEdge - columnHeaderLeftEdge);
rg.Rect = new Rect(xClip, 0, width - xClip, height);
columnHeader.Clip = rg;
}
else
{
columnHeader.Clip = null;
}
}
/// <summary>
/// Clips the DragIndicator and DropLocationIndicator controls according to current ColumnHeaderPresenter constraints.
/// </summary>
/// <param name="control">The DragIndicator or DropLocationIndicator</param>
/// <param name="height">The available height</param>
/// <param name="frozenColumnsWidth">The width of the frozen column region</param>
/// <param name="controlLeftEdge">The left edge of the control to clip</param>
private void EnsureColumnReorderingClip(Control control, double height, double frozenColumnsWidth, double controlLeftEdge)
{
double leftEdge = 0;
double rightEdge = this.OwningGrid.CellsWidth;
double width = control.ActualWidth;
if (this.DragColumn.IsFrozen)
{
// If we're dragging a frozen column, we want to clip the corresponding DragIndicator control when it goes
// into the scrolling columns region, but not the DropLocationIndicator.
if (control == this.DragIndicator)
{
rightEdge = Math.Min(rightEdge, frozenColumnsWidth);
}
}
else if (this.OwningGrid.FrozenColumnCount > 0)
{
// If we're dragging a scrolling column, we want to clip both the DragIndicator and the DropLocationIndicator
// controls when they go into the frozen column range.
leftEdge = frozenColumnsWidth;
}
RectangleGeometry rg = null;
if (leftEdge > controlLeftEdge)
{
rg = new RectangleGeometry();
double xClip = Math.Min(width, leftEdge - controlLeftEdge);
rg.Rect = new Rect(xClip, 0, width - xClip, height);
}
if (controlLeftEdge + width >= rightEdge)
{
if (rg == null)
{
rg = new RectangleGeometry();
}
rg.Rect = new Rect(rg.Rect.X, rg.Rect.Y, Math.Max(0, rightEdge - controlLeftEdge - rg.Rect.X), height);
}
control.Clip = rg;
}
/// <summary>
/// Measures the children of a <see cref="DataGridColumnHeadersPresenter"/> to
/// prepare for arranging them during the <see cref="M:System.Windows.FrameworkElement.ArrangeOverride(System.Windows.Size)"/> pass.
/// </summary>
/// <param name="availableSize">
/// The available size that this element can give to child elements. Indicates an upper limit that child elements should not exceed.
/// </param>
/// <returns>
/// The size that the <see cref="DataGridColumnHeadersPresenter"/> determines it needs during layout, based on its calculations of child object allocated sizes.
/// </returns>
protected override Size MeasureOverride(Size availableSize)
{
if (this.OwningGrid == null)
{
return base.MeasureOverride(availableSize);
}
if (!this.OwningGrid.AreColumnHeadersVisible)
{
return new Size(0.0, 0.0);
}
double height = this.OwningGrid.ColumnHeaderHeight;
bool autoSizeHeight;
if (double.IsNaN(height))
{
// No explicit height values were set so we can autosize
height = 0;
autoSizeHeight = true;
}
else
{
autoSizeHeight = false;
}
double totalDisplayWidth = 0;
this.OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
DataGridColumn lastVisibleColumn = this.OwningGrid.ColumnsInternal.LastVisibleColumn;
foreach (DataGridColumn column in this.OwningGrid.ColumnsInternal.GetVisibleColumns())
{
// Measure each column header
bool autoGrowWidth = column.Width.IsAuto || column.Width.IsSizeToHeader;
DataGridColumnHeader columnHeader = column.HeaderCell;
if (column != lastVisibleColumn)
{
columnHeader.UpdateSeparatorVisibility(lastVisibleColumn);
}
// If we're not using star sizing or the current column can't be resized,
// then just set the display width according to the column's desired width
if (!this.OwningGrid.UsesStarSizing || (!column.ActualCanUserResize && !column.Width.IsStar))
{
// In the edge-case where we're given infinite width and we have star columns, the
// star columns grow to their predefined limit of 10,000 (or their MaxWidth)
double newDisplayWidth = column.Width.IsStar ?
Math.Min(column.ActualMaxWidth, DataGrid.DATAGRID_maximumStarColumnWidth) :
Math.Max(column.ActualMinWidth, Math.Min(column.ActualMaxWidth, column.Width.DesiredValue));
column.SetWidthDisplayValue(newDisplayWidth);
}
// If we're auto-growing the column based on the header content, we want to measure it at its maximum value
if (autoGrowWidth)
{
columnHeader.Measure(new Size(column.ActualMaxWidth, double.PositiveInfinity));
this.OwningGrid.AutoSizeColumn(column, columnHeader.DesiredSize.Width);
column.ComputeLayoutRoundedWidth(totalDisplayWidth);
}
else if (!this.OwningGrid.UsesStarSizing)
{
column.ComputeLayoutRoundedWidth(totalDisplayWidth);
columnHeader.Measure(new Size(column.LayoutRoundedWidth, double.PositiveInfinity));
}
// We need to track the largest height in order to auto-size
if (autoSizeHeight)
{
height = Math.Max(height, columnHeader.DesiredSize.Height);
}
totalDisplayWidth += column.ActualWidth;
}
// If we're using star sizing (and we're not waiting for an auto-column to finish growing)
// then we will resize all the columns to fit the available space.
if (this.OwningGrid.UsesStarSizing && !this.OwningGrid.AutoSizingColumns)
{
double adjustment = double.IsPositiveInfinity(availableSize.Width) ? this.OwningGrid.CellsWidth : availableSize.Width - totalDisplayWidth;
this.OwningGrid.AdjustColumnWidths(0, adjustment, false);
// Since we didn't know the final widths of the columns until we resized,
// we waited until now to measure each header
double leftEdge = 0;
foreach (var column in this.OwningGrid.ColumnsInternal.GetVisibleColumns())
{
column.ComputeLayoutRoundedWidth(leftEdge);
column.HeaderCell.Measure(new Size(column.LayoutRoundedWidth, double.PositiveInfinity));
if (autoSizeHeight)
{
height = Math.Max(height, column.HeaderCell.DesiredSize.Height);
}
leftEdge += column.ActualWidth;
}
}
// Add the filler column if it's not represented. We won't know whether we need it or not until Arrange
DataGridFillerColumn fillerColumn = this.OwningGrid.ColumnsInternal.FillerColumn;
if (!fillerColumn.IsRepresented)
{
Debug.Assert(!this.Children.Contains(fillerColumn.HeaderCell), "Unexpected parent for filler column header cell.");
fillerColumn.HeaderCell.SeparatorVisibility = Visibility.Collapsed;
this.Children.Insert(this.OwningGrid.ColumnsInternal.Count, fillerColumn.HeaderCell);
fillerColumn.IsRepresented = true;
// Optimize for the case where we don't need the filler cell
fillerColumn.HeaderCell.Visibility = Visibility.Collapsed;
}
fillerColumn.HeaderCell.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
if (this.DragIndicator != null)
{
this.DragIndicator.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
}
if (this.DropLocationIndicator != null)
{
this.DropLocationIndicator.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
}
this.OwningGrid.ColumnsInternal.EnsureVisibleEdgedColumnsWidth();
return new Size(this.OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth, height);
}
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="DataGridColumnHeadersPresenter"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new DataGridColumnHeadersPresenterAutomationPeer(this);
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides data for the <see cref="E:Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.ColumnReordering" /> event.
/// </summary>
public class DataGridColumnReorderingEventArgs : CancelEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridColumnReorderingEventArgs"/> class.
/// </summary>
/// <param name="dataGridColumn">The column that the event occurs for.</param>
public DataGridColumnReorderingEventArgs(DataGridColumn dataGridColumn)
{
this.Column = dataGridColumn;
}
/// <summary>
/// Gets the column being moved.
/// </summary>
public DataGridColumn Column
{
get;
private set;
}
/// <summary>
/// Gets or sets the popup indicator displayed while dragging. If null and Handled = true, then do not display a tooltip.
/// </summary>
public Control DragIndicator
{
get;
set;
}
/// <summary>
/// Gets or sets the Control to display at the insertion position. If null and Handled = true, then do not display an insertion indicator.
/// </summary>
public Control DropLocationIndicator
{
get;
set;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,738 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.UI.Utilities;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Represents a <see cref="DataGrid"/> column that hosts textual content in its cells. In edit mode data can be changed to a value from a collection hosted in a ComboBox.
/// </summary>
[StyleTypedProperty(Property = "ElementStyle", StyleTargetType = typeof(TextBlock))]
[StyleTypedProperty(Property = "EditingElementStyle", StyleTargetType = typeof(ComboBox))]
public class DataGridComboBoxColumn : DataGridBoundColumn
{
private const string DATAGRIDCOMBOBOXCOLUMN_fontFamilyName = "FontFamily";
private const string DATAGRIDCOMBOBOXCOLUMN_fontSizeName = "FontSize";
private const string DATAGRIDCOMBOBOXCOLUMN_fontStyleName = "FontStyle";
private const string DATAGRIDCOMBOBOXCOLUMN_fontWeightName = "FontWeight";
private const string DATAGRIDCOMBOBOXCOLUMN_foregroundName = "Foreground";
private const string DATAGRIDCOMBOBOXCOLUMN_itemsSourceName = "ItemsSource";
private const string DATAGRIDCOMBOBOXCOLUMN_displayMemberPathName = "DisplayMemberPath";
private const double DATAGRIDCOMBOBOXCOLUMN_leftMargin = 12.0;
private const double DATAGRIDCOMBOBOXCOLUMN_rightMargin = 12.0;
private double? _fontSize;
private DataGrid _owningGrid;
private FontStyle? _fontStyle;
private FontWeight? _fontWeight;
private Brush _foreground;
private HashSet<object> _notifyingDataItems;
/// <summary>
/// Identifies the ItemsSource dependency property.
/// </summary>
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register(
DATAGRIDCOMBOBOXCOLUMN_itemsSourceName,
typeof(IEnumerable),
typeof(DataGridComboBoxColumn),
new PropertyMetadata(default(IEnumerable), OnItemSourcePropertyChanged));
/// <summary>
/// Gets or sets a collection that is used to generate the content of the ComboBox while in editing mode.
/// </summary>
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
private static void OnItemSourcePropertyChanged(DependencyObject comboBoxDependencyObject, DependencyPropertyChangedEventArgs e)
{
var comboColumn = comboBoxDependencyObject as DataGridComboBoxColumn;
comboColumn.NotifyPropertyChanged(DATAGRIDCOMBOBOXCOLUMN_itemsSourceName);
}
/// <summary>
/// Identifies the DisplayMemberPath dependency property.
/// </summary>
public static readonly DependencyProperty DisplayMemberPathProperty =
DependencyProperty.Register(
DATAGRIDCOMBOBOXCOLUMN_displayMemberPathName,
typeof(string),
typeof(DataGridComboBoxColumn),
new PropertyMetadata(default(string)));
/// <summary>
/// Gets or sets the name or path of the property that is displayed in the ComboBox.
/// </summary>
public string DisplayMemberPath
{
get { return (string)GetValue(DisplayMemberPathProperty); }
set { SetValue(DisplayMemberPathProperty, value); }
}
/// <summary>
/// Gets or sets the font name.
/// </summary>
public FontFamily FontFamily
{
get { return (FontFamily)GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
}
/// <summary>
/// Identifies the FontFamily dependency property.
/// </summary>
public static readonly DependencyProperty FontFamilyProperty =
DependencyProperty.Register(
DATAGRIDCOMBOBOXCOLUMN_fontFamilyName,
typeof(FontFamily),
typeof(DataGridComboBoxColumn),
new PropertyMetadata(null, OnFontFamilyPropertyChanged));
private static void OnFontFamilyPropertyChanged(DependencyObject comboBoxColumnDependencyObject, DependencyPropertyChangedEventArgs e)
{
var comboColumn = comboBoxColumnDependencyObject as DataGridComboBoxColumn;
comboColumn.NotifyPropertyChanged(DATAGRIDCOMBOBOXCOLUMN_fontFamilyName);
}
/// <summary>
/// Gets or sets the font size.
/// </summary>
// Use DefaultValue here so undo in the Designer will set this to NaN
[DefaultValue(double.NaN)]
public double FontSize
{
get
{
return _fontSize ?? double.NaN;
}
set
{
if (_fontSize != value)
{
_fontSize = value;
NotifyPropertyChanged(DATAGRIDCOMBOBOXCOLUMN_fontSizeName);
}
}
}
/// <summary>
/// Gets or sets the font style.
/// </summary>
public FontStyle FontStyle
{
get
{
return _fontStyle ?? FontStyle.Normal;
}
set
{
if (_fontStyle != value)
{
_fontStyle = value;
NotifyPropertyChanged(DATAGRIDCOMBOBOXCOLUMN_fontStyleName);
}
}
}
/// <summary>
/// Gets or sets the font weight or thickness.
/// </summary>
public FontWeight FontWeight
{
get
{
return _fontWeight ?? FontWeights.Normal;
}
set
{
if (!_fontWeight.HasValue || _fontWeight.Value.Weight != value.Weight)
{
_fontWeight = value;
NotifyPropertyChanged(DATAGRIDCOMBOBOXCOLUMN_fontWeightName);
}
}
}
/// <summary>
/// Gets or sets a brush that describes the foreground of the column cells.
/// </summary>
public Brush Foreground
{
get
{
return _foreground;
}
set
{
if (_foreground != value)
{
_foreground = value;
NotifyPropertyChanged(DATAGRIDCOMBOBOXCOLUMN_foregroundName);
}
}
}
/// <summary>
/// Gets a <see cref="T:Windows.UI.Xaml.Controls.ComboBox"/> control that is bound to the column's ItemsSource collection.
/// </summary>
/// <param name="cell">The cell that will contain the generated element.</param>
/// <param name="dataItem">The data item represented by the row that contains the intended cell.</param>
/// <returns>A new <see cref="T:Windows.UI.Xaml.Controls.ComboBox"/> control that is bound to the column's ItemsSource collection.</returns>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
EnsureColumnBinding(dataItem);
EnsureDisplayMemberPathExists();
EnsureItemsSourceBinding();
EnsureColumnTypeAgreement(dataItem);
var comboBox = new ComboBox
{
Margin = default(Thickness),
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Center
};
if (dataItem != null)
{
var value = TypeHelper.GetNestedPropertyValue(dataItem, Binding.Path.Path);
var selection = !string.IsNullOrEmpty(DisplayMemberPath)
? ItemsSource?.Cast<object>().FirstOrDefault(x => TypeHelper.GetNestedPropertyValue(x, Binding.GetBindingPropertyName()).Equals(value))
: ItemsSource?.Cast<object>().FirstOrDefault(x => x.Equals(value));
comboBox.SelectedItem = selection;
}
var itemsSourceBinding = new Binding
{
Source = this,
Path = new PropertyPath(DATAGRIDCOMBOBOXCOLUMN_itemsSourceName)
};
var displayMemberPathBinding = new Binding
{
Source = this,
Path = new PropertyPath(DATAGRIDCOMBOBOXCOLUMN_displayMemberPathName)
};
comboBox.SetBinding(ComboBox.ItemsSourceProperty, itemsSourceBinding);
comboBox.SetBinding(ComboBox.DisplayMemberPathProperty, displayMemberPathBinding);
if (DependencyProperty.UnsetValue != ReadLocalValue(DataGridComboBoxColumn.FontFamilyProperty))
{
comboBox.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
comboBox.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
comboBox.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
comboBox.FontWeight = _fontWeight.Value;
}
RefreshForeground(comboBox, (cell != null & cell.OwningRow != null) ? cell.OwningRow.ComputedForeground : null);
comboBox.SelectionChanged += (sender, args) =>
{
var item = args.AddedItems.FirstOrDefault();
if (item != null)
{
var newValue = !string.IsNullOrEmpty(DisplayMemberPath)
? item.GetType().GetProperty(Binding.GetBindingPropertyName())?.GetValue(item)
: item;
TypeHelper.SetNestedPropertyValue(ref dataItem, newValue, Binding.Path.Path);
}
};
return comboBox;
}
/// <summary>
/// Gets a read-only <see cref="T:Windows.UI.Xaml.Controls.TextBlock"/> element that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </summary>
/// <param name="cell">The cell that will contain the generated element.</param>
/// <param name="dataItem">The data item represented by the row that contains the intended cell.</param>
/// <returns>A new, read-only <see cref="T:Windows.UI.Xaml.Controls.TextBlock"/> element that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.</returns>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
EnsureColumnBinding(dataItem);
EnsureColumnTypeAgreement(dataItem);
EnsureDisplayMemberPathExists();
EnsureItemsSourceBinding();
var textBlockElement = new TextBlock
{
Margin = new Thickness(DATAGRIDCOMBOBOXCOLUMN_leftMargin, 0.0, DATAGRIDCOMBOBOXCOLUMN_rightMargin, 0.0),
VerticalAlignment = VerticalAlignment.Center
};
if (DependencyProperty.UnsetValue != ReadLocalValue(DataGridComboBoxColumn.FontFamilyProperty))
{
textBlockElement.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
textBlockElement.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBlockElement.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBlockElement.FontWeight = _fontWeight.Value;
}
RefreshForeground(textBlockElement, (cell != null & cell.OwningRow != null) ? cell.OwningRow.ComputedForeground : null);
if (Binding != null && EnsureOwningGrid())
{
if (string.IsNullOrEmpty(DisplayMemberPath))
{
textBlockElement.SetBinding(TextBlock.TextProperty, Binding);
}
else
{
textBlockElement.Text = GetDisplayValue(dataItem);
HookDataItemPropertyChanged(dataItem);
}
}
return textBlockElement;
}
/// <summary>
/// Causes the column cell being edited to revert to the specified value.
/// </summary>
/// <param name="editingElement">The element that the column displays for a cell in editing mode.</param>
/// <param name="uneditedValue">The previous, unedited value in the cell being edited.</param>
protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
{
var comboBox = editingElement as ComboBox;
if (comboBox != null)
{
if (uneditedValue != null)
{
var property = uneditedValue.GetType().GetNestedProperty(Binding.GetBindingPropertyName());
if (property == null)
{
comboBox.SelectedItem = uneditedValue;
}
else
{
var value = TypeHelper.GetNestedPropertyValue(uneditedValue, Binding.GetBindingPropertyName());
var selection = ItemsSource?.Cast<object>().FirstOrDefault(x => TypeHelper.GetNestedPropertyValue(x, Binding.GetBindingPropertyName()).Equals(value));
comboBox.SelectedItem = selection;
}
}
else
{
comboBox.SelectedItem = null;
}
}
}
/// <summary>
/// Called when the cell in the column enters editing mode.
/// </summary>
/// <param name="editingElement">The element that the column displays for a cell in editing mode.</param>
/// <param name="editingEventArgs">Information about the user gesture that is causing a cell to enter editing mode.</param>
/// <returns>The unedited value. </returns>
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
return (editingElement as ComboBox)?.SelectedItem;
}
/// <summary>
/// Called by the DataGrid control when this column asks for its elements to be updated, because a property changed.
/// </summary>
protected internal override void RefreshCellContent(FrameworkElement element, Brush computedRowForeground, string propertyName)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
var comboBox = element as ComboBox;
if (comboBox == null)
{
var textBlock = element as TextBlock;
if (textBlock == null)
{
throw DataGridError.DataGrid.ValueIsNotAnInstanceOfEitherOr(nameof(element), typeof(ComboBox), typeof(TextBlock));
}
if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontFamilyName)
{
textBlock.FontFamily = FontFamily;
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontSizeName)
{
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontStyleName)
{
textBlock.FontStyle = FontStyle;
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontWeightName)
{
textBlock.FontWeight = FontWeight;
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_foregroundName)
{
RefreshForeground(textBlock, computedRowForeground);
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_itemsSourceName)
{
OwningGrid.OnColumnBindingChanged(this);
}
else
{
if (FontFamily != null)
{
textBlock.FontFamily = FontFamily;
}
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
textBlock.FontStyle = FontStyle;
textBlock.FontWeight = FontWeight;
RefreshForeground(textBlock, computedRowForeground);
}
return;
}
if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontFamilyName)
{
comboBox.FontFamily = FontFamily;
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontSizeName)
{
SetTextFontSize(comboBox, ComboBox.FontSizeProperty);
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontStyleName)
{
comboBox.FontStyle = FontStyle;
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_fontWeightName)
{
comboBox.FontWeight = FontWeight;
}
else if (propertyName == DATAGRIDCOMBOBOXCOLUMN_foregroundName)
{
RefreshForeground(comboBox, computedRowForeground);
}
else
{
if (FontFamily != null)
{
comboBox.FontFamily = FontFamily;
}
SetTextFontSize(comboBox, ComboBox.FontSizeProperty);
comboBox.FontStyle = FontStyle;
comboBox.FontWeight = FontWeight;
RefreshForeground(comboBox, computedRowForeground);
}
}
/// <summary>
/// Called when the computed foreground of a row changed.
/// </summary>
protected internal override void RefreshForeground(FrameworkElement element, Brush computedRowForeground)
{
if (element is ComboBox comboBox)
{
RefreshForeground(comboBox, computedRowForeground);
}
else if (element is TextBlock textBlock)
{
RefreshForeground(textBlock, computedRowForeground);
}
}
private void RefreshForeground(ComboBox comboBox, Brush computedRowForeground)
{
if (Foreground == null)
{
if (computedRowForeground != null)
{
comboBox.Foreground = computedRowForeground;
}
}
else
{
comboBox.Foreground = Foreground;
}
}
private void RefreshForeground(TextBlock textBlock, Brush computedRowForeground)
{
if (Foreground == null)
{
if (computedRowForeground != null)
{
textBlock.Foreground = computedRowForeground;
}
}
else
{
textBlock.Foreground = Foreground;
}
}
private void SetTextFontSize(DependencyObject textElement, DependencyProperty fontSizeProperty)
{
double newFontSize = FontSize;
if (double.IsNaN(newFontSize))
{
textElement.ClearValue(fontSizeProperty);
}
else
{
textElement.SetValue(fontSizeProperty, newFontSize);
}
}
private bool EnsureOwningGrid()
{
if (OwningGrid != null)
{
if (OwningGrid != _owningGrid)
{
_owningGrid = OwningGrid;
_owningGrid.Columns.CollectionChanged += new NotifyCollectionChangedEventHandler(Columns_CollectionChanged);
_owningGrid.LoadingRow += OwningGrid_LoadingRow;
_owningGrid.UnloadingRow += OwningGrid_UnloadingRow;
_owningGrid.CellEditEnded += OwningGrid_CellEditEnded;
}
return true;
}
return false;
}
private void OwningGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
HookDataItemPropertyChanged(e.Row.DataContext);
SetDisplayMemberPathValue(e.Row);
}
private void OwningGrid_UnloadingRow(object sender, DataGridRowEventArgs e)
{
UnhookDataItemPropertyChanged(e.Row.DataContext);
}
private void OwningGrid_CellEditEnded(object sender, DataGridCellEditEndedEventArgs e)
{
SetDisplayMemberPathValue(e.Row);
}
private void Columns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (OwningGrid == null && _owningGrid != null)
{
_notifyingDataItems?.Clear();
_owningGrid.Columns.CollectionChanged -= new NotifyCollectionChangedEventHandler(Columns_CollectionChanged);
_owningGrid.LoadingRow -= OwningGrid_LoadingRow;
_owningGrid.UnloadingRow -= this.OwningGrid_UnloadingRow;
_owningGrid.CellEditEnded -= OwningGrid_CellEditEnded;
_owningGrid = null;
}
}
private void SetDisplayMemberPathValue(DataGridRow row)
{
if (OwningGrid != null && !string.IsNullOrEmpty(DisplayMemberPath))
{
var textBlock = GetCellContent(row) as TextBlock;
if (textBlock != null)
{
var displayValue = GetDisplayValue(row.DataContext);
textBlock.Text = displayValue;
}
}
}
private string GetDisplayValue(object dataItem)
{
if (Binding?.Path != null && dataItem != null)
{
var value = TypeHelper.GetNestedPropertyValue(dataItem, Binding.Path.Path);
var item = ItemsSource?.Cast<object>().FirstOrDefault(x => TypeHelper.GetNestedPropertyValue(x, Binding.GetBindingPropertyName()).Equals(value));
var displayValue = item?.GetType().GetProperty(DisplayMemberPath).GetValue(item) ?? string.Empty;
return displayValue as string ?? displayValue.ToString();
}
return string.Empty;
}
private void EnsureColumnBinding(object dataItem)
{
if (Binding?.Path == null)
{
if (!string.IsNullOrEmpty(Header as string))
{
throw DataGridError.DataGridComboBoxColumn.UnsetBinding(Header as string);
}
throw DataGridError.DataGridComboBoxColumn.UnsetBinding(GetType());
}
var property = dataItem?.GetType().GetNestedProperty(Binding?.Path?.Path);
if (property == null && dataItem != null)
{
throw DataGridError.DataGridComboBoxColumn.UnknownBindingPath(Binding, dataItem?.GetType());
}
}
private void EnsureColumnTypeAgreement(object dataItem)
{
if (string.IsNullOrEmpty(DisplayMemberPath))
{
var itemsSourceType = ItemsSource?.GetType().GetEnumerableItemType();
var dataItemType = dataItem?.GetType().GetNestedPropertyType(Binding?.Path?.Path);
if (dataItemType != null && itemsSourceType != null && itemsSourceType != dataItemType)
{
throw DataGridError.DataGridComboBoxColumn.BindingTypeMismatch(dataItemType, itemsSourceType);
}
}
}
private void EnsureDisplayMemberPathExists()
{
if (!string.IsNullOrEmpty(DisplayMemberPath))
{
var type = ItemsSource?.GetItemType();
if (ItemsSource != null && !type.GetProperties().Any(x => x.Name.Equals(DisplayMemberPath)))
{
throw DataGridError.DataGridComboBoxColumn.UnknownDisplayMemberPath(DisplayMemberPath, type);
}
}
}
private void EnsureItemsSourceBinding()
{
if (!string.IsNullOrEmpty(DisplayMemberPath) && ItemsSource != null)
{
var item = ItemsSource.Cast<object>().FirstOrDefault();
if (item != null && !item.GetType().GetProperties().Any(y => y.Name.Equals(Binding.GetBindingPropertyName())))
{
throw DataGridError.DataGridComboBoxColumn.UnknownItemsSourcePath(Binding);
}
}
}
private void HookDataItemPropertyChanged(object dataItem)
{
if (Binding.Mode == BindingMode.OneTime)
{
return;
}
var notifyingDataItem = dataItem as INotifyPropertyChanged;
if (notifyingDataItem == null)
{
return;
}
if (_notifyingDataItems == null)
{
_notifyingDataItems = new HashSet<object>();
}
if (!_notifyingDataItems.Contains(dataItem))
{
notifyingDataItem.PropertyChanged += DataItem_PropertyChanged;
_notifyingDataItems.Add(dataItem);
}
}
private void UnhookDataItemPropertyChanged(object dataItem)
{
if (_notifyingDataItems == null)
{
return;
}
var notifyingDataItem = dataItem as INotifyPropertyChanged;
if (notifyingDataItem == null)
{
return;
}
if (_notifyingDataItems.Contains(dataItem))
{
notifyingDataItem.PropertyChanged -= DataItem_PropertyChanged;
_notifyingDataItems.Remove(dataItem);
}
}
private void DataItem_PropertyChanged(object dataItem, PropertyChangedEventArgs e)
{
if (this.OwningGrid != null && Binding?.Path != null && this.Binding.Path.Path == e.PropertyName)
{
var dataGridRow = OwningGrid.GetRowFromItem(dataItem);
if (dataGridRow != null && this.GetCellContent(dataGridRow) is TextBlock textBlockElement)
{
textBlockElement.Text = GetDisplayValue(dataItem);
}
}
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,171 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Primitives
{
/// <summary>
/// Used within the template of a <see cref="DataGrid"/> to specify the location in the control's visual tree
/// where the row details are to be added.
/// </summary>
public sealed class DataGridDetailsPresenter : Panel
{
/// <summary>
/// Gets or sets the height of the content.
/// </summary>
/// <returns>
/// The height of the content.
/// </returns>
public double ContentHeight
{
get { return (double)GetValue(ContentHeightProperty); }
set { SetValue(ContentHeightProperty, value); }
}
/// <summary>
/// Identifies the ContentHeight dependency property.
/// </summary>
public static readonly DependencyProperty ContentHeightProperty =
DependencyProperty.Register(
"ContentHeight",
typeof(double),
typeof(DataGridDetailsPresenter),
new PropertyMetadata(0.0, OnContentHeightPropertyChanged));
/// <summary>
/// ContentHeightProperty property changed handler.
/// </summary>
/// <param name="d">DataGridDetailsPresenter.</param>
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
private static void OnContentHeightPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridDetailsPresenter detailsPresenter = d as DataGridDetailsPresenter;
detailsPresenter.InvalidateMeasure();
}
private DataGrid OwningGrid
{
get
{
if (this.OwningRow != null)
{
return this.OwningRow.OwningGrid;
}
return null;
}
}
internal DataGridRow OwningRow
{
get;
set;
}
/// <summary>
/// Arranges the content of the <see cref="T:System.Windows.Controls.Primitives.DataGridDetailsPresenter"/>.
/// </summary>
/// <returns>
/// The actual size used by the <see cref="T:System.Windows.Controls.Primitives.DataGridDetailsPresenter"/>.
/// </returns>
/// <param name="finalSize">
/// The final area within the parent that this element should use to arrange itself and its children.
/// </param>
protected override Size ArrangeOverride(Size finalSize)
{
if (this.OwningGrid == null)
{
return base.ArrangeOverride(finalSize);
}
double rowGroupSpacerWidth = this.OwningGrid.ColumnsInternal.RowGroupSpacerColumn.Width.Value;
double xClip = this.OwningGrid.AreRowGroupHeadersFrozen ? rowGroupSpacerWidth : 0;
double leftEdge = rowGroupSpacerWidth;
double width;
if (this.OwningGrid.AreRowDetailsFrozen)
{
leftEdge += this.OwningGrid.HorizontalOffset;
width = this.OwningGrid.CellsWidth;
}
else
{
xClip += this.OwningGrid.HorizontalOffset;
width = Math.Max(this.OwningGrid.CellsWidth, this.OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth);
}
// Details should not extend through the indented area
width -= rowGroupSpacerWidth;
double height = Math.Max(0, double.IsNaN(this.ContentHeight) ? 0 : this.ContentHeight);
foreach (UIElement child in this.Children)
{
child.Arrange(new Rect(leftEdge, 0, width, height));
}
if (this.OwningGrid.AreRowDetailsFrozen)
{
// Frozen Details should not be clipped, similar to frozen cells
this.Clip = null;
}
else
{
// Clip so Details doesn't obstruct elements to the left (the RowHeader by default) as we scroll to the right
RectangleGeometry rg = new RectangleGeometry();
rg.Rect = new Rect(xClip, 0, Math.Max(0, width - xClip + rowGroupSpacerWidth), height);
this.Clip = rg;
}
return finalSize;
}
/// <summary>
/// Measures the children of a <see cref="T:System.Windows.Controls.Primitives.DataGridDetailsPresenter"/> to
/// prepare for arranging them during the <see cref="M:System.Windows.FrameworkElement.ArrangeOverride(System.Windows.Size)"/> pass.
/// </summary>
/// <param name="availableSize">
/// The available size that this element can give to child elements. Indicates an upper limit that child elements should not exceed.
/// </param>
/// <returns>
/// The size that the <see cref="T:System.Windows.Controls.Primitives.DataGridDetailsPresenter"/> determines it needs during layout, based on its calculations of child object allocated sizes.
/// </returns>
protected override Size MeasureOverride(Size availableSize)
{
if (this.OwningGrid == null || this.Children.Count == 0)
{
return new Size(0.0, 0.0);
}
double desiredWidth = this.OwningGrid.AreRowDetailsFrozen ?
this.OwningGrid.CellsWidth :
Math.Max(this.OwningGrid.CellsWidth, this.OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth);
desiredWidth -= this.OwningGrid.ColumnsInternal.RowGroupSpacerColumn.Width.Value;
foreach (UIElement child in this.Children)
{
child.Measure(new Size(desiredWidth, double.PositiveInfinity));
}
double desiredHeight = Math.Max(0, double.IsNaN(this.ContentHeight) ? 0 : this.ContentHeight);
return new Size(desiredWidth, desiredHeight);
}
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="T:System.Windows.Controls.Primitives.DataGridDetailsPresenter"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new DataGridDetailsPresenterAutomationPeer(this);
}
}
}

Просмотреть файл

@ -0,0 +1,391 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals
{
internal class DataGridDisplayData
{
private Stack<DataGridRow> _fullyRecycledRows; // list of Rows that have been fully recycled (Collapsed)
private int _headScrollingElements; // index of the row in _scrollingRows that is the first displayed row
private DataGrid _owner;
private Stack<DataGridRow> _recyclableRows; // list of Rows which have not been fully recycled (avoids Measure in several cases)
private List<UIElement> _scrollingElements; // circular list of displayed elements
private Stack<DataGridRowGroupHeader> _fullyRecycledGroupHeaders; // list of GroupHeaders that have been fully recycled (Collapsed)
private Stack<DataGridRowGroupHeader> _recyclableGroupHeaders; // list of GroupHeaders which have not been fully recycled (avoids Measure in several cases)
public DataGridDisplayData(DataGrid owner)
{
_owner = owner;
ResetSlotIndexes();
this.FirstDisplayedScrollingCol = -1;
this.LastTotallyDisplayedScrollingCol = -1;
_scrollingElements = new List<UIElement>();
_recyclableRows = new Stack<DataGridRow>();
_fullyRecycledRows = new Stack<DataGridRow>();
_recyclableGroupHeaders = new Stack<DataGridRowGroupHeader>();
_fullyRecycledGroupHeaders = new Stack<DataGridRowGroupHeader>();
}
public int FirstDisplayedScrollingCol
{
get;
set;
}
public int FirstScrollingSlot
{
get;
set;
}
public int LastScrollingSlot
{
get;
set;
}
public int LastTotallyDisplayedScrollingCol
{
get;
set;
}
public int NumDisplayedScrollingElements
{
get
{
return _scrollingElements.Count;
}
}
public int NumTotallyDisplayedScrollingElements
{
get;
set;
}
internal double PendingVerticalScrollHeight
{
get;
set;
}
internal void AddRecylableRow(DataGridRow row)
{
Debug.Assert(!_recyclableRows.Contains(row), "Expected row parameter to be non-recyclable.");
row.DetachFromDataGrid(true);
_recyclableRows.Push(row);
}
internal void AddRecylableRowGroupHeader(DataGridRowGroupHeader groupHeader)
{
Debug.Assert(!_recyclableGroupHeaders.Contains(groupHeader), "Expected groupHeader parameter to be non-recyclable.");
groupHeader.PropertyName = null;
groupHeader.PropertyValue = null;
groupHeader.IsRecycled = true;
_recyclableGroupHeaders.Push(groupHeader);
}
internal void ClearElements(bool recycle)
{
ResetSlotIndexes();
if (recycle)
{
foreach (UIElement element in _scrollingElements)
{
DataGridRow row = element as DataGridRow;
if (row != null)
{
if (row.IsRecyclable)
{
AddRecylableRow(row);
}
else
{
row.Clip = new RectangleGeometry();
}
}
else
{
DataGridRowGroupHeader groupHeader = element as DataGridRowGroupHeader;
if (groupHeader != null)
{
AddRecylableRowGroupHeader(groupHeader);
}
}
}
}
else
{
_recyclableRows.Clear();
_fullyRecycledRows.Clear();
_recyclableGroupHeaders.Clear();
_fullyRecycledGroupHeaders.Clear();
}
_scrollingElements.Clear();
}
internal void CorrectSlotsAfterDeletion(int slot, bool wasCollapsed)
{
if (wasCollapsed)
{
if (slot > this.FirstScrollingSlot)
{
this.LastScrollingSlot--;
}
}
else if (_owner.IsSlotVisible(slot))
{
UnloadScrollingElement(slot, true /*updateSlotInformation*/, true /*wasDeleted*/);
}
// This cannot be an else condition because if there are 2 rows left, and you delete the first one
// then these indexes need to be updated as well
if (slot < this.FirstScrollingSlot)
{
this.FirstScrollingSlot--;
this.LastScrollingSlot--;
}
}
internal void CorrectSlotsAfterInsertion(int slot, UIElement element, bool isCollapsed)
{
if (slot < this.FirstScrollingSlot)
{
// The row was inserted above our viewport, just update our indexes
this.FirstScrollingSlot++;
this.LastScrollingSlot++;
}
else if (isCollapsed && (slot <= this.LastScrollingSlot))
{
this.LastScrollingSlot++;
}
else if ((_owner.GetPreviousVisibleSlot(slot) <= this.LastScrollingSlot) || (this.LastScrollingSlot == -1))
{
Debug.Assert(element != null, "Expected non-null element.");
// The row was inserted in our viewport, add it as a scrolling row
LoadScrollingSlot(slot, element, true /*updateSlotInformation*/);
}
}
private int GetCircularListIndex(int slot, bool wrap)
{
int index = slot - this.FirstScrollingSlot - _headScrollingElements - _owner.GetCollapsedSlotCount(this.FirstScrollingSlot, slot);
return wrap ? index % _scrollingElements.Count : index;
}
internal void FullyRecycleElements()
{
// Fully recycle Recycleable rows and transfer them to Recycled rows
while (_recyclableRows.Count > 0)
{
DataGridRow row = _recyclableRows.Pop();
Debug.Assert(row != null, "Expected non-null row.");
row.Visibility = Visibility.Collapsed;
Debug.Assert(!_fullyRecycledRows.Contains(row), "Expected row not in _fullyRecycledRows.");
_fullyRecycledRows.Push(row);
}
// Fully recycle recyclable GroupHeaders and transfer them to Recycled GroupHeaders
while (_recyclableGroupHeaders.Count > 0)
{
DataGridRowGroupHeader groupHeader = _recyclableGroupHeaders.Pop();
Debug.Assert(groupHeader != null, "Expected non-null groupHeader.");
groupHeader.Visibility = Visibility.Collapsed;
Debug.Assert(!_fullyRecycledGroupHeaders.Contains(groupHeader), "Expected groupHeader not in _fullyRecycledGroupHeaders.");
_fullyRecycledGroupHeaders.Push(groupHeader);
}
}
internal UIElement GetDisplayedElement(int slot)
{
Debug.Assert(slot >= this.FirstScrollingSlot, "Expected slot greater than or equal to FirstScrollingSlot.");
Debug.Assert(slot <= this.LastScrollingSlot, "Expected slot less than or equal to LastScrollingSlot.");
return _scrollingElements[GetCircularListIndex(slot, true /*wrap*/)];
}
internal DataGridRow GetDisplayedRow(int rowIndex)
{
return GetDisplayedElement(_owner.SlotFromRowIndex(rowIndex)) as DataGridRow;
}
// Returns an enumeration of the displayed scrolling rows in order starting with the FirstDisplayedScrollingRow
// Only DataGridRow instances are returned when onlyRows = true
internal IEnumerable<UIElement> GetScrollingElements(bool onlyRows = false)
{
for (int i = 0; i < _scrollingElements.Count; i++)
{
UIElement element = _scrollingElements[(_headScrollingElements + i) % _scrollingElements.Count];
if (!onlyRows || element is DataGridRow)
{
// _scrollingRows is a circular list that wraps
yield return element;
}
}
}
internal DataGridRowGroupHeader GetUsedGroupHeader()
{
if (_recyclableGroupHeaders.Count > 0)
{
return _recyclableGroupHeaders.Pop();
}
else if (_fullyRecycledGroupHeaders.Count > 0)
{
// For fully recycled rows, we need to set the Visibility back to Visible
DataGridRowGroupHeader groupHeader = _fullyRecycledGroupHeaders.Pop();
groupHeader.Visibility = Visibility.Visible;
return groupHeader;
}
return null;
}
internal DataGridRow GetUsedRow()
{
if (_recyclableRows.Count > 0)
{
return _recyclableRows.Pop();
}
else if (_fullyRecycledRows.Count > 0)
{
// For fully recycled rows, we need to set the Visibility back to Visible
DataGridRow row = _fullyRecycledRows.Pop();
row.Visibility = Visibility.Visible;
return row;
}
return null;
}
// Tracks the row at index rowIndex as a scrolling row
internal void LoadScrollingSlot(int slot, UIElement element, bool updateSlotInformation)
{
if (_scrollingElements.Count == 0)
{
SetScrollingSlots(slot);
_scrollingElements.Add(element);
}
else
{
// The slot should be adjacent to the other slots being displayed
Debug.Assert(slot >= _owner.GetPreviousVisibleSlot(this.FirstScrollingSlot), "Expected slot greater than or equal to _owner.GetPreviousVisibleSlot(this.FirstScrollingSlot).");
Debug.Assert(slot <= _owner.GetNextVisibleSlot(this.LastScrollingSlot), "Expected slot smaller than or equal to _owner.GetNextVisibleSlot(this.LastScrollingSlot).");
if (updateSlotInformation)
{
if (slot < this.FirstScrollingSlot)
{
this.FirstScrollingSlot = slot;
}
else
{
this.LastScrollingSlot = _owner.GetNextVisibleSlot(this.LastScrollingSlot);
}
}
int insertIndex = GetCircularListIndex(slot, false /*wrap*/);
if (insertIndex > _scrollingElements.Count)
{
// We need to wrap around from the bottom to the top of our circular list; as a result the head of the list moves forward
insertIndex -= _scrollingElements.Count;
_headScrollingElements++;
}
_scrollingElements.Insert(insertIndex, element);
}
}
private void ResetSlotIndexes()
{
SetScrollingSlots(-1);
this.NumTotallyDisplayedScrollingElements = 0;
_headScrollingElements = 0;
}
private void SetScrollingSlots(int newValue)
{
this.FirstScrollingSlot = newValue;
this.LastScrollingSlot = newValue;
}
// Stops tracking the element at the given slot as a scrolling element
internal void UnloadScrollingElement(int slot, bool updateSlotInformation, bool wasDeleted)
{
Debug.Assert(_owner.IsSlotVisible(slot), "Expected slot is visible.");
int elementIndex = GetCircularListIndex(slot, false /*wrap*/);
if (elementIndex > _scrollingElements.Count)
{
// We need to wrap around from the top to the bottom of our circular list
elementIndex -= _scrollingElements.Count;
_headScrollingElements--;
}
_scrollingElements.RemoveAt(elementIndex);
if (updateSlotInformation)
{
if (slot == this.FirstScrollingSlot && !wasDeleted)
{
this.FirstScrollingSlot = _owner.GetNextVisibleSlot(this.FirstScrollingSlot);
}
else
{
this.LastScrollingSlot = _owner.GetPreviousVisibleSlot(this.LastScrollingSlot);
}
if (this.LastScrollingSlot < this.FirstScrollingSlot)
{
ResetSlotIndexes();
}
}
}
#if DEBUG
internal void PrintDisplay()
{
foreach (UIElement element in this.GetScrollingElements())
{
DataGridRow row = element as DataGridRow;
if (row != null)
{
Debug.WriteLine(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Slot: {0} Row: {1} ", row.Slot, row.Index));
}
else
{
DataGridRowGroupHeader groupHeader = element as DataGridRowGroupHeader;
if (groupHeader != null)
{
#if FEATURE_ICOLLECTIONVIEW_GROUP
Debug.WriteLine(string.Format(
System.Globalization.CultureInfo.InvariantCulture,
"Slot: {0} GroupHeader: {1}",
groupHeader.RowGroupInfo.Slot,
groupHeader.RowGroupInfo.CollectionViewGroup.Name));
#else
Debug.WriteLine(string.Format(
System.Globalization.CultureInfo.InvariantCulture,
"Slot: {0} GroupHeader: {1}",
groupHeader.RowGroupInfo.Slot,
groupHeader.RowGroupInfo.ToString()));
#endif
}
}
}
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,190 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Defines modes that indicates how DataGrid content is copied to the Clipboard.
/// </summary>
public enum DataGridClipboardCopyMode
{
/// <summary>
/// Disable the DataGrid's ability to copy selected items as text.
/// </summary>
None,
/// <summary>
/// Enable the DataGrid's ability to copy selected items as text, but do not include
/// the column header content as the first line in the text that gets copied to the Clipboard.
/// </summary>
ExcludeHeader,
/// <summary>
/// Enable the DataGrid's ability to copy selected items as text, and include
/// the column header content as the first line in the text that gets copied to the Clipboard.
/// </summary>
IncludeHeader
}
/// <summary>
/// Used to specify action to take out of edit mode.
/// </summary>
public enum DataGridEditAction
{
/// <summary>
/// Cancel the changes.
/// </summary>
Cancel,
/// <summary>
/// Commit edited value.
/// </summary>
Commit
}
// Determines the location and visibility of the editing row.
internal enum DataGridEditingRowLocation
{
Bottom = 0, // The editing row is collapsed below the displayed rows
Inline = 1, // The editing row is visible and displayed
Top = 2 // The editing row is collapsed above the displayed rows
}
/// <summary>
/// Determines whether the inner cells' vertical/horizontal gridlines are shown or not.
/// </summary>
[Flags]
public enum DataGridGridLinesVisibility
{
/// <summary>
/// None DataGridGridLinesVisibility
/// </summary>
None = 0,
/// <summary>
/// Horizontal DataGridGridLinesVisibility
/// </summary>
Horizontal = 1,
/// <summary>
/// Vertical DataGridGridLinesVisibility
/// </summary>
Vertical = 2,
/// <summary>
/// All DataGridGridLinesVisibility
/// </summary>
All = 3,
}
/// <summary>
/// Determines whether the current cell or row is edited.
/// </summary>
public enum DataGridEditingUnit
{
/// <summary>
/// Cell DataGridEditingUnit
/// </summary>
Cell = 0,
/// <summary>
/// Row DataGridEditingUnit
/// </summary>
Row = 1,
}
/// <summary>
/// Determines whether the row/column headers are shown or not.
/// </summary>
[Flags]
public enum DataGridHeadersVisibility
{
/// <summary>
/// Show Row, Column, and Corner Headers
/// </summary>
All = Row | Column,
/// <summary>
/// Show only Column Headers with top-right corner Header
/// </summary>
Column = 0x01,
/// <summary>
/// Show only Row Headers with bottom-left corner
/// </summary>
Row = 0x02,
/// <summary>
/// Dont show any Headers
/// </summary>
None = 0x00
}
/// <summary>
/// Determines the visibility of the row details.
/// </summary>
public enum DataGridRowDetailsVisibilityMode
{
/// <summary>
/// Collapsed DataGridRowDetailsVisibilityMode
/// </summary>
Collapsed = 2, // Show no details. Developer is in charge of toggling visibility.
/// <summary>
/// Visible DataGridRowDetailsVisibilityMode
/// </summary>
Visible = 1, // Show the details section for all rows.
/// <summary>
/// VisibleWhenSelected DataGridRowDetailsVisibilityMode
/// </summary>
VisibleWhenSelected = 0 // Show the details section only for the selected row(s).
}
/// <summary>
/// Determines the type of action to take when selecting items.
/// </summary>
internal enum DataGridSelectionAction
{
AddCurrentToSelection,
None,
RemoveCurrentFromSelection,
SelectCurrent,
SelectFromAnchorToCurrent
}
/// <summary>
/// Determines the selection model.
/// </summary>
public enum DataGridSelectionMode
{
/// <summary>
/// Extended DataGridSelectionMode
/// </summary>
Extended = 0,
/// <summary>
/// Single DataGridSelectionMode
/// </summary>
Single = 1
}
/// <summary>
/// Determines the sort direction of a column.
/// </summary>
public enum DataGridSortDirection
{
/// <summary>
/// Sorts in ascending order.
/// </summary>
Ascending = 0,
/// <summary>
/// Sorts in descending order.
/// </summary>
Descending = 1
}
}

Просмотреть файл

@ -0,0 +1,229 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals
{
internal static class DataGridError
{
public static class DataGrid
{
public static InvalidOperationException CannotChangeItemsWhenLoadingRows()
{
return new InvalidOperationException("Items cannot be added, removed or reset while rows are loading or unloading.");
}
public static InvalidOperationException CannotChangeColumnCollectionWhileAdjustingDisplayIndexes()
{
return new InvalidOperationException("Column collection cannot be changed while adjusting display indexes.");
}
public static InvalidOperationException ColumnCannotBeCollapsed()
{
return new InvalidOperationException("Column cannot be collapsed.");
}
public static InvalidOperationException ColumnCannotBeReassignedToDifferentDataGrid()
{
return new InvalidOperationException("Column already belongs to a DataGrid instance and cannot be reassigned.");
}
public static ArgumentException ColumnNotInThisDataGrid()
{
return new ArgumentException("Provided column does not belong to this DataGrid.");
}
public static ArgumentException ItemIsNotContainedInTheItemsSource(string paramName)
{
return new ArgumentException("The item is not contained in the ItemsSource.", paramName);
}
public static InvalidOperationException NoCurrentRow()
{
return new InvalidOperationException("There is no current row. Operation cannot be completed.");
}
public static InvalidOperationException NoOwningGrid(Type type)
{
return new InvalidOperationException(Format("There is no instance of DataGrid assigned to this {0}. Operation cannot be completed.", type.FullName));
}
public static InvalidOperationException UnderlyingPropertyIsReadOnly(string paramName)
{
return new InvalidOperationException(Format("{0} cannot be set because the underlying property is read only.", paramName));
}
public static ArgumentException ValueCannotBeSetToInfinity(string paramName)
{
return new ArgumentException(Format("{0} cannot be set to infinity.", paramName));
}
public static ArgumentException ValueCannotBeSetToNAN(string paramName)
{
return new ArgumentException(Format("{0} cannot be set to double.NAN.", paramName));
}
public static ArgumentNullException ValueCannotBeSetToNull(string paramName, string valueName)
{
return new ArgumentNullException(paramName, Format("{0} cannot be set to a null value.", valueName));
}
public static ArgumentException ValueIsNotAnInstanceOf(string paramName, Type type)
{
return new ArgumentException(paramName, Format("The value is not an instance of {0}.", type.FullName));
}
public static ArgumentException ValueIsNotAnInstanceOfEitherOr(string paramName, Type type1, Type type2)
{
return new ArgumentException(paramName, Format("The value is not an instance of {0} or {1}.", type1.FullName, type2.FullName));
}
public static ArgumentOutOfRangeException ValueMustBeBetween(string paramName, string valueName, object lowValue, bool lowInclusive, object highValue, bool highInclusive)
{
string message;
if (lowInclusive && highInclusive)
{
message = "{0} must be greater than or equal to {1} and less than or equal to {2}.";
}
else if (lowInclusive && !highInclusive)
{
message = "{0} must be greater than or equal to {1} and less than {2}.";
}
else if (!lowInclusive && highInclusive)
{
message = "{0} must be greater than {1} and less than or equal to {2}.";
}
else
{
message = "{0} must be greater than {1} and less than {2}.";
}
return new ArgumentOutOfRangeException(paramName, Format(message, valueName, lowValue, highValue));
}
public static ArgumentOutOfRangeException ValueMustBeGreaterThanOrEqualTo(string paramName, string valueName, object value)
{
return new ArgumentOutOfRangeException(paramName, Format("{0} must be greater than or equal to {1}.", valueName, value));
}
public static ArgumentOutOfRangeException ValueMustBeLessThanOrEqualTo(string paramName, string valueName, object value)
{
return new ArgumentOutOfRangeException(paramName, Format("{0} must be less than or equal to {1}.", valueName, value));
}
public static ArgumentOutOfRangeException ValueMustBeLessThan(string paramName, string valueName, object value)
{
return new ArgumentOutOfRangeException(paramName, Format("{0} must be less than {1}.", valueName, value));
}
}
public static class DataGridAutomationPeer
{
public static InvalidOperationException OperationCannotBePerformed()
{
return new InvalidOperationException("Cannot perform the operation.");
}
}
public static class DataGridColumnHeader
{
public static NotSupportedException ContentDoesNotSupportUIElements()
{
return new NotSupportedException("Content does not support UIElement; use ContentTemplate instead.");
}
}
public static class DataGridLength
{
public static ArgumentException InvalidUnitType(string paramName)
{
return new ArgumentException(Format("{0} is not a valid DataGridLengthUnitType.", paramName), paramName);
}
}
public static class DataGridLengthConverter
{
public static NotSupportedException CannotConvertFrom(string paramName)
{
return new NotSupportedException(Format("DataGridLengthConverter cannot convert from {0}.", paramName));
}
public static NotSupportedException CannotConvertTo(string paramName)
{
return new NotSupportedException(Format("Cannot convert from DataGridLength to {0}.", paramName));
}
public static NotSupportedException InvalidDataGridLength(string paramName)
{
return new NotSupportedException(Format("Invalid DataGridLength.", paramName));
}
}
public static class DataGridRow
{
public static InvalidOperationException InvalidRowIndexCannotCompleteOperation()
{
return new InvalidOperationException("Invalid row index. Operation cannot be completed.");
}
}
public static class DataGridSelectedItemsCollection
{
public static InvalidOperationException CannotChangeSelectedItemsCollectionInSingleMode()
{
return new InvalidOperationException("Can only change SelectedItems collection in Extended selection mode. Use SelectedItem property in Single selection mode.");
}
}
public static class DataGridComboBoxColumn
{
public static ArgumentException UnsetBinding(string header)
{
return new ArgumentException(Format("Binding for column {0} is null. Ensure that the binding path has been set correctly.", header));
}
public static ArgumentException UnsetBinding(Type type)
{
return new ArgumentException(Format("Binding for column of type {0} is null. Ensure that the binding path has been set correctly.", type.FullName));
}
public static ArgumentException UnknownBindingPath(Binding binding, Type type)
{
return new ArgumentException(Format("Binding path {0} could not be found in type {1}. Ensure that the binding path has been set correctly.", binding.Path.Path, type.FullName));
}
public static ArgumentException UnknownDisplayMemberPath(string displayMemberPath, Type type)
{
return new ArgumentException(Format("DisplayMemberPath {0} could not be found in type {1}. Ensure that the value has been set correctly and note that for built-in types DisplayMemberPath should not be used.", displayMemberPath, type.FullName));
}
public static ArgumentException UnknownItemsSourcePath(Binding binding)
{
return new ArgumentException(Format("The ItemsSource elements do not contain a property {0}. Ensure that the binding path has been set correctly.", binding.Path.Path));
}
public static ArgumentException BindingTypeMismatch(Type bindingType, Type itemSourceType)
{
return new ArgumentException(Format("The DataGridComboBoxColumn ItemSource elements of type \'{0}\' do not match the Binding type \'{1}\'. Ensure that the paths have been set correctly and specify a DisplayMemberPath for non built-in types.", itemSourceType.FullName, bindingType.FullName));
}
}
public static class DataGridTemplateColumn
{
public static TypeInitializationException MissingTemplateForType(Type type)
{
return new TypeInitializationException(Format("Missing template. Cannot initialize {0}.", type.FullName), null);
}
}
private static string Format(string formatString, params object[] args)
{
return string.Format(CultureInfo.CurrentCulture, formatString, args);
}
}
}

Просмотреть файл

@ -0,0 +1,74 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
internal class DataGridFillerColumn : DataGridColumn
{
public DataGridFillerColumn(DataGrid owningGrid)
{
this.IsReadOnly = true;
this.OwningGrid = owningGrid;
this.MinWidth = 0;
this.MaxWidth = int.MaxValue;
}
internal double FillerWidth
{
get;
set;
}
// True if there is room for the filler column; otherwise, false
internal bool IsActive
{
get
{
return this.FillerWidth > 0;
}
}
// True if the FillerColumn's header cell is contained in the visual tree
internal bool IsRepresented
{
get;
set;
}
internal override DataGridColumnHeader CreateHeader()
{
DataGridColumnHeader headerCell = base.CreateHeader();
if (headerCell != null)
{
Windows.UI.Xaml.Automation.AutomationProperties.SetAccessibilityView(
headerCell,
Windows.UI.Xaml.Automation.Peers.AccessibilityView.Raw);
headerCell.IsEnabled = false;
}
return headerCell;
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
return null;
}
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
return null;
}
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
Debug.Assert(false, "Unexpected call to DataGridFillerColumn.PrepareCellForEdit.");
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Primitives
{
/// <summary>
/// Represents a non-scrollable grid that contains <see cref="DataGrid"/> row headers.
/// </summary>
public class DataGridFrozenGrid : Grid
{
/// <summary>
/// A dependency property that indicates whether the grid is frozen.
/// </summary>
public static readonly DependencyProperty IsFrozenProperty = DependencyProperty.RegisterAttached(
"IsFrozen",
typeof(bool),
typeof(DataGridFrozenGrid),
null);
/// <summary>
/// Gets a value that indicates whether the grid is frozen.
/// </summary>
/// <param name="element">
/// The object to get the IsFrozen value from.
/// </param>
/// <returns>true if the grid is frozen; otherwise, false. The default is true.</returns>
public static bool GetIsFrozen(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool)element.GetValue(IsFrozenProperty);
}
/// <summary>
/// Sets a value that indicates whether the grid is frozen.
/// </summary>
/// <param name="element">The object to set the IsFrozen value on.</param>
/// <param name="value">true if <paramref name="element"/> is frozen; otherwise, false.</param>
/// <exception cref="T:System.ArgumentNullException"><paramref name="element"/> is null.</exception>
public static void SetIsFrozen(DependencyObject element, bool value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(IsFrozenProperty, value);
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml.Input;
namespace Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals
{
internal class DataGridInteractionInfo
{
internal uint CapturedPointerId
{
get;
set;
}
internal bool IsPointerOver
{
get;
set;
}
}
}

Просмотреть файл

@ -0,0 +1,477 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Globalization;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.Utilities;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// DataGridLengthUnitType
/// </summary>
/// <remarks>
/// These aren't flags.
/// </remarks>
public enum DataGridLengthUnitType
{
/// <summary>
/// Auto DataGridLengthUnitType
/// </summary>
Auto = 0,
/// <summary>
/// Pixel DataGridLengthUnitType
/// </summary>
Pixel = 1,
/// <summary>
/// SizeToCells DataGridLengthUnitType
/// </summary>
SizeToCells = 2,
/// <summary>
/// SizeToHeader DataGridLengthUnitType
/// </summary>
SizeToHeader = 3,
/// <summary>
/// Star DataGridLengthUnitType
/// </summary>
Star = 4
}
/// <summary>
/// Represents the lengths of elements within the <see cref="DataGrid"/> control.
/// </summary>
[Windows.Foundation.Metadata.CreateFromString(MethodName = "Microsoft.Toolkit.Uwp.UI.Controls.DataGridLength.ConvertFromString")]
public struct DataGridLength : IEquatable<DataGridLength>
{
// static instances of value invariant DataGridLengths
private static readonly DataGridLength _auto = new DataGridLength(DATAGRIDLENGTH_DefaultValue, DataGridLengthUnitType.Auto);
private static readonly DataGridLength _sizeToCells = new DataGridLength(DATAGRIDLENGTH_DefaultValue, DataGridLengthUnitType.SizeToCells);
private static readonly DataGridLength _sizeToHeader = new DataGridLength(DATAGRIDLENGTH_DefaultValue, DataGridLengthUnitType.SizeToHeader);
private static string _starSuffix = "*";
private static string[] _valueInvariantUnitStrings = { "auto", "sizetocells", "sizetoheader" };
private static DataGridLength[] _valueInvariantDataGridLengths = { DataGridLength.Auto, DataGridLength.SizeToCells, DataGridLength.SizeToHeader };
private double _desiredValue; // desired value storage
private double _displayValue; // display value storage
private double _unitValue; // unit value storage
private DataGridLengthUnitType _unitType; // unit type storage
internal const double DATAGRIDLENGTH_DefaultValue = 1.0;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridLength"/> struct based on a numerical value.
/// </summary>
/// <param name="value">numerical length</param>
public DataGridLength(double value)
: this(value, DataGridLengthUnitType.Pixel)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DataGridLength"/> struct based on a numerical value and a type.
/// </summary>
/// <param name="value">The value to hold.</param>
/// <param name="type">The unit of <c>value</c>.</param>
/// <remarks>
/// <c>value</c> is ignored unless <c>type</c> is
/// <c>DataGridLengthUnitType.Pixel</c> or
/// <c>DataGridLengthUnitType.Star</c>
/// </remarks>
/// <exception cref="ArgumentException">
/// If <c>value</c> parameter is <c>double.NaN</c>
/// or <c>value</c> parameter is <c>double.NegativeInfinity</c>
/// or <c>value</c> parameter is <c>double.PositiveInfinity</c>.
/// </exception>
public DataGridLength(double value, DataGridLengthUnitType type)
: this(value, type, type == DataGridLengthUnitType.Pixel ? value : double.NaN, type == DataGridLengthUnitType.Pixel ? value : double.NaN)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DataGridLength"/> struct based on a numerical value and a unit.
/// </summary>
/// <param name="value">The value to hold.</param>
/// <param name="type">The unit of <c>value</c>.</param>
/// <param name="desiredValue">The desired value.</param>
/// <param name="displayValue">The display value.</param>
/// <remarks>
/// <c>value</c> is ignored unless <c>type</c> is
/// <c>DataGridLengthUnitType.Pixel</c> or
/// <c>DataGridLengthUnitType.Star</c>
/// </remarks>
/// <exception cref="ArgumentException">
/// If <c>value</c> parameter is <c>double.NaN</c>
/// or <c>value</c> parameter is <c>double.NegativeInfinity</c>
/// or <c>value</c> parameter is <c>double.PositiveInfinity</c>.
/// </exception>
public DataGridLength(double value, DataGridLengthUnitType type, double desiredValue, double displayValue)
{
if (double.IsNaN(value))
{
throw DataGridError.DataGrid.ValueCannotBeSetToNAN("value");
}
if (double.IsInfinity(value))
{
throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("value");
}
if (double.IsInfinity(desiredValue))
{
throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("desiredValue");
}
if (double.IsInfinity(displayValue))
{
throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("displayValue");
}
if (value < 0)
{
throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "value", 0);
}
if (desiredValue < 0)
{
throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("desiredValue", "desiredValue", 0);
}
if (displayValue < 0)
{
throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("displayValue", "displayValue", 0);
}
if (type != DataGridLengthUnitType.Auto &&
type != DataGridLengthUnitType.SizeToCells &&
type != DataGridLengthUnitType.SizeToHeader &&
type != DataGridLengthUnitType.Star &&
type != DataGridLengthUnitType.Pixel)
{
throw DataGridError.DataGridLength.InvalidUnitType("type");
}
_desiredValue = desiredValue;
_displayValue = displayValue;
_unitValue = (type == DataGridLengthUnitType.Auto) ? DATAGRIDLENGTH_DefaultValue : value;
_unitType = type;
}
/// <summary>
/// Gets a <see cref="DataGridLength"/> structure that represents the standard automatic sizing mode.
/// </summary>
/// <returns>
/// A <see cref="DataGridLength"/> structure that represents the standard automatic sizing mode.
/// </returns>
public static DataGridLength Auto
{
get
{
return _auto;
}
}
/// <summary>
/// Gets a <see cref="DataGridLength"/> structure that represents the cell-based automatic sizing mode.
/// </summary>
/// <returns>
/// A <see cref="DataGridLength"/> structure that represents the cell-based automatic sizing mode.
/// </returns>
public static DataGridLength SizeToCells
{
get
{
return _sizeToCells;
}
}
/// <summary>
/// Gets a <see cref="DataGridLength"/> structure that represents the header-based automatic sizing mode.
/// </summary>
/// <returns>
/// A <see cref="DataGridLength"/> structure that represents the header-based automatic sizing mode.
/// </returns>
public static DataGridLength SizeToHeader
{
get
{
return _sizeToHeader;
}
}
/// <summary>
/// Gets the desired value of this instance.
/// </summary>
public double DesiredValue
{
get
{
return _desiredValue;
}
}
/// <summary>
/// Gets the display value of this instance.
/// </summary>
public double DisplayValue
{
get
{
return _displayValue;
}
}
/// <summary>
/// Gets a value indicating whether this DataGridLength instance holds an absolute (pixel) value.
/// </summary>
public bool IsAbsolute
{
get
{
return _unitType == DataGridLengthUnitType.Pixel;
}
}
/// <summary>
/// Gets a value indicating whether this DataGridLength instance is automatic (not specified).
/// </summary>
public bool IsAuto
{
get
{
return _unitType == DataGridLengthUnitType.Auto;
}
}
/// <summary>
/// Gets a value indicating whether this DataGridLength instance is to size to the cells of a column or row.
/// </summary>
public bool IsSizeToCells
{
get
{
return _unitType == DataGridLengthUnitType.SizeToCells;
}
}
/// <summary>
/// Gets a value indicating whether this DataGridLength instance is to size to the header of a column or row.
/// </summary>
public bool IsSizeToHeader
{
get
{
return _unitType == DataGridLengthUnitType.SizeToHeader;
}
}
/// <summary>
/// Gets a value indicating whether this DataGridLength instance holds a weighted proportion of available space.
/// </summary>
public bool IsStar
{
get
{
return _unitType == DataGridLengthUnitType.Star;
}
}
/// <summary>
/// Gets the <see cref="DataGridLengthUnitType"/> that represents the current sizing mode.
/// </summary>
public DataGridLengthUnitType UnitType
{
get
{
return _unitType;
}
}
/// <summary>
/// Gets the absolute value of the <see cref="DataGridLength"/> in pixels.
/// </summary>
/// <returns>
/// The absolute value of the <see cref="DataGridLength"/> in pixels.
/// </returns>
public double Value
{
get
{
return _unitValue;
}
}
/// <summary>
/// Converts a string into a <see cref="DataGridLength"/> instance.
/// </summary>
/// <param name="value">string to convert.</param>
/// <returns>The result of the conversion.</returns>
public static DataGridLength ConvertFromString(string value)
{
return ConvertFrom(null, value);
}
/// <summary>
/// Converts an object into a <see cref="DataGridLength"/> instance.
/// </summary>
/// <param name="culture">optional culture to use for conversion.</param>
/// <param name="value">object to convert.</param>
/// <returns>The result of the conversion.</returns>
public static DataGridLength ConvertFrom(CultureInfo culture, object value)
{
if (value == null)
{
throw DataGridError.DataGridLengthConverter.CannotConvertFrom("(null)");
}
string stringValue = value as string;
if (stringValue != null)
{
stringValue = stringValue.Trim();
if (stringValue.EndsWith(_starSuffix, StringComparison.Ordinal))
{
string stringValueWithoutSuffix = stringValue.Substring(0, stringValue.Length - _starSuffix.Length);
double starWeight;
if (string.IsNullOrEmpty(stringValueWithoutSuffix))
{
starWeight = 1;
}
else
{
starWeight = Convert.ToDouble(stringValueWithoutSuffix, culture ?? CultureInfo.CurrentCulture);
}
return new DataGridLength(starWeight, DataGridLengthUnitType.Star);
}
for (int index = 0; index < _valueInvariantUnitStrings.Length; index++)
{
if (stringValue.Equals(_valueInvariantUnitStrings[index], StringComparison.OrdinalIgnoreCase))
{
return _valueInvariantDataGridLengths[index];
}
}
}
// Conversion from numeric type
double doubleValue = Convert.ToDouble(value, culture ?? CultureInfo.CurrentCulture);
if (double.IsNaN(doubleValue))
{
return DataGridLength.Auto;
}
else
{
return new DataGridLength(doubleValue);
}
}
/// <summary>
/// Converts a <see cref="DataGridLength"/> instance into a string.
/// </summary>
/// <param name="culture">optional culture to use for conversion.</param>
/// <param name="value">value to convert.</param>
/// <returns>The result of the conversion.</returns>
public static string ConvertToString(CultureInfo culture, DataGridLength value)
{
// Convert dataGridLength to a string
switch (value.UnitType)
{
// for Auto print out "Auto". value is always "1.0"
case DataGridLengthUnitType.Auto:
return "Auto";
case DataGridLengthUnitType.SizeToHeader:
return "SizeToHeader";
case DataGridLengthUnitType.SizeToCells:
return "SizeToCells";
// Star has one special case when value is "1.0".
// in this case drop value part and print only "Star"
case DataGridLengthUnitType.Star:
return
DoubleUtil.AreClose(1.0, value.Value)
? _starSuffix
: Convert.ToString(value.Value, culture ?? CultureInfo.CurrentCulture) + _starSuffix;
default:
return Convert.ToString(value.Value, culture ?? CultureInfo.CurrentCulture);
}
}
/// <summary>
/// Overloaded operator, compares 2 DataGridLength's.
/// </summary>
/// <param name="gl1">first DataGridLength to compare.</param>
/// <param name="gl2">second DataGridLength to compare.</param>
/// <returns>true if specified DataGridLength have same value,
/// unit type, desired value, and display value.</returns>
public static bool operator ==(DataGridLength gl1, DataGridLength gl2)
{
return gl1.UnitType == gl2.UnitType &&
gl1.Value == gl2.Value &&
gl1.DesiredValue == gl2.DesiredValue &&
gl1.DisplayValue == gl2.DisplayValue;
}
/// <summary>
/// Overloaded operator, compares 2 DataGridLength's.
/// </summary>
/// <param name="gl1">first DataGridLength to compare.</param>
/// <param name="gl2">second DataGridLength to compare.</param>
/// <returns>true if specified DataGridLength have either different value,
/// unit type, desired value, or display value.</returns>
public static bool operator !=(DataGridLength gl1, DataGridLength gl2)
{
return gl1.UnitType != gl2.UnitType ||
gl1.Value != gl2.Value ||
gl1.DesiredValue != gl2.DesiredValue ||
gl1.DisplayValue != gl2.DisplayValue;
}
/// <summary>
/// Compares this instance of DataGridLength with another instance.
/// </summary>
/// <param name="other">DataGridLength length instance to compare.</param>
/// <returns><c>true</c> if this DataGridLength instance has the same value
/// and unit type as gridLength.</returns>
public bool Equals(DataGridLength other)
{
return this == other;
}
/// <summary>
/// Compares this instance of DataGridLength with another object.
/// </summary>
/// <param name="obj">Reference to an object for comparison.</param>
/// <returns><c>true</c> if this DataGridLength instance has the same value
/// and unit type as oCompare.</returns>
public override bool Equals(object obj)
{
DataGridLength? dataGridLength = obj as DataGridLength?;
if (dataGridLength.HasValue)
{
return this == dataGridLength;
}
return false;
}
/// <summary>
/// Returns a unique hash code for this DataGridLength
/// </summary>
/// <returns>hash code</returns>
public override int GetHashCode()
{
return (int)_unitValue + (int)_unitType + (int)_desiredValue + (int)_displayValue;
}
}
}

Просмотреть файл

@ -0,0 +1,70 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides data for the <see cref="E:Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.PreparingCellForEdit"/> event.
/// </summary>
public class DataGridPreparingCellForEditEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridPreparingCellForEditEventArgs"/> class.
/// </summary>
/// <param name="column">The column that contains the cell to be edited.</param>
/// <param name="row">The row that contains the cell to be edited.</param>
/// <param name="editingEventArgs">Information about the user gesture that caused the cell to enter edit mode.</param>
/// <param name="editingElement">The element that the column displays for a cell in editing mode.</param>
public DataGridPreparingCellForEditEventArgs(
DataGridColumn column,
DataGridRow row,
RoutedEventArgs editingEventArgs,
FrameworkElement editingElement)
{
this.Column = column;
this.Row = row;
this.EditingEventArgs = editingEventArgs;
this.EditingElement = editingElement;
}
/// <summary>
/// Gets the column that contains the cell to be edited.
/// </summary>
public DataGridColumn Column
{
get;
private set;
}
/// <summary>
/// Gets the element that the column displays for a cell in editing mode.
/// </summary>
public FrameworkElement EditingElement
{
get;
private set;
}
/// <summary>
/// Gets information about the user gesture that caused the cell to enter edit mode.
/// </summary>
public RoutedEventArgs EditingEventArgs
{
get;
private set;
}
/// <summary>
/// Gets the row that contains the cell to be edited.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,68 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// This class encapsulates a selected row's information necessary for the CopyingRowClipboardContent event.
/// </summary>
public class DataGridRowClipboardEventArgs : EventArgs
{
private List<DataGridClipboardCellContent> _clipboardRowContent;
private bool _isColumnHeadersRow;
private object _item;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowClipboardEventArgs"/> class.
/// </summary>
/// <param name="item">The row's associated data item.</param>
/// <param name="isColumnHeadersRow">Whether or not this EventArgs is for the column headers.</param>
internal DataGridRowClipboardEventArgs(object item, bool isColumnHeadersRow)
{
_isColumnHeadersRow = isColumnHeadersRow;
_item = item;
}
/// <summary>
/// Gets a list used to modify, add or remove a cell content before it gets stored into the clipboard.
/// </summary>
public List<DataGridClipboardCellContent> ClipboardRowContent
{
get
{
if (_clipboardRowContent == null)
{
_clipboardRowContent = new List<DataGridClipboardCellContent>();
}
return _clipboardRowContent;
}
}
/// <summary>
/// Gets a value indicating whether this property is true when the ClipboardRowContent represents column headers, in which case the Item is null.
/// </summary>
public bool IsColumnHeadersRow
{
get
{
return _isColumnHeadersRow;
}
}
/// <summary>
/// Gets the <see cref="DataGrid"/> row item used for preparing the ClipboardRowContent.
/// </summary>
public object Item
{
get
{
return _item;
}
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides data for the <see cref="E:Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.LoadingRowDetails"/>, <see cref="E:Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.UnloadingRowDetails"/>,
/// and <see cref="E:Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.RowDetailsVisibilityChanged"/> events.
/// </summary>
public class DataGridRowDetailsEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowDetailsEventArgs"/> class.
/// </summary>
/// <param name="row">The row that the event occurs for.</param>
/// <param name="detailsElement">The row details section as a framework element.</param>
public DataGridRowDetailsEventArgs(DataGridRow row, FrameworkElement detailsElement)
{
this.Row = row;
this.DetailsElement = detailsElement;
}
/// <summary>
/// Gets the row details section as a framework element.
/// </summary>
public FrameworkElement DetailsElement
{
get;
private set;
}
/// <summary>
/// Gets the row that the event occurs for.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides information just after a row has exited edit mode.
/// </summary>
public class DataGridRowEditEndedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowEditEndedEventArgs"/> class.
/// </summary>
/// <param name="row">The row container of the cell container that has just exited edit mode.</param>
/// <param name="editAction">The editing action that has been taken.</param>
public DataGridRowEditEndedEventArgs(DataGridRow row, DataGridEditAction editAction)
{
this.Row = row;
this.EditAction = editAction;
}
/// <summary>
/// Gets the editing action that has been taken.
/// </summary>
public DataGridEditAction EditAction
{
get;
private set;
}
/// <summary>
/// Gets the row container of the cell container that has just exited edit mode.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,43 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides information just before a row exits editing mode.
/// </summary>
public class DataGridRowEditEndingEventArgs : CancelEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowEditEndingEventArgs"/> class.
/// </summary>
/// <param name="row">The row container of the cell container that is about to exit edit mode.</param>
/// <param name="editAction">The editing action that will be taken.</param>
public DataGridRowEditEndingEventArgs(DataGridRow row, DataGridEditAction editAction)
{
this.Row = row;
this.EditAction = editAction;
}
/// <summary>
/// Gets the editing action that will be taken.
/// </summary>
public DataGridEditAction EditAction
{
get;
private set;
}
/// <summary>
/// Gets the row container of the cell container that is about to exit edit mode.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides data for <see cref="DataGrid"/> row-related events.
/// </summary>
public class DataGridRowEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowEventArgs"/> class.
/// </summary>
/// <param name="dataGridRow">The row that the event occurs for.</param>
public DataGridRowEventArgs(DataGridRow dataGridRow)
{
this.Row = dataGridRow;
}
/// <summary>
/// Gets the row that the event occurs for.
/// </summary>
public DataGridRow Row
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,749 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.UI.Controls.Primitives;
using Microsoft.Toolkit.Uwp.UI.Controls.Utilities;
using Microsoft.Toolkit.Uwp.UI.Utilities;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Represents the header of a <see cref="DataGrid"/> row group.
/// </summary>
[TemplatePart(Name = DataGridRow.DATAGRIDROW_elementRoot, Type = typeof(Panel))]
[TemplatePart(Name = DataGridRow.DATAGRIDROW_elementRowHeader, Type = typeof(DataGridRowHeader))]
[TemplatePart(Name = DATAGRIDROWGROUPHEADER_bottomGridLine, Type = typeof(Rectangle))]
[TemplatePart(Name = DATAGRIDROWGROUPHEADER_expanderButton, Type = typeof(ToggleButton))]
[TemplatePart(Name = DATAGRIDROWGROUPHEADER_indentSpacer, Type = typeof(FrameworkElement))]
[TemplatePart(Name = DATAGRIDROWGROUPHEADER_itemCountElement, Type = typeof(TextBlock))]
[TemplatePart(Name = DATAGRIDROWGROUPHEADER_propertyNameElement, Type = typeof(TextBlock))]
[TemplatePart(Name = DATAGRIDROWGROUPHEADER_propertyValueElement, Type = typeof(TextBlock))]
[StyleTypedProperty(Property = "HeaderStyle", StyleTargetType = typeof(DataGridRowHeader))]
public class DataGridRowGroupHeader : Control
{
private const string DATAGRIDROWGROUPHEADER_bottomGridLine = "BottomGridLine";
private const string DATAGRIDROWGROUPHEADER_expanderButton = "ExpanderButton";
private const string DATAGRIDROWGROUPHEADER_indentSpacer = "IndentSpacer";
private const string DATAGRIDROWGROUPHEADER_itemCountElement = "ItemCountElement";
private const string DATAGRIDROWGROUPHEADER_propertyNameElement = "PropertyNameElement";
private const string DATAGRIDROWGROUPHEADER_propertyValueElement = "PropertyValueElement";
private bool _areIsCheckedHandlersSuspended;
private Rectangle _bottomGridLine;
private ToggleButton _expanderButton;
private FrameworkElement _indentSpacer;
private TextBlock _itemCountElement;
private TextBlock _propertyNameElement;
private TextBlock _propertyValueElement;
private Panel _rootElement;
private double _totalIndent;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowGroupHeader"/> class.
/// </summary>
public DataGridRowGroupHeader()
{
DefaultStyleKey = typeof(DataGridRowGroupHeader);
this.AddHandler(UIElement.TappedEvent, new TappedEventHandler(DataGridRowGroupHeader_Tapped), true /*handledEventsToo*/);
this.AddHandler(UIElement.DoubleTappedEvent, new DoubleTappedEventHandler(DataGridRowGroupHeader_DoubleTapped), true /*handledEventsToo*/);
this.PointerCanceled += new PointerEventHandler(DataGridRowGroupHeader_PointerCanceled);
this.PointerEntered += new PointerEventHandler(DataGridRowGroupHeader_PointerEntered);
this.PointerExited += new PointerEventHandler(DataGridRowGroupHeader_PointerExited);
this.PointerMoved += new PointerEventHandler(DataGridRowGroupHeader_PointerMoved);
this.PointerPressed += new PointerEventHandler(DataGridRowGroupHeader_PointerPressed);
this.PointerReleased += new PointerEventHandler(DataGridRowGroupHeader_PointerReleased);
}
/// <summary>
/// Gets or sets the style applied to the header cell of a <see cref="DataGridRowGroupHeader"/>.
/// </summary>
public Style HeaderStyle
{
get { return GetValue(HeaderStyleProperty) as Style; }
set { SetValue(HeaderStyleProperty, value); }
}
/// <summary>
/// Dependency Property for HeaderStyle
/// </summary>
public static readonly DependencyProperty HeaderStyleProperty =
DependencyProperty.Register(
"HeaderStyle",
typeof(Style),
typeof(DataGridRowGroupHeader),
new PropertyMetadata(null, OnHeaderStylePropertyChanged));
private static void OnHeaderStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridRowGroupHeader groupHeader = d as DataGridRowGroupHeader;
if (groupHeader.HeaderElement != null)
{
groupHeader.HeaderElement.EnsureStyle(e.OldValue as Style);
}
}
/// <summary>
/// Gets or sets a value that indicates whether the item count is visible.
/// </summary>
public Visibility ItemCountVisibility
{
get { return (Visibility)GetValue(ItemCountVisibilityProperty); }
set { SetValue(ItemCountVisibilityProperty, value); }
}
/// <summary>
/// DependencyProperty for ItemCountVisibility
/// </summary>
public static readonly DependencyProperty ItemCountVisibilityProperty =
DependencyProperty.Register(
"ItemCountVisibility",
typeof(Visibility),
typeof(DataGridRowGroupHeader),
new PropertyMetadata(Visibility.Visible));
/// <summary>
/// Gets the nesting level of the associated group.
/// </summary>
public int Level
{
get { return (int)GetValue(LevelProperty); }
internal set { SetValue(LevelProperty, value); }
}
/// <summary>
/// Identifies the Level dependency property.
/// </summary>
public static readonly DependencyProperty LevelProperty =
DependencyProperty.Register(
"Level",
typeof(int),
typeof(DataGridRowGroupHeader),
new PropertyMetadata(0));
/// <summary>
/// Gets or sets the name of the property that this <see cref="DataGrid"/> row is bound to.
/// </summary>
public string PropertyName
{
get { return GetValue(PropertyNameProperty) as string; }
set { SetValue(PropertyNameProperty, value); }
}
/// <summary>
/// DependencyProperty for PropertyName
/// </summary>
public static readonly DependencyProperty PropertyNameProperty =
DependencyProperty.Register(
"PropertyName",
typeof(string),
typeof(DataGridRowGroupHeader),
new PropertyMetadata(null, OnPropertyNameChanged));
private static void OnPropertyNameChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridRowGroupHeader groupHeader = d as DataGridRowGroupHeader;
groupHeader.UpdateTitleElements();
}
/// <summary>
/// Gets or sets a value that indicates whether the property name is visible.
/// </summary>
public Visibility PropertyNameVisibility
{
get { return (Visibility)GetValue(PropertyNameVisibilityProperty); }
set { SetValue(PropertyNameVisibilityProperty, value); }
}
/// <summary>
/// DependencyProperty for PropertyNameVisibility
/// </summary>
public static readonly DependencyProperty PropertyNameVisibilityProperty =
DependencyProperty.Register(
"PropertyNameVisibility",
typeof(Visibility),
typeof(DataGridRowGroupHeader),
new PropertyMetadata(Visibility.Visible));
/// <summary>
/// Gets or sets the value of the property that this <see cref="DataGrid"/> row is bound to.
/// </summary>
public string PropertyValue
{
get { return GetValue(PropertyValueProperty) as string; }
set { SetValue(PropertyValueProperty, value); }
}
/// <summary>
/// DependencyProperty for PropertyName
/// </summary>
public static readonly DependencyProperty PropertyValueProperty =
DependencyProperty.Register(
"PropertyValue",
typeof(string),
typeof(DataGridRowGroupHeader),
new PropertyMetadata(null, OnPropertyValueChanged));
private static void OnPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridRowGroupHeader groupHeader = d as DataGridRowGroupHeader;
groupHeader.UpdateTitleElements();
}
/// <summary>
/// Gets or sets a value that indicates the amount that the
/// children of the <see cref="DataGridRowGroupHeader"/> are indented.
/// </summary>
public double SublevelIndent
{
get { return (double)GetValue(SublevelIndentProperty); }
set { SetValue(SublevelIndentProperty, value); }
}
/// <summary>
/// SublevelIndent Dependency property
/// </summary>
public static readonly DependencyProperty SublevelIndentProperty =
DependencyProperty.Register(
"SublevelIndent",
typeof(double),
typeof(DataGridRowGroupHeader),
new PropertyMetadata(DataGrid.DATAGRID_defaultRowGroupSublevelIndent, OnSublevelIndentPropertyChanged));
private static void OnSublevelIndentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridRowGroupHeader groupHeader = d as DataGridRowGroupHeader;
double newValue = (double)e.NewValue;
// We don't need to revert to the old value if our input is bad because we never read this property value
if (double.IsNaN(newValue))
{
throw DataGridError.DataGrid.ValueCannotBeSetToNAN("SublevelIndent");
}
else if (double.IsInfinity(newValue))
{
throw DataGridError.DataGrid.ValueCannotBeSetToInfinity("SublevelIndent");
}
else if (newValue < 0)
{
throw DataGridError.DataGrid.ValueMustBeGreaterThanOrEqualTo("value", "SublevelIndent", 0);
}
if (groupHeader.OwningGrid != null)
{
groupHeader.OwningGrid.OnSublevelIndentUpdated(groupHeader, newValue);
}
}
/// <summary>
/// Gets the ICollectionViewGroup implementation associated with this <see cref="DataGridRowGroupHeader"/>.
/// </summary>
public ICollectionViewGroup CollectionViewGroup
{
get
{
return this.RowGroupInfo == null ? null : this.RowGroupInfo.CollectionViewGroup;
}
}
internal DataGridRowHeader HeaderCell
{
get
{
return this.HeaderElement;
}
}
private DataGridRowHeader HeaderElement
{
get;
set;
}
private bool IsCurrent
{
get
{
Debug.Assert(this.OwningGrid != null, "Expected non-null OwningGrid.");
return this.RowGroupInfo.Slot == this.OwningGrid.CurrentSlot;
}
}
private bool IsPointerOver
{
get;
set;
}
private bool IsPressed
{
get;
set;
}
internal bool IsRecycled
{
get;
set;
}
internal DataGrid OwningGrid
{
get;
set;
}
internal DataGridRowGroupInfo RowGroupInfo
{
get;
set;
}
internal double TotalIndent
{
set
{
_totalIndent = value;
if (_indentSpacer != null)
{
_indentSpacer.Width = _totalIndent;
}
}
}
internal void ApplyHeaderState(bool animate)
{
if (this.HeaderElement != null && this.OwningGrid.AreRowHeadersVisible)
{
this.HeaderElement.ApplyOwnerState(animate);
}
}
internal void ApplyState(bool useTransitions)
{
// Common States
if (this.IsPressed)
{
VisualStates.GoToState(this, useTransitions, VisualStates.StatePressed, VisualStates.StatePointerOver, VisualStates.StateNormal);
}
else if (this.IsPointerOver)
{
VisualStates.GoToState(this, useTransitions, VisualStates.StatePointerOver, VisualStates.StateNormal);
}
else
{
VisualStates.GoToState(this, useTransitions, VisualStates.StateNormal);
}
// Current States
if (this.IsCurrent && !this.OwningGrid.ColumnHeaderHasFocus)
{
if (this.OwningGrid.ContainsFocus)
{
VisualStates.GoToState(this, useTransitions, VisualStates.StateCurrentWithFocus, VisualStates.StateCurrent, VisualStates.StateRegular);
}
else
{
VisualStates.GoToState(this, useTransitions, VisualStates.StateCurrent, VisualStates.StateRegular);
}
}
else
{
VisualStates.GoToState(this, useTransitions, VisualStates.StateRegular);
}
// Expanded States
if (this.RowGroupInfo.CollectionViewGroup.GroupItems.Count == 0)
{
VisualStates.GoToState(this, useTransitions, VisualStates.StateEmpty);
}
else
{
if (this.RowGroupInfo.Visibility == Visibility.Visible)
{
VisualStates.GoToState(this, useTransitions, VisualStates.StateExpanded, VisualStates.StateEmpty);
}
else
{
VisualStates.GoToState(this, useTransitions, VisualStates.StateCollapsed, VisualStates.StateEmpty);
}
}
}
/// <summary>
/// ArrangeOverride
/// </summary>
/// <param name="finalSize">The final area within the parent that this object should use to arrange itself and its children.</param>
/// <returns>The actual size that is used after the element is arranged in layout.</returns>
protected override Size ArrangeOverride(Size finalSize)
{
if (this.OwningGrid == null)
{
return base.ArrangeOverride(finalSize);
}
Size size = base.ArrangeOverride(finalSize);
if (_rootElement != null)
{
if (this.OwningGrid.AreRowGroupHeadersFrozen)
{
foreach (UIElement child in _rootElement.Children)
{
child.Clip = null;
}
}
else
{
double frozenLeftEdge = 0;
foreach (UIElement child in _rootElement.Children)
{
if (DataGridFrozenGrid.GetIsFrozen(child) && child.Visibility == Visibility.Visible)
{
TranslateTransform transform = new TranslateTransform();
// Automatic layout rounding doesn't apply to transforms so we need to Round this
transform.X = Math.Round(this.OwningGrid.HorizontalOffset);
child.RenderTransform = transform;
double childLeftEdge = child.Translate(this, new Point(child.RenderSize.Width, 0)).X - transform.X;
frozenLeftEdge = Math.Max(frozenLeftEdge, childLeftEdge + this.OwningGrid.HorizontalOffset);
}
}
// Clip the non-frozen elements so they don't overlap the frozen ones
foreach (UIElement child in _rootElement.Children)
{
if (!DataGridFrozenGrid.GetIsFrozen(child))
{
EnsureChildClip(child, frozenLeftEdge);
}
}
}
}
return size;
}
internal void ClearFrozenStates()
{
if (_rootElement != null)
{
foreach (UIElement child in _rootElement.Children)
{
child.RenderTransform = null;
}
}
}
private void DataGridRowGroupHeader_Tapped(object sender, TappedRoutedEventArgs e)
{
if (this.OwningGrid != null && !this.OwningGrid.HasColumnUserInteraction)
{
if (!e.Handled && this.OwningGrid.IsTabStop)
{
bool success = this.OwningGrid.Focus(FocusState.Programmatic);
Debug.Assert(success, "Expected successful focus change.");
}
e.Handled = this.OwningGrid.UpdateStateOnTapped(e, this.OwningGrid.CurrentColumnIndex, this.RowGroupInfo.Slot, false /*allowEdit*/);
}
}
private void DataGridRowGroupHeader_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
if (this.OwningGrid != null && !this.OwningGrid.HasColumnUserInteraction && !e.Handled)
{
ToggleExpandCollapse(this.RowGroupInfo.Visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible, true);
e.Handled = true;
}
}
private void EnsureChildClip(UIElement child, double frozenLeftEdge)
{
double childLeftEdge = child.Translate(this, new Point(0, 0)).X;
if (frozenLeftEdge > childLeftEdge)
{
double xClip = Math.Round(frozenLeftEdge - childLeftEdge);
RectangleGeometry rg = new RectangleGeometry();
rg.Rect = new Rect(xClip, 0, Math.Max(0, child.RenderSize.Width - xClip), child.RenderSize.Height);
child.Clip = rg;
}
else
{
child.Clip = null;
}
}
internal void EnsureExpanderButtonIsChecked()
{
if (_expanderButton != null &&
this.RowGroupInfo != null &&
this.RowGroupInfo.CollectionViewGroup != null &&
this.RowGroupInfo.CollectionViewGroup.GroupItems != null &&
this.RowGroupInfo.CollectionViewGroup.GroupItems.Count != 0)
{
SetIsCheckedNoCallBack(this.RowGroupInfo.Visibility == Visibility.Visible);
}
}
internal void EnsureHeaderStyleAndVisibility(Style previousStyle)
{
if (this.HeaderElement != null && this.OwningGrid != null)
{
if (this.OwningGrid.AreRowHeadersVisible)
{
this.HeaderElement.EnsureStyle(previousStyle);
this.HeaderElement.Visibility = Visibility.Visible;
}
else
{
this.HeaderElement.Visibility = Visibility.Collapsed;
}
}
}
private void ExpanderButton_Checked(object sender, RoutedEventArgs e)
{
if (!_areIsCheckedHandlersSuspended)
{
ToggleExpandCollapse(Visibility.Visible, true);
}
}
private void ExpanderButton_Unchecked(object sender, RoutedEventArgs e)
{
if (!_areIsCheckedHandlersSuspended)
{
ToggleExpandCollapse(Visibility.Collapsed, true);
}
}
internal void LoadVisualsForDisplay()
{
EnsureExpanderButtonIsChecked();
EnsureHeaderStyleAndVisibility(null);
ApplyState(false /*useTransitions*/);
ApplyHeaderState(false);
}
/// <summary>
/// Builds the visual tree for the row group header when a new template is applied.
/// </summary>
protected override void OnApplyTemplate()
{
_rootElement = GetTemplateChild(DataGridRow.DATAGRIDROW_elementRoot) as Panel;
if (_expanderButton != null)
{
_expanderButton.Checked -= ExpanderButton_Checked;
_expanderButton.Unchecked -= ExpanderButton_Unchecked;
}
_bottomGridLine = GetTemplateChild(DATAGRIDROWGROUPHEADER_bottomGridLine) as Rectangle;
_expanderButton = GetTemplateChild(DATAGRIDROWGROUPHEADER_expanderButton) as ToggleButton;
if (_expanderButton != null)
{
EnsureExpanderButtonIsChecked();
_expanderButton.Checked += new RoutedEventHandler(ExpanderButton_Checked);
_expanderButton.Unchecked += new RoutedEventHandler(ExpanderButton_Unchecked);
}
this.HeaderElement = GetTemplateChild(DataGridRow.DATAGRIDROW_elementRowHeader) as DataGridRowHeader;
if (this.HeaderElement != null)
{
this.HeaderElement.Owner = this;
EnsureHeaderStyleAndVisibility(null);
}
_indentSpacer = GetTemplateChild(DATAGRIDROWGROUPHEADER_indentSpacer) as FrameworkElement;
if (_indentSpacer != null)
{
_indentSpacer.Width = _totalIndent;
}
_itemCountElement = GetTemplateChild(DATAGRIDROWGROUPHEADER_itemCountElement) as TextBlock;
_propertyNameElement = GetTemplateChild(DATAGRIDROWGROUPHEADER_propertyNameElement) as TextBlock;
_propertyValueElement = GetTemplateChild(DATAGRIDROWGROUPHEADER_propertyValueElement) as TextBlock;
UpdateTitleElements();
EnsureGridLine();
}
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="DataGridRowGroupHeader"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new DataGridRowGroupHeaderAutomationPeer(this);
}
private void SetIsCheckedNoCallBack(bool value)
{
if (_expanderButton != null && _expanderButton.IsChecked != value)
{
_areIsCheckedHandlersSuspended = true;
try
{
_expanderButton.IsChecked = value;
}
finally
{
_areIsCheckedHandlersSuspended = false;
}
}
}
internal void ToggleExpandCollapse(Visibility newVisibility, bool setCurrent)
{
if (this.RowGroupInfo.CollectionViewGroup.GroupItems.Count != 0)
{
if (this.OwningGrid == null)
{
// Do these even if the OwningGrid is null in case it could improve the Designer experience for a standalone DataGridRowGroupHeader
this.RowGroupInfo.Visibility = newVisibility;
}
else
{
this.OwningGrid.OnRowGroupHeaderToggled(this, newVisibility, setCurrent);
}
EnsureExpanderButtonIsChecked();
ApplyState(true /*useTransitions*/);
}
}
internal void UpdateTitleElements()
{
string propertyName = this.PropertyName;
bool hasPropertyValue = _propertyValueElement != null && !string.IsNullOrEmpty(this.PropertyValue);
if (_propertyNameElement != null)
{
if (!string.IsNullOrWhiteSpace(propertyName) && this.OwningGrid.DataConnection.DataType != null)
{
string displayName = this.OwningGrid.DataConnection.DataType.GetDisplayName(propertyName);
if (!string.IsNullOrWhiteSpace(displayName))
{
propertyName = displayName;
}
}
if (string.IsNullOrEmpty(propertyName))
{
propertyName = this.OwningGrid.RowGroupHeaderPropertyNameAlternative;
}
if (!string.IsNullOrEmpty(propertyName) && hasPropertyValue)
{
propertyName = string.Format(CultureInfo.CurrentCulture, Properties.Resources.DataGridRowGroupHeader_PropertyName, propertyName);
}
if (!string.IsNullOrEmpty(propertyName))
{
_propertyNameElement.Text = propertyName;
}
}
if (hasPropertyValue)
{
_propertyValueElement.Text = this.PropertyValue;
}
if (_itemCountElement != null && this.RowGroupInfo != null && this.RowGroupInfo.CollectionViewGroup != null)
{
_itemCountElement.Text = string.Format(
CultureInfo.CurrentCulture,
this.RowGroupInfo.CollectionViewGroup.GroupItems.Count == 1 ? Properties.Resources.DataGridRowGroupHeader_ItemCountSingular : Properties.Resources.DataGridRowGroupHeader_ItemCountPlural,
this.RowGroupInfo.CollectionViewGroup.GroupItems.Count);
}
}
private void DataGridRowGroupHeader_PointerCanceled(object sender, PointerRoutedEventArgs e)
{
UpdateIsPointerOver(false);
UpdateIsPressed(false);
}
private void DataGridRowGroupHeader_PointerEntered(object sender, PointerRoutedEventArgs e)
{
UpdateIsPointerOver(true);
}
private void DataGridRowGroupHeader_PointerExited(object sender, PointerRoutedEventArgs e)
{
UpdateIsPointerOver(false);
}
private void DataGridRowGroupHeader_PointerMoved(object sender, PointerRoutedEventArgs e)
{
UpdateIsPointerOver(true);
}
private void DataGridRowGroupHeader_PointerPressed(object sender, PointerRoutedEventArgs e)
{
UpdateIsPressed(true);
}
private void DataGridRowGroupHeader_PointerReleased(object sender, PointerRoutedEventArgs e)
{
UpdateIsPressed(false);
}
internal void EnsureGridLine()
{
if (this.OwningGrid != null && _bottomGridLine != null)
{
Visibility newVisibility = this.OwningGrid.GridLinesVisibility == DataGridGridLinesVisibility.Horizontal || this.OwningGrid.GridLinesVisibility == DataGridGridLinesVisibility.All
? Visibility.Visible : Visibility.Collapsed;
if (newVisibility != _bottomGridLine.Visibility)
{
_bottomGridLine.Visibility = newVisibility;
}
_bottomGridLine.Fill = this.OwningGrid.HorizontalGridLinesBrush;
}
}
private void UpdateIsPointerOver(bool isPointerOver)
{
if (!this.IsEnabled || isPointerOver == this.IsPointerOver)
{
return;
}
this.IsPointerOver = isPointerOver;
ApplyState(true /*useTransitions*/);
}
private void UpdateIsPressed(bool isPressed)
{
if (!this.IsEnabled || isPressed == this.IsPressed)
{
return;
}
this.IsPressed = isPressed;
ApplyState(true /*useTransitions*/);
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// EventArgs used for the DataGrid's LoadingRowGroup and UnloadingRowGroup events
/// </summary>
public class DataGridRowGroupHeaderEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowGroupHeaderEventArgs"/> class.
/// </summary>
/// <param name="rowGroupHeader">The row group header that the event occurs for.</param>
public DataGridRowGroupHeaderEventArgs(DataGridRowGroupHeader rowGroupHeader)
{
this.RowGroupHeader = rowGroupHeader;
}
/// <summary>
/// Gets the <see cref="DataGridRowGroupHeader"/> associated with this instance.
/// </summary>
public DataGridRowGroupHeader RowGroupHeader
{
get;
private set;
}
}
}

Просмотреть файл

@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals
{
internal class DataGridRowGroupInfo
{
public DataGridRowGroupInfo(
ICollectionViewGroup collectionViewGroup,
Visibility visibility,
int level,
int slot,
int lastSubItemSlot)
{
this.CollectionViewGroup = collectionViewGroup;
this.Visibility = visibility;
this.Level = level;
this.Slot = slot;
this.LastSubItemSlot = lastSubItemSlot;
}
public ICollectionViewGroup CollectionViewGroup
{
get;
private set;
}
public int LastSubItemSlot
{
get;
set;
}
public int Level
{
get;
private set;
}
public int Slot
{
get;
set;
}
public Visibility Visibility
{
get;
set;
}
}
}

Просмотреть файл

@ -0,0 +1,443 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Microsoft.Toolkit.Uwp.UI.Controls.Utilities;
using Microsoft.Toolkit.Uwp.UI.Utilities;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Primitives
{
/// <summary>
/// Represents an individual <see cref="DataGrid"/> row header.
/// </summary>
[TemplatePart(Name = DATAGRIDROWHEADER_elementRootName, Type = typeof(FrameworkElement))]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateNormal, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateNormalCurrentRow, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateNormalEditingRow, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateNormalEditingRowFocused, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOver, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOverCurrentRow, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOverEditingRow, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOverEditingRowFocused, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOverSelected, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOverSelectedFocused, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOverSelectedCurrentRow, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowFocused, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateSelected, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateSelectedCurrentRow, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateSelectedCurrentRowFocused, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = DATAGRIDROWHEADER_stateSelectedFocused, GroupName = VisualStates.GroupCommon)]
[TemplateVisualState(Name = VisualStates.StateRowInvalid, GroupName = VisualStates.GroupValidation)]
[TemplateVisualState(Name = VisualStates.StateRowValid, GroupName = VisualStates.GroupValidation)]
public partial class DataGridRowHeader : ContentControl
{
private const string DATAGRIDROWHEADER_elementRootName = "RowHeaderRoot";
private const double DATAGRIDROWHEADER_separatorThickness = 1;
private const string DATAGRIDROWHEADER_statePointerOver = "PointerOver";
private const string DATAGRIDROWHEADER_statePointerOverCurrentRow = "PointerOverCurrentRow";
private const string DATAGRIDROWHEADER_statePointerOverEditingRow = "PointerOverUnfocusedEditingRow";
private const string DATAGRIDROWHEADER_statePointerOverEditingRowFocused = "PointerOverEditingRow";
private const string DATAGRIDROWHEADER_statePointerOverSelected = "PointerOverUnfocusedSelected";
private const string DATAGRIDROWHEADER_statePointerOverSelectedCurrentRow = "PointerOverUnfocusedCurrentRowSelected";
private const string DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowFocused = "PointerOverCurrentRowSelected";
private const string DATAGRIDROWHEADER_statePointerOverSelectedFocused = "PointerOverSelected";
private const string DATAGRIDROWHEADER_stateNormal = "Normal";
private const string DATAGRIDROWHEADER_stateNormalCurrentRow = "NormalCurrentRow";
private const string DATAGRIDROWHEADER_stateNormalEditingRow = "UnfocusedEditingRow";
private const string DATAGRIDROWHEADER_stateNormalEditingRowFocused = "NormalEditingRow";
private const string DATAGRIDROWHEADER_stateSelected = "UnfocusedSelected";
private const string DATAGRIDROWHEADER_stateSelectedCurrentRow = "UnfocusedCurrentRowSelected";
private const string DATAGRIDROWHEADER_stateSelectedCurrentRowFocused = "NormalCurrentRowSelected";
private const string DATAGRIDROWHEADER_stateSelectedFocused = "NormalSelected";
private const byte DATAGRIDROWHEADER_statePointerOverCode = 0;
private const byte DATAGRIDROWHEADER_statePointerOverCurrentRowCode = 1;
private const byte DATAGRIDROWHEADER_statePointerOverEditingRowCode = 2;
private const byte DATAGRIDROWHEADER_statePointerOverEditingRowFocusedCode = 3;
private const byte DATAGRIDROWHEADER_statePointerOverSelectedCode = 4;
private const byte DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowCode = 5;
private const byte DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowFocusedCode = 6;
private const byte DATAGRIDROWHEADER_statePointerOverSelectedFocusedCode = 7;
private const byte DATAGRIDROWHEADER_stateNormalCode = 8;
private const byte DATAGRIDROWHEADER_stateNormalCurrentRowCode = 9;
private const byte DATAGRIDROWHEADER_stateNormalEditingRowCode = 10;
private const byte DATAGRIDROWHEADER_stateNormalEditingRowFocusedCode = 11;
private const byte DATAGRIDROWHEADER_stateSelectedCode = 12;
private const byte DATAGRIDROWHEADER_stateSelectedCurrentRowCode = 13;
private const byte DATAGRIDROWHEADER_stateSelectedCurrentRowFocusedCode = 14;
private const byte DATAGRIDROWHEADER_stateSelectedFocusedCode = 15;
private const byte DATAGRIDROWHEADER_stateNullCode = 255;
private static byte[] _fallbackStateMapping = new byte[]
{
DATAGRIDROWHEADER_stateNormalCode,
DATAGRIDROWHEADER_stateNormalCurrentRowCode,
DATAGRIDROWHEADER_statePointerOverEditingRowFocusedCode,
DATAGRIDROWHEADER_stateNormalEditingRowFocusedCode,
DATAGRIDROWHEADER_statePointerOverSelectedFocusedCode,
DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowFocusedCode,
DATAGRIDROWHEADER_stateSelectedFocusedCode,
DATAGRIDROWHEADER_stateSelectedFocusedCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateNormalCode,
DATAGRIDROWHEADER_stateNormalEditingRowFocusedCode,
DATAGRIDROWHEADER_stateSelectedCurrentRowFocusedCode,
DATAGRIDROWHEADER_stateSelectedFocusedCode,
DATAGRIDROWHEADER_stateSelectedCurrentRowFocusedCode,
DATAGRIDROWHEADER_stateNormalCurrentRowCode,
DATAGRIDROWHEADER_stateNormalCode,
};
private static byte[] _idealStateMapping = new byte[]
{
DATAGRIDROWHEADER_stateNormalCode,
DATAGRIDROWHEADER_stateNormalCode,
DATAGRIDROWHEADER_statePointerOverCode,
DATAGRIDROWHEADER_statePointerOverCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateSelectedCode,
DATAGRIDROWHEADER_stateSelectedFocusedCode,
DATAGRIDROWHEADER_statePointerOverSelectedCode,
DATAGRIDROWHEADER_statePointerOverSelectedFocusedCode,
DATAGRIDROWHEADER_stateNormalEditingRowCode,
DATAGRIDROWHEADER_stateNormalEditingRowFocusedCode,
DATAGRIDROWHEADER_statePointerOverEditingRowCode,
DATAGRIDROWHEADER_statePointerOverEditingRowFocusedCode,
DATAGRIDROWHEADER_stateNormalCurrentRowCode,
DATAGRIDROWHEADER_stateNormalCurrentRowCode,
DATAGRIDROWHEADER_statePointerOverCurrentRowCode,
DATAGRIDROWHEADER_statePointerOverCurrentRowCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateNullCode,
DATAGRIDROWHEADER_stateSelectedCurrentRowCode,
DATAGRIDROWHEADER_stateSelectedCurrentRowFocusedCode,
DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowCode,
DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowFocusedCode,
DATAGRIDROWHEADER_stateNormalEditingRowCode,
DATAGRIDROWHEADER_stateNormalEditingRowFocusedCode,
DATAGRIDROWHEADER_statePointerOverEditingRowCode,
DATAGRIDROWHEADER_statePointerOverEditingRowFocusedCode
};
private static string[] _stateNames = new string[]
{
DATAGRIDROWHEADER_statePointerOver,
DATAGRIDROWHEADER_statePointerOverCurrentRow,
DATAGRIDROWHEADER_statePointerOverEditingRow,
DATAGRIDROWHEADER_statePointerOverEditingRowFocused,
DATAGRIDROWHEADER_statePointerOverSelected,
DATAGRIDROWHEADER_statePointerOverSelectedCurrentRow,
DATAGRIDROWHEADER_statePointerOverSelectedCurrentRowFocused,
DATAGRIDROWHEADER_statePointerOverSelectedFocused,
DATAGRIDROWHEADER_stateNormal,
DATAGRIDROWHEADER_stateNormalCurrentRow,
DATAGRIDROWHEADER_stateNormalEditingRow,
DATAGRIDROWHEADER_stateNormalEditingRowFocused,
DATAGRIDROWHEADER_stateSelected,
DATAGRIDROWHEADER_stateSelectedCurrentRow,
DATAGRIDROWHEADER_stateSelectedCurrentRowFocused,
DATAGRIDROWHEADER_stateSelectedFocused
};
private FrameworkElement _rootElement;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowHeader"/> class.
/// </summary>
public DataGridRowHeader()
{
this.IsTapEnabled = true;
this.AddHandler(UIElement.TappedEvent, new TappedEventHandler(DataGridRowHeader_Tapped), true /*handledEventsToo*/);
DefaultStyleKey = typeof(DataGridRowHeader);
}
/// <summary>
/// Gets or sets the <see cref="T:System.Windows.Media.Brush"/> used to paint the row header separator lines.
/// </summary>
public Brush SeparatorBrush
{
get { return GetValue(SeparatorBrushProperty) as Brush; }
set { SetValue(SeparatorBrushProperty, value); }
}
/// <summary>
/// Identifies the <see cref="Microsoft.Toolkit.Uwp.UI.Controls.Primitives.DataGridRowHeader.SeparatorBrush"/> dependency property.
/// </summary>
public static readonly DependencyProperty SeparatorBrushProperty =
DependencyProperty.Register(
"SeparatorBrush",
typeof(Brush),
typeof(DataGridRowHeader),
null);
/// <summary>
/// Gets or sets a value indicating whether the row header separator lines are visible.
/// </summary>
public Visibility SeparatorVisibility
{
get { return (Visibility)GetValue(SeparatorVisibilityProperty); }
set { SetValue(SeparatorVisibilityProperty, value); }
}
/// <summary>
/// Identifies the <see cref="Microsoft.Toolkit.Uwp.UI.Controls.Primitives.DataGridRowHeader.SeparatorVisibility"/> dependency property.
/// </summary>
public static readonly DependencyProperty SeparatorVisibilityProperty =
DependencyProperty.Register(
"SeparatorVisibility",
typeof(Visibility),
typeof(DataGridRowHeader),
new PropertyMetadata(Visibility.Visible));
private DataGrid OwningGrid
{
get
{
if (this.OwningRow != null)
{
return this.OwningRow.OwningGrid;
}
else if (this.OwningRowGroupHeader != null)
{
return this.OwningRowGroupHeader.OwningGrid;
}
return null;
}
}
private DataGridRow OwningRow
{
get
{
return this.Owner as DataGridRow;
}
}
private DataGridRowGroupHeader OwningRowGroupHeader
{
get
{
return this.Owner as DataGridRowGroupHeader;
}
}
internal Control Owner
{
get;
set;
}
private int Slot
{
get
{
if (this.OwningRow != null)
{
return this.OwningRow.Slot;
}
else if (this.OwningRowGroupHeader != null)
{
return this.OwningRowGroupHeader.RowGroupInfo.Slot;
}
return -1;
}
}
/// <summary>
/// Builds the visual tree for the row header when a new template is applied.
/// </summary>
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_rootElement = GetTemplateChild(DATAGRIDROWHEADER_elementRootName) as FrameworkElement;
if (_rootElement != null)
{
ApplyOwnerState(false /*animate*/);
}
}
/// <summary>
/// Measures the children of a <see cref="T:System.Windows.Controls.Primitives.DataGridRowHeader"/> to prepare for arranging them during the <see cref="M:System.Windows.FrameworkElement.ArrangeOverride(System.Windows.Size)"/> pass.
/// </summary>
/// <param name="availableSize">
/// The available size that this element can give to child elements. Indicates an upper limit that child elements should not exceed.
/// </param>
/// <returns>
/// The size that the <see cref="T:System.Windows.Controls.Primitives.DataGridRowHeader"/> determines it needs during layout, based on its calculations of child object allocated sizes.
/// </returns>
protected override Size MeasureOverride(Size availableSize)
{
if (this.OwningRow == null || this.OwningGrid == null)
{
return base.MeasureOverride(availableSize);
}
double measureHeight = double.IsNaN(this.OwningGrid.RowHeight) ? availableSize.Height : this.OwningGrid.RowHeight;
double measureWidth = double.IsNaN(this.OwningGrid.RowHeaderWidth) ? availableSize.Width : this.OwningGrid.RowHeaderWidth;
Size measuredSize = base.MeasureOverride(new Size(measureWidth, measureHeight));
// Auto grow the row header or force it to a fixed width based on the DataGrid's setting
if (!double.IsNaN(this.OwningGrid.RowHeaderWidth) || measuredSize.Width < this.OwningGrid.ActualRowHeaderWidth)
{
return new Size(this.OwningGrid.ActualRowHeaderWidth, measuredSize.Height);
}
return measuredSize;
}
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="T:System.Windows.Controls.Primitives.DataGridRowHeader"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new DataGridRowHeaderAutomationPeer(this);
}
internal void ApplyOwnerState(bool animate)
{
if (_rootElement != null && this.Owner != null && this.Owner.Visibility == Visibility.Visible)
{
byte idealStateMappingIndex = 0;
if (this.OwningRow != null)
{
if (this.OwningRow.IsValid)
{
VisualStates.GoToState(this, true, VisualStates.StateRowValid);
}
else
{
VisualStates.GoToState(this, true, VisualStates.StateRowInvalid, VisualStates.StateRowValid);
}
if (this.OwningGrid != null)
{
if (this.OwningGrid.CurrentSlot == this.OwningRow.Slot)
{
idealStateMappingIndex += 16;
}
if (this.OwningGrid.ContainsFocus)
{
idealStateMappingIndex += 1;
}
}
if (this.OwningRow.IsSelected || this.OwningRow.IsEditing)
{
idealStateMappingIndex += 8;
}
if (this.OwningRow.IsEditing)
{
idealStateMappingIndex += 4;
}
if (this.OwningRow.IsPointerOver)
{
idealStateMappingIndex += 2;
}
}
else if (this.OwningRowGroupHeader != null && this.OwningGrid != null && this.OwningGrid.CurrentSlot == this.OwningRowGroupHeader.RowGroupInfo.Slot)
{
idealStateMappingIndex += 16;
}
byte stateCode = _idealStateMapping[idealStateMappingIndex];
Debug.Assert(stateCode != DATAGRIDROWHEADER_stateNullCode, "Expected stateCode other than DATAGRIDROWHEADER_stateNullCode.");
string storyboardName;
while (stateCode != DATAGRIDROWHEADER_stateNullCode)
{
storyboardName = _stateNames[stateCode];
if (VisualStateManager.GoToState(this, storyboardName, animate))
{
break;
}
else
{
// The state wasn't implemented so fall back to the next one
stateCode = _fallbackStateMapping[stateCode];
}
}
}
}
/// <summary>
/// Ensures that the correct Style is applied to this object.
/// </summary>
/// <param name="previousStyle">Caller's previous associated Style</param>
internal void EnsureStyle(Style previousStyle)
{
if (this.Style != null &&
this.OwningRow != null &&
this.Style != this.OwningRow.HeaderStyle &&
this.OwningRowGroupHeader != null &&
this.Style != this.OwningRowGroupHeader.HeaderStyle &&
this.OwningGrid != null &&
this.Style != this.OwningGrid.RowHeaderStyle &&
this.Style != previousStyle)
{
return;
}
Style style = null;
if (this.OwningRow != null)
{
style = this.OwningRow.HeaderStyle;
}
if (style == null && this.OwningGrid != null)
{
style = this.OwningGrid.RowHeaderStyle;
}
this.SetStyleWithType(style);
}
private void DataGridRowHeader_Tapped(object sender, TappedRoutedEventArgs e)
{
if (this.OwningGrid != null && !this.OwningGrid.HasColumnUserInteraction)
{
if (!e.Handled && this.OwningGrid.IsTabStop)
{
bool success = this.OwningGrid.Focus(FocusState.Programmatic);
Debug.Assert(success, "Expected successful focus change.");
}
if (this.OwningRow != null)
{
Debug.Assert(sender is DataGridRowHeader, "Expected sender is DataGridRowHeader.");
Debug.Assert(sender as ContentControl == this, "Expected sender is this.");
e.Handled = this.OwningGrid.UpdateStateOnTapped(e, -1, this.Slot, false /*allowEdit*/);
this.OwningGrid.UpdatedStateOnTapped = true;
}
}
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,234 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Automation.Peers;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Primitives
{
/// <summary>
/// Used within the template of a <see cref="DataGrid"/> to specify the
/// location in the control's visual tree where the rows are to be added.
/// </summary>
public sealed class DataGridRowsPresenter : Panel
{
private double _preManipulationHorizontalOffset;
private double _preManipulationVerticalOffset;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridRowsPresenter"/> class.
/// </summary>
public DataGridRowsPresenter()
{
this.ManipulationStarting += new ManipulationStartingEventHandler(DataGridRowsPresenter_ManipulationStarting);
this.ManipulationStarted += new ManipulationStartedEventHandler(DataGridRowsPresenter_ManipulationStarted);
this.ManipulationDelta += new ManipulationDeltaEventHandler(DataGridRowsPresenter_ManipulationDelta);
}
internal DataGrid OwningGrid
{
get;
set;
}
/// <summary>
/// Arranges the content of the <see cref="DataGridRowsPresenter"/>.
/// </summary>
/// <returns>
/// The actual size used by the <see cref="DataGridRowsPresenter"/>.
/// </returns>
/// <param name="finalSize">
/// The final area within the parent that this element should use to arrange itself and its children.
/// </param>
protected override Size ArrangeOverride(Size finalSize)
{
if (finalSize.Height == 0 || this.OwningGrid == null)
{
return base.ArrangeOverride(finalSize);
}
this.OwningGrid.OnFillerColumnWidthNeeded(finalSize.Width);
double rowDesiredWidth = this.OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth + this.OwningGrid.ColumnsInternal.FillerColumn.FillerWidth;
double topEdge = -this.OwningGrid.NegVerticalOffset;
foreach (UIElement element in this.OwningGrid.DisplayData.GetScrollingElements())
{
DataGridRow row = element as DataGridRow;
if (row != null)
{
Debug.Assert(row.Index != -1, "Expected Index other than -1."); // A displayed row should always have its index
// Visibility for all filler cells needs to be set in one place. Setting it individually in
// each CellsPresenter causes an NxN layout cycle (see DevDiv Bugs 211557)
row.EnsureFillerVisibility();
row.Arrange(new Rect(-this.OwningGrid.HorizontalOffset, topEdge, rowDesiredWidth, element.DesiredSize.Height));
}
else
{
DataGridRowGroupHeader groupHeader = element as DataGridRowGroupHeader;
if (groupHeader != null)
{
double leftEdge = this.OwningGrid.AreRowGroupHeadersFrozen ? 0 : -this.OwningGrid.HorizontalOffset;
groupHeader.Arrange(new Rect(leftEdge, topEdge, rowDesiredWidth - leftEdge, element.DesiredSize.Height));
}
}
topEdge += element.DesiredSize.Height;
}
double finalHeight = Math.Max(topEdge + this.OwningGrid.NegVerticalOffset, finalSize.Height);
// Clip the RowsPresenter so rows cannot overlap other elements in certain styling scenarios
RectangleGeometry rg = new RectangleGeometry();
rg.Rect = new Rect(0, 0, finalSize.Width, finalHeight);
this.Clip = rg;
return new Size(finalSize.Width, finalHeight);
}
/// <summary>
/// Measures the children of a <see cref="DataGridRowsPresenter"/> to
/// prepare for arranging them during the <see cref="M:System.Windows.FrameworkElement.ArrangeOverride(System.Windows.Size)"/> pass.
/// </summary>
/// <param name="availableSize">
/// The available size that this element can give to child elements. Indicates an upper limit that child elements should not exceed.
/// </param>
/// <returns>
/// The size that the <see cref="DataGridRowsPresenter"/> determines it needs during layout, based on its calculations of child object allocated sizes.
/// </returns>
protected override Size MeasureOverride(Size availableSize)
{
if (availableSize.Height == 0 || this.OwningGrid == null)
{
return base.MeasureOverride(availableSize);
}
// If the Width of our RowsPresenter changed then we need to invalidate our rows
bool invalidateRows =
(!this.OwningGrid.RowsPresenterAvailableSize.HasValue || availableSize.Width != this.OwningGrid.RowsPresenterAvailableSize.Value.Width) &&
!double.IsInfinity(availableSize.Width);
// The DataGrid uses the RowsPresenter available size in order to autogrow
// and calculate the scrollbars
this.OwningGrid.RowsPresenterAvailableSize = availableSize;
this.OwningGrid.OnRowsMeasure();
double totalHeight = -this.OwningGrid.NegVerticalOffset;
double totalCellsWidth = this.OwningGrid.ColumnsInternal.VisibleEdgedColumnsWidth;
double headerWidth = 0;
foreach (UIElement element in this.OwningGrid.DisplayData.GetScrollingElements())
{
DataGridRow row = element as DataGridRow;
if (row != null)
{
if (invalidateRows)
{
row.InvalidateMeasure();
}
}
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
if (row != null && row.HeaderCell != null)
{
headerWidth = Math.Max(headerWidth, row.HeaderCell.DesiredSize.Width);
}
else
{
DataGridRowGroupHeader groupHeader = element as DataGridRowGroupHeader;
if (groupHeader != null && groupHeader.HeaderCell != null)
{
headerWidth = Math.Max(headerWidth, groupHeader.HeaderCell.DesiredSize.Width);
}
}
totalHeight += element.DesiredSize.Height;
}
this.OwningGrid.RowHeadersDesiredWidth = headerWidth;
// Could be positive infinity depending on the DataGrid's bounds
this.OwningGrid.AvailableSlotElementRoom = availableSize.Height - totalHeight;
// TODO: totalHeight can be negative if we've just collapsed details. This is a workaround,
// the real fix is to correct NegVerticalOffset.
totalHeight = Math.Max(0, totalHeight);
return new Size(totalCellsWidth + headerWidth, totalHeight);
}
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="DataGridRowsPresenter"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new DataGridRowsPresenterAutomationPeer(this);
}
private void DataGridRowsPresenter_ManipulationStarting(object sender, ManipulationStartingRoutedEventArgs e)
{
if (this.OwningGrid != null)
{
Debug.Assert(this.OwningGrid.IsEnabled, "Expected OwningGrid.IsEnabled is true.");
_preManipulationHorizontalOffset = this.OwningGrid.HorizontalOffset;
_preManipulationVerticalOffset = this.OwningGrid.VerticalOffset;
}
}
private void DataGridRowsPresenter_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
if (e.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Touch)
{
e.Complete();
}
}
private void DataGridRowsPresenter_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
if (this.OwningGrid != null)
{
e.Handled =
this.OwningGrid.ProcessScrollOffsetDelta(_preManipulationHorizontalOffset - e.Cumulative.Translation.X - this.OwningGrid.HorizontalOffset, true /*isForHorizontalScroll*/) ||
this.OwningGrid.ProcessScrollOffsetDelta(_preManipulationVerticalOffset - e.Cumulative.Translation.Y - this.OwningGrid.VerticalOffset, false /*isForHorizontalScroll*/);
}
}
#if DEBUG
internal void PrintChildren()
{
foreach (UIElement element in this.Children)
{
DataGridRow row = element as DataGridRow;
if (row != null)
{
Debug.WriteLine(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Slot: {0} Row: {1} Visibility: {2} ", row.Slot, row.Index, row.Visibility));
}
else
{
DataGridRowGroupHeader groupHeader = element as DataGridRowGroupHeader;
if (groupHeader != null)
{
#if FEATURE_ICOLLECTIONVIEW_GROUP
Debug.WriteLine(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Slot: {0} GroupHeader: {1} Visibility: {2}", groupHeader.RowGroupInfo.Slot, groupHeader.RowGroupInfo.CollectionViewGroup.Name, groupHeader.Visibility));
#else
Debug.WriteLine(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Slot: {0} Visibility: {1}", groupHeader.RowGroupInfo.Slot, groupHeader.Visibility));
#endif
}
}
}
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,494 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
internal class DataGridSelectedItemsCollection : IList
{
private List<object> _oldSelectedItemsCache;
private IndexToValueTable<bool> _oldSelectedSlotsTable;
private List<object> _selectedItemsCache;
private IndexToValueTable<bool> _selectedSlotsTable;
public DataGridSelectedItemsCollection(DataGrid owningGrid)
{
this.OwningGrid = owningGrid;
_oldSelectedItemsCache = new List<object>();
_oldSelectedSlotsTable = new IndexToValueTable<bool>();
_selectedItemsCache = new List<object>();
_selectedSlotsTable = new IndexToValueTable<bool>();
}
public object this[int index]
{
get
{
if (index < 0 || index >= _selectedSlotsTable.IndexCount)
{
throw DataGridError.DataGrid.ValueMustBeBetween("index", "Index", 0, true, _selectedSlotsTable.IndexCount, false);
}
int slot = _selectedSlotsTable.GetNthIndex(index);
Debug.Assert(slot >= 0, "Expected positive slot.");
return this.OwningGrid.DataConnection.GetDataItem(this.OwningGrid.RowIndexFromSlot(slot));
}
set
{
throw new NotSupportedException();
}
}
public bool IsFixedSize
{
get
{
return false;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
public int Add(object dataItem)
{
if (this.OwningGrid.SelectionMode == DataGridSelectionMode.Single)
{
throw DataGridError.DataGridSelectedItemsCollection.CannotChangeSelectedItemsCollectionInSingleMode();
}
int itemIndex = this.OwningGrid.DataConnection.IndexOf(dataItem);
if (itemIndex == -1)
{
throw DataGridError.DataGrid.ItemIsNotContainedInTheItemsSource("dataItem");
}
Debug.Assert(itemIndex >= 0, "Expected positive itemIndex.");
int slot = this.OwningGrid.SlotFromRowIndex(itemIndex);
if (_selectedSlotsTable.RangeCount == 0)
{
this.OwningGrid.SelectedItem = dataItem;
}
else
{
this.OwningGrid.SetRowSelection(slot, true /*isSelected*/, false /*setAnchorSlot*/);
}
return _selectedSlotsTable.IndexOf(slot);
}
public void Clear()
{
if (this.OwningGrid.SelectionMode == DataGridSelectionMode.Single)
{
throw DataGridError.DataGridSelectedItemsCollection.CannotChangeSelectedItemsCollectionInSingleMode();
}
if (_selectedSlotsTable.RangeCount > 0)
{
// Clearing the selection does not reset the potential current cell.
if (!this.OwningGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
{
// Edited value couldn't be committed or aborted
return;
}
this.OwningGrid.ClearRowSelection(true /*resetAnchorSlot*/);
}
}
public bool Contains(object dataItem)
{
int itemIndex = this.OwningGrid.DataConnection.IndexOf(dataItem);
if (itemIndex == -1)
{
return false;
}
Debug.Assert(itemIndex >= 0, "Expected positive itemIndex.");
return ContainsSlot(this.OwningGrid.SlotFromRowIndex(itemIndex));
}
public int IndexOf(object dataItem)
{
int itemIndex = this.OwningGrid.DataConnection.IndexOf(dataItem);
if (itemIndex == -1)
{
return -1;
}
Debug.Assert(itemIndex >= 0, "Expected positive itemIndex.");
int slot = this.OwningGrid.SlotFromRowIndex(itemIndex);
return _selectedSlotsTable.IndexOf(slot);
}
public void Insert(int index, object dataItem)
{
throw new NotSupportedException();
}
public void Remove(object dataItem)
{
if (this.OwningGrid.SelectionMode == DataGridSelectionMode.Single)
{
throw DataGridError.DataGridSelectedItemsCollection.CannotChangeSelectedItemsCollectionInSingleMode();
}
int itemIndex = this.OwningGrid.DataConnection.IndexOf(dataItem);
if (itemIndex == -1)
{
return;
}
Debug.Assert(itemIndex >= 0, "Expected positive itemIndex.");
if (itemIndex == this.OwningGrid.CurrentSlot &&
!this.OwningGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
{
// Edited value couldn't be committed or aborted
return;
}
this.OwningGrid.SetRowSelection(itemIndex, false /*isSelected*/, false /*setAnchorSlot*/);
}
public void RemoveAt(int index)
{
if (this.OwningGrid.SelectionMode == DataGridSelectionMode.Single)
{
throw DataGridError.DataGridSelectedItemsCollection.CannotChangeSelectedItemsCollectionInSingleMode();
}
if (index < 0 || index >= _selectedSlotsTable.IndexCount)
{
throw DataGridError.DataGrid.ValueMustBeBetween("index", "Index", 0, true, _selectedSlotsTable.IndexCount, false);
}
int rowIndex = _selectedSlotsTable.GetNthIndex(index);
Debug.Assert(rowIndex > -1, "Expected positive itemIndex.");
if (rowIndex == this.OwningGrid.CurrentSlot &&
!this.OwningGrid.CommitEdit(DataGridEditingUnit.Row, true /*exitEditing*/))
{
// Edited value couldn't be committed or aborted
return;
}
this.OwningGrid.SetRowSelection(rowIndex, false /*isSelected*/, false /*setAnchorSlot*/);
}
public int Count
{
get
{
return _selectedSlotsTable.IndexCount;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return this;
}
}
public void CopyTo(Array array, int index)
{
// TODO: Not supported yet.
throw new NotImplementedException();
}
public IEnumerator GetEnumerator()
{
Debug.Assert(this.OwningGrid != null, "Expected non-null owning DataGrid.");
Debug.Assert(this.OwningGrid.DataConnection != null, "Expected non-null owning DataGrid.DataConnection.");
Debug.Assert(_selectedSlotsTable != null, "Expected non-null _selectedSlotsTable.");
foreach (int slot in _selectedSlotsTable.GetIndexes())
{
int rowIndex = this.OwningGrid.RowIndexFromSlot(slot);
Debug.Assert(rowIndex > -1, "Expected positive rowIndex.");
yield return this.OwningGrid.DataConnection.GetDataItem(rowIndex);
}
}
internal DataGrid OwningGrid
{
get;
private set;
}
internal List<object> SelectedItemsCache
{
get
{
return _selectedItemsCache;
}
set
{
_selectedItemsCache = value;
UpdateIndexes();
}
}
internal void ClearRows()
{
_selectedSlotsTable.Clear();
_selectedItemsCache.Clear();
}
internal bool ContainsSlot(int slot)
{
return _selectedSlotsTable.Contains(slot);
}
internal bool ContainsAll(int startSlot, int endSlot)
{
int itemSlot = this.OwningGrid.RowGroupHeadersTable.GetNextGap(startSlot - 1);
while (itemSlot <= endSlot)
{
// Skip over the RowGroupHeaderSlots
int nextRowGroupHeaderSlot = this.OwningGrid.RowGroupHeadersTable.GetNextIndex(itemSlot);
int lastItemSlot = nextRowGroupHeaderSlot == -1 ? endSlot : Math.Min(endSlot, nextRowGroupHeaderSlot - 1);
if (!_selectedSlotsTable.ContainsAll(itemSlot, lastItemSlot))
{
return false;
}
itemSlot = this.OwningGrid.RowGroupHeadersTable.GetNextGap(lastItemSlot);
}
return true;
}
// Called when an item is deleted from the ItemsSource as opposed to just being unselected
internal void Delete(int slot, object item)
{
if (_oldSelectedSlotsTable.Contains(slot))
{
this.OwningGrid.SelectionHasChanged = true;
}
DeleteSlot(slot);
_selectedItemsCache.Remove(item);
}
internal void DeleteSlot(int slot)
{
_selectedSlotsTable.RemoveIndex(slot);
_oldSelectedSlotsTable.RemoveIndex(slot);
}
// Returns the inclusive index count between lowerBound and upperBound of all indexes with the given value
internal int GetIndexCount(int lowerBound, int upperBound)
{
return _selectedSlotsTable.GetIndexCount(lowerBound, upperBound, true);
}
internal IEnumerable<int> GetIndexes()
{
return _selectedSlotsTable.GetIndexes();
}
internal IEnumerable<int> GetSlots(int startSlot)
{
return _selectedSlotsTable.GetIndexes(startSlot);
}
internal SelectionChangedEventArgs GetSelectionChangedEventArgs()
{
List<object> addedSelectedItems = new List<object>();
List<object> removedSelectedItems = new List<object>();
// Compare the old selected indexes with the current selection to determine which items
// have been added and removed since the last time this method was called
foreach (int newSlot in _selectedSlotsTable.GetIndexes())
{
object newItem = this.OwningGrid.DataConnection.GetDataItem(this.OwningGrid.RowIndexFromSlot(newSlot));
if (_oldSelectedSlotsTable.Contains(newSlot))
{
_oldSelectedSlotsTable.RemoveValue(newSlot);
_oldSelectedItemsCache.Remove(newItem);
}
else
{
addedSelectedItems.Add(newItem);
}
}
foreach (object oldItem in _oldSelectedItemsCache)
{
removedSelectedItems.Add(oldItem);
}
// The current selection becomes the old selection
_oldSelectedSlotsTable = _selectedSlotsTable.Copy();
_oldSelectedItemsCache = new List<object>(_selectedItemsCache);
return new SelectionChangedEventArgs(removedSelectedItems, addedSelectedItems);
}
internal void InsertIndex(int slot)
{
_selectedSlotsTable.InsertIndex(slot);
_oldSelectedSlotsTable.InsertIndex(slot);
// It's possible that we're inserting an item that was just removed. If that's the case,
// and the re-inserted item used to be selected, we want to update the _oldSelectedSlotsTable
// to include the item's new index within the collection.
int rowIndex = this.OwningGrid.RowIndexFromSlot(slot);
if (rowIndex != -1)
{
object insertedItem = this.OwningGrid.DataConnection.GetDataItem(rowIndex);
if (insertedItem != null && _oldSelectedItemsCache.Contains(insertedItem))
{
_oldSelectedSlotsTable.AddValue(slot, true);
}
}
}
internal void SelectSlot(int slot, bool select)
{
if (this.OwningGrid.RowGroupHeadersTable.Contains(slot))
{
return;
}
if (select)
{
if (!_selectedSlotsTable.Contains(slot))
{
_selectedItemsCache.Add(this.OwningGrid.DataConnection.GetDataItem(this.OwningGrid.RowIndexFromSlot(slot)));
}
_selectedSlotsTable.AddValue(slot, true);
}
else
{
if (_selectedSlotsTable.Contains(slot))
{
_selectedItemsCache.Remove(this.OwningGrid.DataConnection.GetDataItem(this.OwningGrid.RowIndexFromSlot(slot)));
}
_selectedSlotsTable.RemoveValue(slot);
}
}
internal void SelectSlots(int startSlot, int endSlot, bool select)
{
int itemSlot = this.OwningGrid.RowGroupHeadersTable.GetNextGap(startSlot - 1);
int endItemSlot = this.OwningGrid.RowGroupHeadersTable.GetPreviousGap(endSlot + 1);
if (select)
{
while (itemSlot <= endItemSlot)
{
// Add the newly selected item slots by skipping over the RowGroupHeaderSlots
int nextRowGroupHeaderSlot = this.OwningGrid.RowGroupHeadersTable.GetNextIndex(itemSlot);
int lastItemSlot = nextRowGroupHeaderSlot == -1 ? endItemSlot : Math.Min(endItemSlot, nextRowGroupHeaderSlot - 1);
for (int slot = itemSlot; slot <= lastItemSlot; slot++)
{
if (!_selectedSlotsTable.Contains(slot))
{
_selectedItemsCache.Add(this.OwningGrid.DataConnection.GetDataItem(this.OwningGrid.RowIndexFromSlot(slot)));
}
}
_selectedSlotsTable.AddValues(itemSlot, lastItemSlot - itemSlot + 1, true);
itemSlot = this.OwningGrid.RowGroupHeadersTable.GetNextGap(lastItemSlot);
}
}
else
{
while (itemSlot <= endItemSlot)
{
// Remove the unselected item slots by skipping over the RowGroupHeaderSlots
int nextRowGroupHeaderSlot = this.OwningGrid.RowGroupHeadersTable.GetNextIndex(itemSlot);
int lastItemSlot = nextRowGroupHeaderSlot == -1 ? endItemSlot : Math.Min(endItemSlot, nextRowGroupHeaderSlot - 1);
for (int slot = itemSlot; slot <= lastItemSlot; slot++)
{
if (_selectedSlotsTable.Contains(slot))
{
_selectedItemsCache.Remove(this.OwningGrid.DataConnection.GetDataItem(this.OwningGrid.RowIndexFromSlot(slot)));
}
}
_selectedSlotsTable.RemoveValues(itemSlot, lastItemSlot - itemSlot + 1);
itemSlot = this.OwningGrid.RowGroupHeadersTable.GetNextGap(lastItemSlot);
}
}
}
internal void UpdateIndexes()
{
_oldSelectedSlotsTable.Clear();
_selectedSlotsTable.Clear();
if (this.OwningGrid.DataConnection.DataSource == null)
{
if (this.SelectedItemsCache.Count > 0)
{
this.OwningGrid.SelectionHasChanged = true;
this.SelectedItemsCache.Clear();
}
}
else
{
List<object> tempSelectedItemsCache = new List<object>();
foreach (object item in _selectedItemsCache)
{
int index = this.OwningGrid.DataConnection.IndexOf(item);
if (index != -1)
{
tempSelectedItemsCache.Add(item);
_selectedSlotsTable.AddValue(this.OwningGrid.SlotFromRowIndex(index), true);
}
}
foreach (object item in _oldSelectedItemsCache)
{
int index = this.OwningGrid.DataConnection.IndexOf(item);
if (index == -1)
{
this.OwningGrid.SelectionHasChanged = true;
}
else
{
_oldSelectedSlotsTable.AddValue(this.OwningGrid.SlotFromRowIndex(index), true);
}
}
_selectedItemsCache = tempSelectedItemsCache;
}
}
}
}

Просмотреть файл

@ -0,0 +1,161 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Represents a <see cref="DataGrid"/> column that hosts template-specified
/// content in its cells.
/// </summary>
public class DataGridTemplateColumn : DataGridColumn
{
private DataTemplate _cellTemplate;
private DataTemplate _cellEditingTemplate;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridTemplateColumn"/> class.
/// </summary>
public DataGridTemplateColumn()
{
}
/// <summary>
/// Gets or sets the template that is used to display the contents of a cell that is in editing mode.
/// </summary>
public DataTemplate CellEditingTemplate
{
get
{
return _cellEditingTemplate;
}
set
{
if (_cellEditingTemplate != value)
{
this.RemoveEditingElement();
_cellEditingTemplate = value;
}
}
}
/// <summary>
/// Gets or sets the template that is used to display the contents of a cell that is not in editing mode.
/// </summary>
public DataTemplate CellTemplate
{
get
{
return _cellTemplate;
}
set
{
if (_cellTemplate != value)
{
if (_cellEditingTemplate == null)
{
this.RemoveEditingElement();
}
_cellTemplate = value;
}
}
}
internal bool HasDistinctTemplates
{
get
{
return this.CellTemplate != this.CellEditingTemplate;
}
}
/// <summary>
/// CancelCellEdit
/// </summary>
/// <param name="editingElement">The element that the column displays for a cell in editing mode.</param>
/// <param name="uneditedValue">The previous, unedited value in the cell being edited.</param>
protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
{
_ = GenerateEditingElement(null, null);
}
/// <summary>
/// Gets an element defined by the <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridTemplateColumn.CellEditingTemplate"/> that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </summary>
/// <returns>A new editing element that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.</returns>
/// <param name="cell">The cell that will contain the generated element.</param>
/// <param name="dataItem">The data item represented by the row that contains the intended cell.</param>
/// <exception cref="T:System.TypeInitializationException">
/// The <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridTemplateColumn.CellEditingTemplate"/> is null.
/// </exception>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
if (this.CellEditingTemplate != null)
{
return this.CellEditingTemplate.LoadContent() as FrameworkElement;
}
if (this.CellTemplate != null)
{
return this.CellTemplate.LoadContent() as FrameworkElement;
}
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
return null;
}
else
{
throw DataGridError.DataGridTemplateColumn.MissingTemplateForType(typeof(DataGridTemplateColumn));
}
}
/// <summary>
/// Gets an element defined by the <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridTemplateColumn.CellTemplate"/> that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </summary>
/// <returns>A new, read-only element that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.</returns>
/// <param name="cell">The cell that will contain the generated element.</param>
/// <param name="dataItem">The data item represented by the row that contains the intended cell.</param>
/// <exception cref="T:System.TypeInitializationException">
/// The <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridTemplateColumn.CellTemplate"/> is null.
/// </exception>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
if (this.CellTemplate != null)
{
return this.CellTemplate.LoadContent() as FrameworkElement;
}
if (this.CellEditingTemplate != null)
{
return this.CellEditingTemplate.LoadContent() as FrameworkElement;
}
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
return null;
}
else
{
throw DataGridError.DataGridTemplateColumn.MissingTemplateForType(typeof(DataGridTemplateColumn));
}
}
/// <summary>
/// Called when a cell in the column enters editing mode.
/// </summary>
/// <param name="editingElement">The element that the column displays for a cell in editing mode.</param>
/// <param name="editingEventArgs">Information about the user gesture that is causing a cell to enter editing mode.</param>
/// <returns>null in all cases.</returns>
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,433 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.ComponentModel;
using Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals;
using Windows.UI;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Represents a <see cref="DataGrid"/> column that hosts textual content in its cells.
/// </summary>
[StyleTypedProperty(Property = "ElementStyle", StyleTargetType = typeof(TextBlock))]
[StyleTypedProperty(Property = "EditingElementStyle", StyleTargetType = typeof(TextBox))]
public class DataGridTextColumn : DataGridBoundColumn
{
private const string DATAGRIDTEXTCOLUMN_fontFamilyName = "FontFamily";
private const string DATAGRIDTEXTCOLUMN_fontSizeName = "FontSize";
private const string DATAGRIDTEXTCOLUMN_fontStyleName = "FontStyle";
private const string DATAGRIDTEXTCOLUMN_fontWeightName = "FontWeight";
private const string DATAGRIDTEXTCOLUMN_foregroundName = "Foreground";
private const double DATAGRIDTEXTCOLUMN_leftMargin = 12.0;
private const double DATAGRIDTEXTCOLUMN_rightMargin = 12.0;
private double? _fontSize;
private FontStyle? _fontStyle;
private FontWeight? _fontWeight;
private Brush _foreground;
/// <summary>
/// Initializes a new instance of the <see cref="DataGridTextColumn"/> class.
/// </summary>
public DataGridTextColumn()
{
this.BindingTarget = TextBox.TextProperty;
}
/// <summary>
/// Gets or sets the font name.
/// </summary>
public FontFamily FontFamily
{
get { return (FontFamily)GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
}
/// <summary>
/// Identifies the FontFamily dependency property.
/// </summary>
public static readonly DependencyProperty FontFamilyProperty =
DependencyProperty.Register(
DATAGRIDTEXTCOLUMN_fontFamilyName,
typeof(FontFamily),
typeof(DataGridTextColumn),
new PropertyMetadata(null, OnFontFamilyPropertyChanged));
private static void OnFontFamilyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridTextColumn textColumn = d as DataGridTextColumn;
textColumn.NotifyPropertyChanged(DATAGRIDTEXTCOLUMN_fontFamilyName);
}
/// <summary>
/// Gets or sets the font size.
/// </summary>
// Use DefaultValue here so undo in the Designer will set this to NaN
[DefaultValue(double.NaN)]
public double FontSize
{
get
{
return _fontSize ?? double.NaN;
}
set
{
if (_fontSize != value)
{
_fontSize = value;
NotifyPropertyChanged(DATAGRIDTEXTCOLUMN_fontSizeName);
}
}
}
/// <summary>
/// Gets or sets the font style.
/// </summary>
public FontStyle FontStyle
{
get
{
return _fontStyle ?? FontStyle.Normal;
}
set
{
if (_fontStyle != value)
{
_fontStyle = value;
NotifyPropertyChanged(DATAGRIDTEXTCOLUMN_fontStyleName);
}
}
}
/// <summary>
/// Gets or sets the font weight or thickness.
/// </summary>
public FontWeight FontWeight
{
get
{
return _fontWeight ?? FontWeights.Normal;
}
set
{
if (!_fontWeight.HasValue || _fontWeight.Value.Weight != value.Weight)
{
_fontWeight = value;
NotifyPropertyChanged(DATAGRIDTEXTCOLUMN_fontWeightName);
}
}
}
/// <summary>
/// Gets or sets a brush that describes the foreground of the column cells.
/// </summary>
public Brush Foreground
{
get
{
return _foreground;
}
set
{
if (_foreground != value)
{
_foreground = value;
NotifyPropertyChanged(DATAGRIDTEXTCOLUMN_foregroundName);
}
}
}
/// <summary>
/// Causes the column cell being edited to revert to the specified value.
/// </summary>
/// <param name="editingElement">The element that the column displays for a cell in editing mode.</param>
/// <param name="uneditedValue">The previous, unedited value in the cell being edited.</param>
protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
{
TextBox textBox = editingElement as TextBox;
if (textBox != null)
{
string uneditedString = uneditedValue as string;
textBox.Text = uneditedString ?? string.Empty;
}
}
/// <summary>
/// Gets a <see cref="T:System.Windows.Controls.TextBox"/> control that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </summary>
/// <param name="cell">The cell that will contain the generated element.</param>
/// <param name="dataItem">The data item represented by the row that contains the intended cell.</param>
/// <returns>A new <see cref="T:System.Windows.Controls.TextBox"/> control that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.</returns>
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
TextBox textBox = new TextBox();
textBox.VerticalAlignment = VerticalAlignment.Stretch;
textBox.Background = new SolidColorBrush(Colors.Transparent);
if (DependencyProperty.UnsetValue != ReadLocalValue(DataGridTextColumn.FontFamilyProperty))
{
textBox.FontFamily = this.FontFamily;
}
if (_fontSize.HasValue)
{
textBox.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBox.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBox.FontWeight = _fontWeight.Value;
}
RefreshForeground(textBox, (cell != null & cell.OwningRow != null) ? cell.OwningRow.ComputedForeground : null);
if (this.Binding != null)
{
textBox.SetBinding(this.BindingTarget, this.Binding);
}
return textBox;
}
/// <summary>
/// Gets a read-only <see cref="T:System.Windows.Controls.TextBlock"/> element that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.
/// </summary>
/// <param name="cell">The cell that will contain the generated element.</param>
/// <param name="dataItem">The data item represented by the row that contains the intended cell.</param>
/// <returns>A new, read-only <see cref="T:System.Windows.Controls.TextBlock"/> element that is bound to the column's <see cref="P:Microsoft.Toolkit.Uwp.UI.Controls.DataGridBoundColumn.Binding"/> property value.</returns>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
TextBlock textBlockElement = new TextBlock();
textBlockElement.Margin = new Thickness(DATAGRIDTEXTCOLUMN_leftMargin, 0.0, DATAGRIDTEXTCOLUMN_rightMargin, 0.0);
textBlockElement.VerticalAlignment = VerticalAlignment.Center;
if (DependencyProperty.UnsetValue != ReadLocalValue(DataGridTextColumn.FontFamilyProperty))
{
textBlockElement.FontFamily = this.FontFamily;
}
if (_fontSize.HasValue)
{
textBlockElement.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBlockElement.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBlockElement.FontWeight = _fontWeight.Value;
}
RefreshForeground(textBlockElement, (cell != null & cell.OwningRow != null) ? cell.OwningRow.ComputedForeground : null);
if (this.Binding != null)
{
textBlockElement.SetBinding(TextBlock.TextProperty, this.Binding);
}
return textBlockElement;
}
/// <summary>
/// Called when the cell in the column enters editing mode.
/// </summary>
/// <param name="editingElement">The element that the column displays for a cell in editing mode.</param>
/// <param name="editingEventArgs">Information about the user gesture that is causing a cell to enter editing mode.</param>
/// <returns>The unedited value. </returns>
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
TextBox textBox = editingElement as TextBox;
if (textBox != null)
{
string uneditedText = textBox.Text;
int len = uneditedText.Length;
KeyRoutedEventArgs keyEventArgs = editingEventArgs as KeyRoutedEventArgs;
if (keyEventArgs != null && keyEventArgs.Key == Windows.System.VirtualKey.F2)
{
// Put caret at the end of the text
textBox.Select(len, len);
}
else
{
// Select all text
textBox.Select(0, len);
}
return uneditedText;
}
return string.Empty;
}
/// <summary>
/// Called by the DataGrid control when this column asks for its elements to be updated, because a property changed.
/// </summary>
protected internal override void RefreshCellContent(FrameworkElement element, Brush computedRowForeground, string propertyName)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
TextBox textBox = element as TextBox;
if (textBox == null)
{
TextBlock textBlock = element as TextBlock;
if (textBlock == null)
{
throw DataGridError.DataGrid.ValueIsNotAnInstanceOfEitherOr("element", typeof(TextBox), typeof(TextBlock));
}
if (propertyName == DATAGRIDTEXTCOLUMN_fontFamilyName)
{
textBlock.FontFamily = this.FontFamily;
}
else if (propertyName == DATAGRIDTEXTCOLUMN_fontSizeName)
{
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
}
else if (propertyName == DATAGRIDTEXTCOLUMN_fontStyleName)
{
textBlock.FontStyle = this.FontStyle;
}
else if (propertyName == DATAGRIDTEXTCOLUMN_fontWeightName)
{
textBlock.FontWeight = this.FontWeight;
}
else if (propertyName == DATAGRIDTEXTCOLUMN_foregroundName)
{
RefreshForeground(textBlock, computedRowForeground);
}
else
{
if (this.FontFamily != null)
{
textBlock.FontFamily = this.FontFamily;
}
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
textBlock.FontStyle = this.FontStyle;
textBlock.FontWeight = this.FontWeight;
RefreshForeground(textBlock, computedRowForeground);
}
return;
}
if (propertyName == DATAGRIDTEXTCOLUMN_fontFamilyName)
{
textBox.FontFamily = this.FontFamily;
}
else if (propertyName == DATAGRIDTEXTCOLUMN_fontSizeName)
{
SetTextFontSize(textBox, TextBox.FontSizeProperty);
}
else if (propertyName == DATAGRIDTEXTCOLUMN_fontStyleName)
{
textBox.FontStyle = this.FontStyle;
}
else if (propertyName == DATAGRIDTEXTCOLUMN_fontWeightName)
{
textBox.FontWeight = this.FontWeight;
}
else if (propertyName == DATAGRIDTEXTCOLUMN_foregroundName)
{
RefreshForeground(textBox, computedRowForeground);
}
else
{
if (this.FontFamily != null)
{
textBox.FontFamily = this.FontFamily;
}
SetTextFontSize(textBox, TextBox.FontSizeProperty);
textBox.FontStyle = this.FontStyle;
textBox.FontWeight = this.FontWeight;
RefreshForeground(textBox, computedRowForeground);
}
}
/// <summary>
/// Called when the computed foreground of a row changed.
/// </summary>
protected internal override void RefreshForeground(FrameworkElement element, Brush computedRowForeground)
{
TextBox textBox = element as TextBox;
if (textBox != null)
{
RefreshForeground(textBox, computedRowForeground);
}
else
{
TextBlock textBlock = element as TextBlock;
if (textBlock != null)
{
RefreshForeground(textBlock, computedRowForeground);
}
}
}
private void RefreshForeground(TextBlock textBlock, Brush computedRowForeground)
{
if (this.Foreground == null)
{
if (computedRowForeground != null)
{
textBlock.Foreground = computedRowForeground;
}
}
else
{
textBlock.Foreground = this.Foreground;
}
}
private void RefreshForeground(TextBox textBox, Brush computedRowForeground)
{
if (this.Foreground == null)
{
if (computedRowForeground != null)
{
textBox.Foreground = computedRowForeground;
}
}
else
{
textBox.Foreground = this.Foreground;
}
}
private void SetTextFontSize(DependencyObject textElement, DependencyProperty fontSizeProperty)
{
double newFontSize = this.FontSize;
if (double.IsNaN(newFontSize))
{
textElement.ClearValue(fontSizeProperty);
}
else
{
textElement.SetValue(fontSizeProperty, newFontSize);
}
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Controls.DataGridInternals
{
internal class DataGridValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (targetType != null && TypeHelper.IsNullableType(targetType))
{
string strValue = value as string;
if (strValue == string.Empty)
{
return null;
}
}
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFramework>uap10.0.17763</TargetFramework>
<Title>Windows Community Toolkit Controls DataGrid</Title>
<Description>
This library provides a XAML DataGrid control. It is part of the Windows Community Toolkit.
</Description>
<PackageTags>UWP Toolkit Windows Controls XAML DataGrid</PackageTags>
<RootNamespace>Microsoft.Toolkit.Uwp.UI.Controls</RootNamespace>
<LangVersion>preview</LangVersion> <!-- Fix a small internal bug -->
</PropertyGroup>
<ItemGroup>
<None Include="VisualStudioToolsManifest.xml" Pack="true" PackagePath="tools" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=datagrid/@EntryIndexedValue">True</s:Boolean>
</wpf:ResourceDictionary>

Просмотреть файл

@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Resources;
using System.Runtime.CompilerServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
// TODO: Fix tests for WinUI3
// [assembly: InternalsVisibleTo("UnitTests.UWP")]
[assembly: NeutralResourcesLanguage("en-US")]

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
<Library Name="Microsoft.Toolkit.Uwp.UI.Controls.DataGrid">
</Library>
</Directives>

Просмотреть файл

@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Microsoft.Toolkit.Uwp.UI.Controls.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Toolkit.Uwp.UI.Controls.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to row.
/// </summary>
internal static string DataGridRowAutomationPeer_ItemType {
get {
return ResourceManager.GetString("DataGridRowAutomationPeer_ItemType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ({0} items).
/// </summary>
internal static string DataGridRowGroupHeader_ItemCountPlural {
get {
return ResourceManager.GetString("DataGridRowGroupHeader_ItemCountPlural", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ({0} item).
/// </summary>
internal static string DataGridRowGroupHeader_ItemCountSingular {
get {
return ResourceManager.GetString("DataGridRowGroupHeader_ItemCountSingular", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to {0}:.
/// </summary>
internal static string DataGridRowGroupHeader_PropertyName {
get {
return ResourceManager.GetString("DataGridRowGroupHeader_PropertyName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Group.
/// </summary>
internal static string DefaultRowGroupHeaderPropertyNameAlternative {
get {
return ResourceManager.GetString("DefaultRowGroupHeaderPropertyNameAlternative", resourceCulture);
}
}
}
}

Просмотреть файл

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DataGridRowAutomationPeer_ItemType" xml:space="preserve">
<value>row</value>
</data>
<data name="DataGridRowGroupHeader_ItemCountPlural" xml:space="preserve">
<value>({0} items)</value>
</data>
<data name="DataGridRowGroupHeader_ItemCountSingular" xml:space="preserve">
<value>({0} item)</value>
</data>
<data name="DataGridRowGroupHeader_PropertyName" xml:space="preserve">
<value>{0}:</value>
</data>
<data name="DefaultRowGroupHeaderPropertyNameAlternative" xml:space="preserve">
<value>Group</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,18 @@
<!--
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
-->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/DataGrid/DataGrid.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

Просмотреть файл

@ -0,0 +1,51 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.UI.Data.Utilities
{
/// <summary>
/// Stores information about a Binding, including the BindingExpression, BindingTarget and associated Element.
/// </summary>
internal class BindingInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="BindingInfo"/> class.
/// </summary>
public BindingInfo()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BindingInfo"/> class
/// with the specified BindingExpression, DependencyProperty and FrameworkElement.
/// </summary>
/// <param name="bindingExpression">BindingExpression</param>
/// <param name="bindingTarget">BindingTarget</param>
/// <param name="element">Element</param>
public BindingInfo(BindingExpression bindingExpression, DependencyProperty bindingTarget, FrameworkElement element)
{
this.BindingExpression = bindingExpression;
this.BindingTarget = bindingTarget;
this.Element = element;
}
/// <summary>
/// Gets or sets the BindingExpression.
/// </summary>
public BindingExpression BindingExpression { get; set; }
/// <summary>
/// Gets or sets the BindingTarget.
/// </summary>
public DependencyProperty BindingTarget { get; set; }
/// <summary>
/// Gets or sets the Element.
/// </summary>
public FrameworkElement Element { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,135 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.Utilities
{
internal static class DoubleUtil
{
internal const double DBL_EPSILON = 1.1102230246251567e-016;
/// <summary>
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other. Note that this epsilon is proportional
/// to the numbers themselves to that AreClose survives scalar multiplication.
/// There are plenty of ways for this to return false even for numbers which
/// are theoretically identical, so no code calling this should fail to work if this
/// returns false. This is important enough to repeat:
/// NB: NO CODE CALLING THIS FUNCTION SHOULD DEPEND ON ACCURATE RESULTS - this should be
/// used for optimizations *only*.
/// </summary>
/// <returns>
/// bool - the result of the AreClose comparison.
/// </returns>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
public static bool AreClose(double value1, double value2)
{
// in case they are Infinities (then epsilon check does not work)
if (value1 == value2)
{
return true;
}
// This computes (|value1-value2| / (|value1| + |value2| + 10.0)) < DBL_EPSILON
double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * DBL_EPSILON;
double delta = value1 - value2;
return -eps < delta && eps > delta;
}
/// <summary>
/// GreaterThan - Returns whether or not the first double is greater than the second double.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
/// the other number. Note that this epsilon is proportional to the numbers themselves
/// to that AreClose survives scalar multiplication.
/// There are plenty of ways for this to return false even for numbers which
/// are theoretically identical, so no code calling this should fail to work if this
/// returns false. This is important enough to repeat:
/// NB: This method should be used for optimizations only.
/// </summary>
/// <returns>
/// bool - the result of the GreaterThan comparison.
/// </returns>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
public static bool GreaterThan(double value1, double value2)
{
return value1 > value2 && !AreClose(value1, value2);
}
/// <summary>
/// GreaterThanOrClose - Returns whether or not the first double is greater than or close to
/// the second double. That is, whether or not the first is strictly greater than or within
/// epsilon of the other number. Note that this epsilon is proportional to the numbers
/// themselves to that AreClose survives scalar multiplication.
/// There are plenty of ways for this to return false even for numbers which
/// are theoretically identical, so no code calling this should fail to work if this
/// returns false. This is important enough to repeat:
/// NB: This method should be used for optimizations only.
/// </summary>
/// <returns>
/// bool - the result of the GreaterThanOrClose comparison.
/// </returns>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
public static bool GreaterThanOrClose(double value1, double value2)
{
return value1 > value2 || AreClose(value1, value2);
}
/// <summary>
/// IsZero - Returns whether or not the double is "close" to 0. Same as AreClose(double, 0),
/// but this is faster.
/// </summary>
/// <returns>
/// bool - the result of the IsZero comparison.
/// </returns>
/// <param name="value">The double to compare to 0.</param>
public static bool IsZero(double value)
{
return Math.Abs(value) < 10.0 * DBL_EPSILON;
}
/// <summary>
/// LessThan - Returns whether or not the first double is less than the second double.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
/// the other number. Note that this epsilon is proportional to the numbers themselves
/// to that AreClose survives scalar multiplication.
/// There are plenty of ways for this to return false even for numbers which
/// are theoretically identical, so no code calling this should fail to work if this
/// returns false. This is important enough to repeat:
/// NB: This method should be used for optimizations only.
/// </summary>
/// <returns>
/// bool - the result of the LessThan comparison.
/// </returns>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
public static bool LessThan(double value1, double value2)
{
return value1 < value2 && !AreClose(value1, value2);
}
/// <summary>
/// LessThanOrClose - Returns whether or not the first double is less than or close to
/// the second double. That is, whether or not the first is strictly less than or within
/// epsilon of the other number. Note that this epsilon is proportional to the numbers
/// themselves to that AreClose survives scalar multiplication.
/// There are plenty of ways for this to return false even for numbers which
/// are theoretically identical, so no code calling this should fail to work if this
/// returns false. This is important enough to repeat:
/// NB: This method should be used for optimizations only.
/// </summary>
/// <returns>
/// bool - the result of the LessThanOrClose comparison.
/// </returns>
/// <param name="value1">The first double to compare.</param>
/// <param name="value2">The second double to compare.</param>
public static bool LessThanOrClose(double value1, double value2)
{
return value1 < value2 || AreClose(value1, value2);
}
}
}

Просмотреть файл

@ -0,0 +1,255 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Microsoft.Toolkit.Uwp.Utilities;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace Microsoft.Toolkit.Uwp.UI.Utilities
{
internal static class Extensions
{
private static Dictionary<DependencyObject, Dictionary<DependencyProperty, int>> _suspendedHandlers = new Dictionary<DependencyObject, Dictionary<DependencyProperty, int>>();
public static bool IsHandlerSuspended(this DependencyObject dependencyObject, DependencyProperty dependencyProperty)
{
return _suspendedHandlers.ContainsKey(dependencyObject) ? _suspendedHandlers[dependencyObject].ContainsKey(dependencyProperty) : false;
}
/// <summary>
/// Walks the visual tree to determine if a particular child is contained within a parent DependencyObject.
/// </summary>
/// <param name="element">Parent DependencyObject</param>
/// <param name="child">Child DependencyObject</param>
/// <returns>True if the parent element contains the child</returns>
internal static bool ContainsChild(this DependencyObject element, DependencyObject child)
{
if (element != null)
{
while (child != null)
{
if (child == element)
{
return true;
}
// Walk up the visual tree. If the root is hit, try using the framework element's
// parent. This is done because Popups behave differently with respect to the visual tree,
// and it could have a parent even if the VisualTreeHelper doesn't find it.
DependencyObject parent = VisualTreeHelper.GetParent(child);
if (parent == null)
{
FrameworkElement childElement = child as FrameworkElement;
if (childElement != null)
{
parent = childElement.Parent;
}
}
child = parent;
}
}
return false;
}
/// <summary>
/// Walks the visual tree to determine if the currently focused element is contained within
/// a parent DependencyObject. The FocusManager's GetFocusedElement method is used to determine
/// the currently focused element, which is updated synchronously.
/// </summary>
/// <param name="element">Parent DependencyObject</param>
/// <param name="uiElement">Parent UIElement. Used to query the element's XamlRoot.</param>
/// <returns>True if the currently focused element is within the visual tree of the parent</returns>
internal static bool ContainsFocusedElement(this DependencyObject element, UIElement uiElement)
{
return (element == null) ? false : element.ContainsChild(GetFocusedElement(uiElement) as DependencyObject);
}
private static object GetFocusedElement(UIElement uiElement)
{
if (TypeHelper.IsXamlRootAvailable && uiElement.XamlRoot != null)
{
return FocusManager.GetFocusedElement(uiElement.XamlRoot);
}
else
{
return FocusManager.GetFocusedElement();
}
}
/// <summary>
/// Checks a MemberInfo object (e.g. a Type or PropertyInfo) for the ReadOnly attribute
/// and returns the value of IsReadOnly if it exists.
/// </summary>
/// <param name="memberInfo">MemberInfo to check</param>
/// <returns>true if MemberInfo is read-only, false otherwise</returns>
internal static bool GetIsReadOnly(this MemberInfo memberInfo)
{
if (memberInfo != null)
{
// Check if ReadOnlyAttribute is defined on the member
object[] attributes = memberInfo.GetCustomAttributes(typeof(ReadOnlyAttribute), true);
if (attributes != null && attributes.Length > 0)
{
ReadOnlyAttribute readOnlyAttribute = attributes[0] as ReadOnlyAttribute;
Debug.Assert(readOnlyAttribute != null, "Expected non-null readOnlyAttribute.");
return readOnlyAttribute.IsReadOnly;
}
}
return false;
}
internal static Type GetItemType(this IEnumerable list)
{
Type listType = list.GetType();
Type itemType = null;
bool isICustomTypeProvider = false;
// If it's a generic enumerable, get the generic type.
// Unfortunately, if data source is fed from a bare IEnumerable, TypeHelper will report an element type of object,
// which is not particularly interesting. It is dealt with it further on.
if (listType.IsEnumerableType())
{
itemType = listType.GetEnumerableItemType();
if (itemType != null)
{
isICustomTypeProvider = typeof(ICustomTypeProvider).IsAssignableFrom(itemType);
}
}
// Bare IEnumerables mean that result type will be object. In that case, try to get something more interesting.
// Or, if the itemType implements ICustomTypeProvider, try to retrieve the custom type from one of the object instances.
if (itemType == null || itemType == typeof(object) || isICustomTypeProvider)
{
// No type was located yet. Does the list have anything in it?
Type firstItemType = null;
IEnumerator en = list.GetEnumerator();
if (en.MoveNext() && en.Current != null)
{
firstItemType = en.Current.GetCustomOrCLRType();
}
else
{
firstItemType = list
.Cast<object>() // cast to convert IEnumerable to IEnumerable<object>
.Select(x => x.GetType()) // get the type
.FirstOrDefault(); // get only the first thing to come out of the sequence, or null if empty
}
if (firstItemType != typeof(object))
{
return firstItemType;
}
}
// Couldn't get the CustomType because there were no items.
if (isICustomTypeProvider)
{
return null;
}
return itemType;
}
public static void SetStyleWithType(this FrameworkElement element, Style style)
{
if (element.Style != style && (style == null || style.TargetType != null))
{
element.Style = style;
}
}
public static void SetValueNoCallback(this DependencyObject obj, DependencyProperty property, object value)
{
obj.SuspendHandler(property, true);
try
{
obj.SetValue(property, value);
}
finally
{
obj.SuspendHandler(property, false);
}
}
internal static Point Translate(this UIElement fromElement, UIElement toElement, Point fromPoint)
{
if (fromElement == toElement)
{
return fromPoint;
}
else
{
return fromElement.TransformToVisual(toElement).TransformPoint(fromPoint);
}
}
// If the parent element goes into a background tab, the elements need to be remeasured
// or they will report 0 height.
internal static UIElement EnsureMeasured(this UIElement element)
{
if (element.DesiredSize.Height == 0)
{
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
}
return element;
}
private static void SuspendHandler(this DependencyObject obj, DependencyProperty dependencyProperty, bool incrementSuspensionCount)
{
if (_suspendedHandlers.ContainsKey(obj))
{
Dictionary<DependencyProperty, int> suspensions = _suspendedHandlers[obj];
if (incrementSuspensionCount)
{
if (suspensions.ContainsKey(dependencyProperty))
{
suspensions[dependencyProperty]++;
}
else
{
suspensions[dependencyProperty] = 1;
}
}
else
{
Debug.Assert(suspensions.ContainsKey(dependencyProperty), "Expected existing key for dependencyProperty.");
if (suspensions[dependencyProperty] == 1)
{
suspensions.Remove(dependencyProperty);
}
else
{
suspensions[dependencyProperty]--;
}
if (suspensions.Count == 0)
{
_suspendedHandlers.Remove(obj);
}
}
}
else
{
Debug.Assert(incrementSuspensionCount, "Expected incrementSuspensionCount==true.");
_suspendedHandlers[obj] = new Dictionary<DependencyProperty, int>();
_suspendedHandlers[obj][dependencyProperty] = 1;
}
}
}
}

Просмотреть файл

@ -0,0 +1,907 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Microsoft.Toolkit.Uwp.Utilities
{
internal class IndexToValueTable<T> : IEnumerable<Range<T>>
{
private List<Range<T>> _list;
public IndexToValueTable()
{
_list = new List<Range<T>>();
}
// Begin Public Properties
/// <summary>
/// Gets the total number of indices represented in the table
/// </summary>
public int IndexCount
{
get
{
int indexCount = 0;
foreach (Range<T> range in _list)
{
indexCount += range.Count;
}
return indexCount;
}
}
/// <summary>
/// Gets a value indicating whether the table is empty
/// </summary>
public bool IsEmpty
{
get
{
return _list.Count == 0;
}
}
/// <summary>
/// Gets the number of index ranges in the table
/// </summary>
public int RangeCount
{
get
{
return _list.Count;
}
}
// End Public Properties
// Begin Public methods
/// <summary>
/// Add a value with an associated index to the table
/// </summary>
/// <param name="index">Index where the value is to be added or updated</param>
/// <param name="value">Value to add</param>
public void AddValue(int index, T value)
{
AddValues(index, 1, value);
}
/// <summary>
/// Add multiples values with an associated start index to the table
/// </summary>
/// <param name="startIndex">index where first value is added</param>
/// <param name="count">Total number of values to add (must be greater than 0)</param>
/// <param name="value">Value to add</param>
public void AddValues(int startIndex, int count, T value)
{
Debug.Assert(count > 0, "Expected a strictly positive count parameter.");
AddValuesPrivate(startIndex, count, value, null);
}
/// <summary>
/// Clears the index table
/// </summary>
public void Clear()
{
_list.Clear();
}
/// <summary>
/// Returns true if the given index is contained in the table
/// </summary>
/// <param name="index">index to search for</param>
/// <returns>True if the index is contained in the table</returns>
public bool Contains(int index)
{
return IsCorrectRangeIndex(this.FindRangeIndex(index), index);
}
/// <summary>
/// Returns true if the entire given index range is contained in the table
/// </summary>
/// <param name="startIndex">beginning of the range</param>
/// <param name="endIndex">end of the range</param>
/// <returns>True if the entire index range is present in the table</returns>
public bool ContainsAll(int startIndex, int endIndex)
{
int start = -1;
int end = -1;
foreach (Range<T> range in _list)
{
if (start == -1 && range.UpperBound >= startIndex)
{
if (startIndex < range.LowerBound)
{
return false;
}
start = startIndex;
end = range.UpperBound;
if (end >= endIndex)
{
return true;
}
}
else if (start != -1)
{
if (range.LowerBound > end + 1)
{
return false;
}
end = range.UpperBound;
if (end >= endIndex)
{
return true;
}
}
}
return false;
}
/// <summary>
/// Returns true if the given index is contained in the table with the the given value
/// </summary>
/// <param name="index">index to search for</param>
/// <param name="value">value expected</param>
/// <returns>true if the given index is contained in the table with the given value</returns>
public bool ContainsIndexAndValue(int index, T value)
{
int lowerRangeIndex = this.FindRangeIndex(index);
return IsCorrectRangeIndex(lowerRangeIndex, index) && _list[lowerRangeIndex].ContainsValue(value);
}
/// <summary>
/// Returns a copy of this IndexToValueTable
/// </summary>
/// <returns>copy of this IndexToValueTable</returns>
public IndexToValueTable<T> Copy()
{
IndexToValueTable<T> copy = new IndexToValueTable<T>();
foreach (Range<T> range in _list)
{
copy._list.Add(range.Copy());
}
return copy;
}
public int GetNextGap(int index)
{
int targetIndex = index + 1;
int rangeIndex = FindRangeIndex(targetIndex);
if (IsCorrectRangeIndex(rangeIndex, targetIndex))
{
while (rangeIndex < _list.Count - 1 && _list[rangeIndex].UpperBound == _list[rangeIndex + 1].LowerBound - 1)
{
rangeIndex++;
}
return _list[rangeIndex].UpperBound + 1;
}
else
{
return targetIndex;
}
}
public int GetNextIndex(int index)
{
int targetIndex = index + 1;
int rangeIndex = FindRangeIndex(targetIndex);
if (IsCorrectRangeIndex(rangeIndex, targetIndex))
{
return targetIndex;
}
else
{
rangeIndex++;
return rangeIndex < _list.Count ? _list[rangeIndex].LowerBound : -1;
}
}
public int GetPreviousGap(int index)
{
int targetIndex = index - 1;
int rangeIndex = FindRangeIndex(targetIndex);
if (IsCorrectRangeIndex(rangeIndex, targetIndex))
{
while (rangeIndex > 0 && _list[rangeIndex].LowerBound == _list[rangeIndex - 1].UpperBound + 1)
{
rangeIndex--;
}
return _list[rangeIndex].LowerBound - 1;
}
else
{
return targetIndex;
}
}
public int GetPreviousIndex(int index)
{
int targetIndex = index - 1;
int rangeIndex = FindRangeIndex(targetIndex);
if (IsCorrectRangeIndex(rangeIndex, targetIndex))
{
return targetIndex;
}
else
{
return rangeIndex >= 0 && rangeIndex < _list.Count ? _list[rangeIndex].UpperBound : -1;
}
}
/// <summary>
/// Returns the inclusive index count between lowerBound and upperBound of all indexes with the given value
/// </summary>
/// <param name="lowerBound">lowerBound criteria</param>
/// <param name="upperBound">upperBound criteria</param>
/// <param name="value">value to look for</param>
/// <returns>Number of indexes contained in the table between lowerBound and upperBound (inclusive)</returns>
public int GetIndexCount(int lowerBound, int upperBound, T value)
{
Debug.Assert(upperBound >= lowerBound, "Expected upperBound greater or equal to lowerBound.");
if (_list.Count == 0)
{
return 0;
}
int count = 0;
int index = FindRangeIndex(lowerBound);
if (IsCorrectRangeIndex(index, lowerBound) && _list[index].ContainsValue(value))
{
count += _list[index].UpperBound - lowerBound + 1;
}
index++;
while (index < _list.Count && _list[index].UpperBound <= upperBound)
{
if (_list[index].ContainsValue(value))
{
count += _list[index].Count;
}
index++;
}
if (index < _list.Count && IsCorrectRangeIndex(index, upperBound) && _list[index].ContainsValue(value))
{
count += upperBound - _list[index].LowerBound;
}
return count;
}
/// <summary>
/// Returns the inclusive index count between lowerBound and upperBound
/// </summary>
/// <param name="lowerBound">lowerBound criteria</param>
/// <param name="upperBound">upperBound criteria</param>
/// <returns>Number of indexes contained in the table between lowerBound and upperBound (inclusive)</returns>
public int GetIndexCount(int lowerBound, int upperBound)
{
if (upperBound < lowerBound || _list.Count == 0)
{
return 0;
}
int count = 0;
int index = this.FindRangeIndex(lowerBound);
if (IsCorrectRangeIndex(index, lowerBound))
{
count += _list[index].UpperBound - lowerBound + 1;
}
index++;
while (index < _list.Count && _list[index].UpperBound <= upperBound)
{
count += _list[index].Count;
index++;
}
if (index < _list.Count && IsCorrectRangeIndex(index, upperBound))
{
count += upperBound - _list[index].LowerBound;
}
return count;
}
/// <summary>
/// Returns the number of indexes in this table after a given startingIndex but before
/// reaching a gap of indexes of a given size
/// </summary>
/// <param name="startingIndex">Index to start at</param>
/// <param name="gapSize">Size of index gap</param>
/// <returns>the number of indexes in this table after a given startingIndex but before
/// reaching a gap of indexes of a given size</returns>
public int GetIndexCountBeforeGap(int startingIndex, int gapSize)
{
if (_list.Count == 0)
{
return 0;
}
int count = 0;
int currentIndex = startingIndex;
int rangeIndex = 0;
int gap = 0;
while (gap <= gapSize && rangeIndex < _list.Count)
{
gap += _list[rangeIndex].LowerBound - currentIndex;
if (gap <= gapSize)
{
count += _list[rangeIndex].UpperBound - _list[rangeIndex].LowerBound + 1;
currentIndex = _list[rangeIndex].UpperBound + 1;
rangeIndex++;
}
}
return count;
}
/// <summary>
/// Returns an enumerator that goes through the indexes present in the table
/// </summary>
/// <returns>an enumerator that enumerates the indexes present in the table</returns>
public IEnumerable<int> GetIndexes()
{
Debug.Assert(_list != null, "Expected non-null _list.");
foreach (Range<T> range in _list)
{
for (int i = range.LowerBound; i <= range.UpperBound; i++)
{
yield return i;
}
}
}
/// <summary>
/// Returns all the indexes on or after a starting index
/// </summary>
/// <param name="startIndex">start index</param>
/// <returns>all the indexes on or after a starting index</returns>
public IEnumerable<int> GetIndexes(int startIndex)
{
Debug.Assert(_list != null, "Expected non-null _list.");
int rangeIndex = FindRangeIndex(startIndex);
if (rangeIndex == -1)
{
rangeIndex++;
}
while (rangeIndex < _list.Count)
{
for (int i = _list[rangeIndex].LowerBound; i <= _list[rangeIndex].UpperBound; i++)
{
if (i >= startIndex)
{
yield return i;
}
}
rangeIndex++;
}
}
/// <summary>
/// Return the index of the Nth element in the table
/// </summary>
/// <param name="n">n</param>
/// <returns>the index of the Nth element in the table</returns>
public int GetNthIndex(int n)
{
Debug.Assert(n >= 0 && n < this.IndexCount, "Expected n between 0 and IndexCount-1, inclusive.");
int cumulatedEntries = 0;
foreach (Range<T> range in _list)
{
if (cumulatedEntries + range.Count > n)
{
return range.LowerBound + n - cumulatedEntries;
}
else
{
cumulatedEntries += range.Count;
}
}
return -1;
}
/// <summary>
/// Returns the value at a given index or the default value if the index is not in the table
/// </summary>
/// <param name="index">index to search for</param>
/// <returns>the value at the given index or the default value if index is not in the table</returns>
public T GetValueAt(int index) => GetValueAt(index, out _);
/// <summary>
/// Returns the value at a given index or the default value if the index is not in the table
/// </summary>
/// <param name="index">index to search for</param>
/// <param name="found">set to true by the method if the index was found; otherwise, false</param>
/// <returns>the value at the given index or the default value if index is not in the table</returns>
public T GetValueAt(int index, out bool found)
{
int rangeIndex = this.FindRangeIndex(index);
if (this.IsCorrectRangeIndex(rangeIndex, index))
{
found = true;
return _list[rangeIndex].Value;
}
else
{
found = false;
return default(T);
}
}
/// <summary>
/// Returns an index's index within this table
/// </summary>
/// <param name="index">index to search for</param>
/// <returns>an index's index within this table</returns>
public int IndexOf(int index)
{
int cumulatedIndexes = 0;
foreach (Range<T> range in _list)
{
if (range.UpperBound >= index)
{
cumulatedIndexes += index - range.LowerBound;
break;
}
else
{
cumulatedIndexes += range.Count;
}
}
return cumulatedIndexes;
}
/// <summary>
/// Inserts an index at the given location. This does not alter values in the table
/// </summary>
/// <param name="index">index location to insert an index</param>
public void InsertIndex(int index)
{
InsertIndexes(index, 1);
}
/// <summary>
/// Inserts an index into the table with the given value
/// </summary>
/// <param name="index">index to insert</param>
/// <param name="value">value for the index</param>
public void InsertIndexAndValue(int index, T value)
{
InsertIndexesAndValues(index, 1, value);
}
/// <summary>
/// Inserts multiple indexes into the table. This does not alter Values in the table
/// </summary>
/// <param name="startIndex">first index to insert</param>
/// <param name="count">total number of indexes to insert</param>
public void InsertIndexes(int startIndex, int count)
{
Debug.Assert(count > 0, "Expected a strictly positive count parameter.");
InsertIndexesPrivate(startIndex, count, this.FindRangeIndex(startIndex));
}
/// <summary>
/// Inserts multiple indexes into the table with the given value
/// </summary>
/// <param name="startIndex">Index to insert first value</param>
/// <param name="count">Total number of values to insert (must be greater than 0)</param>
/// <param name="value">Value to insert</param>
public void InsertIndexesAndValues(int startIndex, int count, T value)
{
Debug.Assert(count > 0, "Expected a strictly positive count parameter.");
int lowerRangeIndex = this.FindRangeIndex(startIndex);
InsertIndexesPrivate(startIndex, count, lowerRangeIndex);
if ((lowerRangeIndex >= 0) && (_list[lowerRangeIndex].LowerBound > startIndex))
{
// Because of the insert, the original range no longer contains the startIndex
lowerRangeIndex--;
}
AddValuesPrivate(startIndex, count, value, lowerRangeIndex);
}
/// <summary>
/// Removes an index from the table. This does not alter Values in the table
/// </summary>
/// <param name="index">index to remove</param>
public void RemoveIndex(int index)
{
RemoveIndexes(index, 1);
}
/// <summary>
/// Removes a value and its index from the table
/// </summary>
/// <param name="index">index to remove</param>
public void RemoveIndexAndValue(int index)
{
RemoveIndexesAndValues(index, 1);
}
/// <summary>
/// Removes multiple indexes from the table. This does not alter Values in the table
/// </summary>
/// <param name="startIndex">first index to remove</param>
/// <param name="count">total number of indexes to remove</param>
public void RemoveIndexes(int startIndex, int count)
{
int lowerRangeIndex = this.FindRangeIndex(startIndex);
if (lowerRangeIndex < 0)
{
lowerRangeIndex = 0;
}
int i = lowerRangeIndex;
while (i < _list.Count)
{
Range<T> range = _list[i];
if (range.UpperBound >= startIndex)
{
if (range.LowerBound >= startIndex + count)
{
// Both bounds will remain after the removal
range.LowerBound -= count;
range.UpperBound -= count;
}
else
{
int currentIndex = i;
if (range.LowerBound <= startIndex)
{
// Range gets split up
if (range.UpperBound >= startIndex + count)
{
i++;
_list.Insert(i, new Range<T>(startIndex, range.UpperBound - count, range.Value));
}
range.UpperBound = startIndex - 1;
}
else
{
range.LowerBound = startIndex;
range.UpperBound -= count;
}
if (RemoveRangeIfInvalid(range, currentIndex))
{
i--;
}
}
}
i++;
}
if (!this.Merge(lowerRangeIndex))
{
this.Merge(lowerRangeIndex + 1);
}
}
/// <summary>
/// Removes multiple values and their indexes from the table
/// </summary>
/// <param name="startIndex">first index to remove</param>
/// <param name="count">total number of indexes to remove</param>
public void RemoveIndexesAndValues(int startIndex, int count)
{
RemoveValues(startIndex, count);
RemoveIndexes(startIndex, count);
}
/// <summary>
/// Removes a value from the table at the given index. This does not alter other indexes in the table
/// </summary>
/// <param name="index">index where value should be removed</param>
public void RemoveValue(int index)
{
RemoveValues(index, 1);
}
/// <summary>
/// Removes multiple values from the table. This does not alter other indexes in the table
/// </summary>
/// <param name="startIndex">first index where values should be removed </param>
/// <param name="count">total number of values to remove</param>
public void RemoveValues(int startIndex, int count)
{
Debug.Assert(count > 0, "Expected a strictly positive count parameter.");
int lowerRangeIndex = this.FindRangeIndex(startIndex);
if (lowerRangeIndex < 0)
{
lowerRangeIndex = 0;
}
while ((lowerRangeIndex < _list.Count) && (_list[lowerRangeIndex].UpperBound < startIndex))
{
lowerRangeIndex++;
}
if (lowerRangeIndex >= _list.Count || _list[lowerRangeIndex].LowerBound > startIndex + count - 1)
{
// If all the values are above our below our values, we have nothing to remove
return;
}
if (_list[lowerRangeIndex].LowerBound < startIndex)
{
// Need to split this up
_list.Insert(lowerRangeIndex, new Range<T>(_list[lowerRangeIndex].LowerBound, startIndex - 1, _list[lowerRangeIndex].Value));
lowerRangeIndex++;
}
_list[lowerRangeIndex].LowerBound = startIndex + count;
if (!RemoveRangeIfInvalid(_list[lowerRangeIndex], lowerRangeIndex))
{
lowerRangeIndex++;
}
while ((lowerRangeIndex < _list.Count) && (_list[lowerRangeIndex].UpperBound < startIndex + count))
{
_list.RemoveAt(lowerRangeIndex);
}
if ((lowerRangeIndex < _list.Count) && (_list[lowerRangeIndex].UpperBound >= startIndex + count) &&
(_list[lowerRangeIndex].LowerBound < startIndex + count))
{
// Chop off the start of the remaining Range if it contains values that we're removing
_list[lowerRangeIndex].LowerBound = startIndex + count;
RemoveRangeIfInvalid(_list[lowerRangeIndex], lowerRangeIndex);
}
}
// End Public Methods
// Begin Private Methods
private void AddValuesPrivate(int startIndex, int count, T value, int? startRangeIndex)
{
Debug.Assert(count > 0, "Expected a strictly positive count parameter.");
int endIndex = startIndex + count - 1;
Range<T> newRange = new Range<T>(startIndex, endIndex, value);
if (_list.Count == 0)
{
_list.Add(newRange);
}
else
{
int lowerRangeIndex = startRangeIndex ?? this.FindRangeIndex(startIndex);
Range<T> lowerRange = (lowerRangeIndex < 0) ? null : _list[lowerRangeIndex];
if (lowerRange == null)
{
if (lowerRangeIndex < 0)
{
lowerRangeIndex = 0;
}
_list.Insert(lowerRangeIndex, newRange);
}
else
{
if (!lowerRange.Value.Equals(value) && (lowerRange.UpperBound >= startIndex))
{
// Split up the range
if (lowerRange.UpperBound > endIndex)
{
_list.Insert(lowerRangeIndex + 1, new Range<T>(endIndex + 1, lowerRange.UpperBound, lowerRange.Value));
}
lowerRange.UpperBound = startIndex - 1;
if (!RemoveRangeIfInvalid(lowerRange, lowerRangeIndex))
{
lowerRangeIndex++;
}
_list.Insert(lowerRangeIndex, newRange);
}
else
{
_list.Insert(lowerRangeIndex + 1, newRange);
if (!Merge(lowerRangeIndex))
{
lowerRangeIndex++;
}
}
}
// At this point the newRange has been inserted in the correct place, now we need to remove
// any subsequent ranges that no longer make sense and possibly update the one at newRange.UpperBound
int upperRangeIndex = lowerRangeIndex + 1;
while ((upperRangeIndex < _list.Count) && (_list[upperRangeIndex].UpperBound < endIndex))
{
_list.RemoveAt(upperRangeIndex);
}
if (upperRangeIndex < _list.Count)
{
Range<T> upperRange = _list[upperRangeIndex];
if (upperRange.LowerBound <= endIndex)
{
// Update the range
upperRange.LowerBound = endIndex + 1;
RemoveRangeIfInvalid(upperRange, upperRangeIndex);
}
Merge(lowerRangeIndex);
}
}
}
// Returns the index of the range that contains the input or the range before if the input is not found
private int FindRangeIndex(int index)
{
if (_list.Count == 0)
{
return -1;
}
// Do a binary search for the index
int front = 0;
int end = _list.Count - 1;
Range<T> range;
while (end > front)
{
int median = (front + end) / 2;
range = _list[median];
if (range.UpperBound < index)
{
front = median + 1;
}
else if (range.LowerBound > index)
{
end = median - 1;
}
else
{
// we found it
return median;
}
}
if (front == end)
{
range = _list[front];
if (range.ContainsIndex(index) || (range.UpperBound < index))
{
// we found it or the index isn't there and we're one range before
return front;
}
else
{
// not found and we're one range after
return front - 1;
}
}
else
{
// end is one index before front in this case so it's the range before
return end;
}
}
private bool Merge(int lowerRangeIndex)
{
int upperRangeIndex = lowerRangeIndex + 1;
if ((lowerRangeIndex >= 0) && (upperRangeIndex < _list.Count))
{
Range<T> lowerRange = _list[lowerRangeIndex];
Range<T> upperRange = _list[upperRangeIndex];
if (lowerRange.UpperBound + 1 >= upperRange.LowerBound && lowerRange.Value.Equals(upperRange.Value))
{
lowerRange.UpperBound = Math.Max(lowerRange.UpperBound, upperRange.UpperBound);
_list.RemoveAt(upperRangeIndex);
return true;
}
}
return false;
}
private void InsertIndexesPrivate(int startIndex, int count, int lowerRangeIndex)
{
Debug.Assert(count > 0, "Expected a strictly positive count parameter.");
// Same as AddRange after we fix the indices affected by the insertion
int startRangeIndex = (lowerRangeIndex >= 0) ? lowerRangeIndex : 0;
for (int i = startRangeIndex; i < _list.Count; i++)
{
Range<T> range = _list[i];
if (range.LowerBound >= startIndex)
{
range.LowerBound += count;
}
else
{
if (range.UpperBound >= startIndex)
{
// Split up this range
i++;
_list.Insert(i, new Range<T>(startIndex, range.UpperBound + count, range.Value));
range.UpperBound = startIndex - 1;
continue;
}
}
if (range.UpperBound >= startIndex)
{
range.UpperBound += count;
}
}
}
private bool IsCorrectRangeIndex(int rangeIndex, int index)
{
return rangeIndex != -1 && _list[rangeIndex].ContainsIndex(index);
}
private bool RemoveRangeIfInvalid(Range<T> range, int rangeIndex)
{
if (range.UpperBound < range.LowerBound)
{
_list.RemoveAt(rangeIndex);
return true;
}
return false;
}
// End Private Methods
// Begin IEnumerable<Range<T>> Members
public IEnumerator<Range<T>> GetEnumerator()
{
return _list.GetEnumerator();
}
// End IEnumerable<Range<T>> Members
// Begin IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _list.GetEnumerator();
}
// End IEnumerable Members
#if DEBUG
public void PrintIndexes()
{
Debug.WriteLine(this.IndexCount + " indexes");
foreach (Range<T> range in _list)
{
Debug.WriteLine(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0} - {1}", range.LowerBound, range.UpperBound));
}
}
#endif
}
}

Просмотреть файл

@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.Utilities
{
internal static class KeyboardHelper
{
public static void GetMetaKeyState(out bool ctrl, out bool shift)
{
ctrl = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
shift = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
}
public static void GetMetaKeyState(out bool ctrl, out bool shift, out bool alt)
{
GetMetaKeyState(out ctrl, out shift);
alt = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Microsoft.Toolkit.Uwp.Utilities
{
internal class Range<T>
{
public Range(int lowerBound, int upperBound, T value)
{
LowerBound = lowerBound;
UpperBound = upperBound;
Value = value;
}
public int Count
{
get
{
return UpperBound - LowerBound + 1;
}
}
public int LowerBound
{
get;
set;
}
public int UpperBound
{
get;
set;
}
public T Value
{
get;
set;
}
public bool ContainsIndex(int index)
{
return LowerBound <= index && UpperBound >= index;
}
public bool ContainsValue(object value)
{
return (this.Value == null) ? value == null : this.Value.Equals(value);
}
public Range<T> Copy()
{
return new Range<T>(LowerBound, UpperBound, Value);
}
}
}

Просмотреть файл

@ -0,0 +1,478 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Windows.UI.Xaml.Data;
namespace Microsoft.Toolkit.Uwp.Utilities
{
internal static class TypeHelper
{
internal const char LeftIndexerToken = '[';
internal const char PropertyNameSeparator = '.';
internal const char RightIndexerToken = ']';
private static bool isAPIsAvailableInitialized = false;
private static bool isXamlRootAvailable = false;
// Methods
private static Type FindGenericType(Type definition, Type type)
{
TypeInfo definitionTypeInfo = definition.GetTypeInfo();
while (type != null && type != typeof(object))
{
TypeInfo typeTypeInfo = type.GetTypeInfo();
if (typeTypeInfo.IsGenericType && type.GetGenericTypeDefinition() == definition)
{
return type;
}
if (definitionTypeInfo.IsInterface)
{
foreach (Type type2 in typeTypeInfo.ImplementedInterfaces)
{
Type type3 = FindGenericType(definition, type2);
if (type3 != null)
{
return type3;
}
}
}
type = typeTypeInfo.BaseType;
}
return null;
}
/// <summary>
/// Finds an int or string indexer in the specified collection of members, where int indexers take priority
/// over string indexers. If found, this method will return the associated PropertyInfo and set the out index
/// argument to its appropriate value. If not found, the return value will be null, as will the index.
/// </summary>
/// <param name="members">Collection of members to search through for an indexer.</param>
/// <param name="stringIndex">String value of indexer argument.</param>
/// <param name="index">Resultant index value.</param>
/// <returns>Indexer PropertyInfo if found, null otherwise.</returns>
private static PropertyInfo FindIndexerInMembers(MemberInfo[] members, string stringIndex, out object[] index)
{
index = null;
ParameterInfo[] parameters;
PropertyInfo stringIndexer = null;
foreach (PropertyInfo pi in members)
{
if (pi == null)
{
continue;
}
// Only a single parameter is supported and it must be a string or Int32 value.
parameters = pi.GetIndexParameters();
if (parameters.Length > 1)
{
continue;
}
if (parameters[0].ParameterType == typeof(int))
{
int intIndex = -1;
if (int.TryParse(stringIndex.Trim(), NumberStyles.None, CultureInfo.InvariantCulture, out intIndex))
{
index = new object[] { intIndex };
return pi;
}
}
// If string indexer is found save it, in case there is an int indexer.
if (parameters[0].ParameterType == typeof(string))
{
index = new object[] { stringIndex };
stringIndexer = pi;
}
}
return stringIndexer;
}
/// <summary>
/// Gets the default member name that is used for an indexer (e.g. "Item").
/// </summary>
/// <param name="type">Type to check.</param>
/// <returns>Default member name.</returns>
private static string GetDefaultMemberName(this Type type)
{
DefaultMemberAttribute defaultMemberAttribute = type.GetTypeInfo().GetCustomAttributes().OfType<DefaultMemberAttribute>().FirstOrDefault();
return defaultMemberAttribute == null ? null : defaultMemberAttribute.MemberName;
}
internal static string GetBindingPropertyName(this Binding binding)
{
return binding?.Path?.Path?.Split('.')?.LastOrDefault();
}
/// <summary>
/// Finds the PropertyInfo for the specified property path within this Type, and returns
/// the value of GetShortName on its DisplayAttribute, if one exists. GetShortName will return
/// the value of Name if there is no ShortName specified.
/// </summary>
/// <param name="type">Type to search</param>
/// <param name="propertyPath">property path</param>
/// <returns>DisplayAttribute.ShortName if it exists, null otherwise</returns>
internal static string GetDisplayName(this Type type, string propertyPath)
{
PropertyInfo propertyInfo = type.GetNestedProperty(propertyPath);
if (propertyInfo != null)
{
DisplayAttribute displayAttribute = propertyInfo.GetCustomAttributes().OfType<DisplayAttribute>().FirstOrDefault();
return displayAttribute == null ? null : displayAttribute.GetShortName();
}
return null;
}
internal static Type GetEnumerableItemType(this Type enumerableType)
{
Type type = FindGenericType(typeof(IEnumerable<>), enumerableType);
if (type != null)
{
return type.GetGenericArguments()[0];
}
return enumerableType;
}
internal static PropertyInfo GetNestedProperty(this Type parentType, string propertyPath)
{
if (parentType != null)
{
object item = null;
return parentType.GetNestedProperty(propertyPath, ref item);
}
return null;
}
/// <summary>
/// Finds the leaf PropertyInfo for the specified property path, and returns its value
/// if the item is non-null.
/// </summary>
/// <param name="parentType">Type to search.</param>
/// <param name="propertyPath">Property path.</param>
/// <param name="item">Parent item which will be set to the property value if non-null.</param>
/// <returns>The PropertyInfo.</returns>
internal static PropertyInfo GetNestedProperty(this Type parentType, string propertyPath, ref object item)
{
if (parentType == null || string.IsNullOrEmpty(propertyPath))
{
item = null;
return null;
}
PropertyInfo propertyInfo = null;
Type propertyType = parentType;
List<string> propertyNames = SplitPropertyPath(propertyPath);
for (int i = 0; i < propertyNames.Count; i++)
{
propertyInfo = propertyType.GetPropertyOrIndexer(propertyNames[i], out var index);
if (propertyInfo == null)
{
item = null;
return null;
}
if (item != null)
{
item = propertyInfo.GetValue(item, index);
}
propertyType = propertyInfo.PropertyType.GetNonNullableType();
}
return propertyInfo;
}
internal static Type GetNestedPropertyType(this Type parentType, string propertyPath)
{
if (parentType == null || string.IsNullOrEmpty(propertyPath))
{
return parentType;
}
PropertyInfo propertyInfo = parentType.GetNestedProperty(propertyPath);
if (propertyInfo != null)
{
return propertyInfo.PropertyType;
}
return null;
}
/// <summary>
/// Gets the value of a given property path on a particular data item.
/// </summary>
/// <param name="item">Parent data item.</param>
/// <param name="propertyPath">Property path.</param>
/// <returns>Value.</returns>
internal static object GetNestedPropertyValue(object item, string propertyPath)
{
if (item != null)
{
Type parentType = item.GetCustomOrCLRType();
if (string.IsNullOrEmpty(propertyPath))
{
return item;
}
else if (parentType != null)
{
object nestedValue = item;
parentType.GetNestedProperty(propertyPath, ref nestedValue);
return nestedValue;
}
}
return null;
}
internal static Type GetNonNullableType(this Type type)
{
if (IsNullableType(type))
{
return type.GetGenericArguments()[0];
}
return type;
}
/// <summary>
/// Returns the PropertyInfo for the specified property path. If the property path
/// refers to an indexer (e.g. "[abc]"), then the index out parameter will be set to the value
/// specified in the property path. This method only supports indexers with a single parameter
/// that is either an int or a string. Int parameters take priority over string parameters.
/// </summary>
/// <param name="type">Type to search.</param>
/// <param name="propertyPath">Property path.</param>
/// <param name="index">Set to the index if return value is an indexer, otherwise null.</param>
/// <returns>PropertyInfo for either a property or an indexer.</returns>
internal static PropertyInfo GetPropertyOrIndexer(this Type type, string propertyPath, out object[] index)
{
index = null;
if (string.IsNullOrEmpty(propertyPath) || propertyPath[0] != LeftIndexerToken)
{
// Return the default value of GetProperty if the first character is not an indexer token.
return type.GetProperty(propertyPath);
}
if (propertyPath.Length < 2 || propertyPath[propertyPath.Length - 1] != RightIndexerToken)
{
// Return null if the indexer does not meet the standard format (i.e. "[x]").
return null;
}
var stringIndex = propertyPath.Substring(1, propertyPath.Length - 2);
var indexer = FindIndexerInMembers(type.GetDefaultMembers(), stringIndex, out index);
if (indexer != null)
{
// We found the indexer, so return it.
return indexer;
}
if (typeof(System.Collections.IList).IsAssignableFrom(type))
{
// If the object is of type IList, try to use its default indexer.
indexer = FindIndexerInMembers(typeof(System.Collections.IList).GetDefaultMembers(), stringIndex, out index);
}
return indexer;
}
internal static bool IsEnumerableType(this Type enumerableType)
{
return FindGenericType(typeof(IEnumerable<>), enumerableType) != null;
}
internal static bool IsNullableType(this Type type)
{
return type != null && type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
/* Unused for now
internal static bool IsNullableEnum(this Type type)
{
return type.IsNullableType() &&
type.GenericTypeArguments.Length == 1 &&
type.GenericTypeArguments[0].GetTypeInfo().IsEnum;
}
*/
/// <summary>
/// If the specified property is an indexer, this method will prepend the object's
/// default member name to it (e.g. "[foo]" returns "Item[foo]").
/// </summary>
/// <param name="item">Declaring data item.</param>
/// <param name="property">Property name.</param>
/// <returns>Property with default member name prepended, or property if unchanged.</returns>
internal static string PrependDefaultMemberName(object item, string property)
{
if (item != null && !string.IsNullOrEmpty(property) && property[0] == TypeHelper.LeftIndexerToken)
{
// The leaf property name is an indexer, so add the default member name.
Type declaringType = item.GetCustomOrCLRType();
if (declaringType != null)
{
string defaultMemberName = declaringType.GetNonNullableType().GetDefaultMemberName();
if (!string.IsNullOrEmpty(defaultMemberName))
{
return defaultMemberName + property;
}
}
}
return property;
}
/// <summary>
/// If the specified property is an indexer, this method will remove the object's
/// default member name from it (e.g. "Item[foo]" returns "[foo]").
/// </summary>
/// <param name="property">Property name.</param>
/// <returns>Property with default member name removed, or property if unchanged.</returns>
internal static string RemoveDefaultMemberName(string property)
{
if (!string.IsNullOrEmpty(property) && property[property.Length - 1] == TypeHelper.RightIndexerToken)
{
// The property is an indexer, so remove the default member name.
int leftIndexerToken = property.IndexOf(TypeHelper.LeftIndexerToken);
if (leftIndexerToken >= 0)
{
return property.Substring(leftIndexerToken);
}
}
return property;
}
/// <summary>
/// Sets the value of a given property path on a particular item.
/// </summary>
/// <param name="item">Parent data item.</param>
/// <param name="newValue">New child value</param>
/// <param name="propertyPath">Property path</param>
internal static void SetNestedPropertyValue(ref object item, object newValue, string propertyPath)
{
if (string.IsNullOrEmpty(propertyPath))
{
item = newValue;
}
else
{
var propertyPathParts = SplitPropertyPath(propertyPath);
if (propertyPathParts.Count == 1)
{
item?.GetType().GetProperty(propertyPath)?.SetValue(item, newValue);
}
else
{
object temporaryItem = item;
object nextToLastItem = null;
PropertyInfo propertyInfo = null;
for (var i = 0; i < propertyPathParts.Count; i++)
{
propertyInfo = temporaryItem?.GetType().GetProperty(propertyPathParts[i]);
if (i == propertyPathParts.Count - 2)
{
nextToLastItem = propertyInfo?.GetValue(temporaryItem);
}
temporaryItem = propertyInfo?.GetValue(temporaryItem);
}
propertyInfo?.SetValue(nextToLastItem, newValue);
}
}
}
/// <summary>
/// Returns a list of substrings where each one represents a single property within a nested
/// property path which may include indexers. For example, the string "abc.d[efg][h].ijk"
/// would return the substrings: "abc", "d", "[efg]", "[h]", and "ijk".
/// </summary>
/// <param name="propertyPath">Path to split.</param>
/// <returns>List of property substrings.</returns>
internal static List<string> SplitPropertyPath(string propertyPath)
{
List<string> propertyPaths = new List<string>();
if (!string.IsNullOrEmpty(propertyPath))
{
int startIndex = 0;
for (int index = 0; index < propertyPath.Length; index++)
{
if (propertyPath[index] == PropertyNameSeparator)
{
propertyPaths.Add(propertyPath.Substring(startIndex, index - startIndex));
startIndex = index + 1;
}
else if (startIndex != index && propertyPath[index] == LeftIndexerToken)
{
propertyPaths.Add(propertyPath.Substring(startIndex, index - startIndex));
startIndex = index;
}
else if (index == propertyPath.Length - 1)
{
propertyPaths.Add(propertyPath.Substring(startIndex));
}
}
}
return propertyPaths;
}
/// <summary>
/// Returns instance.GetCustomType() if the instance implements ICustomTypeProvider; otherwise,
/// returns instance.GetType().
/// </summary>
/// <param name="instance">Object to return the type of</param>
/// <returns>Type of the instance</returns>
internal static Type GetCustomOrCLRType(this object instance)
{
ICustomTypeProvider customTypeProvider = instance as ICustomTypeProvider;
if (customTypeProvider != null)
{
return customTypeProvider.GetCustomType() ?? instance.GetType();
}
return instance == null ? null : instance.GetType();
}
internal static bool IsXamlRootAvailable
{
get
{
if (!isAPIsAvailableInitialized)
{
InitializeAPIsAvailable();
}
return isXamlRootAvailable;
}
}
internal static void InitializeAPIsAvailable()
{
isXamlRootAvailable = Windows.Foundation.Metadata.ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot");
isAPIsAvailableInitialized = true;
}
}
}

Просмотреть файл

@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.ViewManagement;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Utilities
{
/// <summary>
/// Helper class for accessing UISettings properties.
/// </summary>
internal static class UISettingsHelper
{
private static UISettings _uiSettings = null;
internal static bool AreSettingsEnablingAnimations
{
get
{
if (_uiSettings == null)
{
_uiSettings = new UISettings();
}
return _uiSettings.AnimationsEnabled;
}
}
internal static bool AreSettingsAutoHidingScrollBars
{
get
{
// TODO: Use UISettings public API once available
return true;
}
}
}
}

Просмотреть файл

@ -0,0 +1,302 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Threading;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
namespace Microsoft.Toolkit.Uwp.UI.Data.Utilities
{
/// <summary>
/// Static class with methods to help with validation.
/// </summary>
internal static class ValidationUtil
{
/// <summary>
/// Adds a new ValidationResult to the collection if an equivalent does not exist.
/// </summary>
/// <param name="collection">ValidationResults to search through</param>
/// <param name="value">ValidationResult to add</param>
public static void AddIfNew(this ICollection<ValidationResult> collection, ValidationResult value)
{
if (!collection.ContainsEqualValidationResult(value))
{
collection.Add(value);
}
}
/// <summary>
/// Performs an action and catches any non-critical exceptions.
/// </summary>
/// <param name="action">Action to perform</param>
public static void CatchNonCriticalExceptions(Action action)
{
try
{
action();
}
catch (Exception exception)
{
if (IsCriticalException(exception))
{
throw;
}
// Catch any non-critical exceptions
}
}
/// <summary>
/// Determines whether the collection contains an equivalent ValidationResult
/// </summary>
/// <param name="collection">ValidationResults to search through</param>
/// <param name="target">ValidationResult to search for</param>
/// <returns>True when the collection contains an equivalent ValidationResult.</returns>
public static bool ContainsEqualValidationResult(this ICollection<ValidationResult> collection, ValidationResult target)
{
return collection.FindEqualValidationResult(target) != null;
}
/// <summary>
/// Searches a ValidationResult for the specified target member name. If the target is null
/// or empty, this method will return true if there are no member names at all.
/// </summary>
/// <param name="validationResult">ValidationResult to search.</param>
/// <param name="target">Member name to search for.</param>
/// <returns>True if found.</returns>
public static bool ContainsMemberName(this ValidationResult validationResult, string target)
{
int memberNameCount = 0;
foreach (string memberName in validationResult.MemberNames)
{
if (string.Equals(target, memberName))
{
return true;
}
memberNameCount++;
}
return memberNameCount == 0 && string.IsNullOrEmpty(target);
}
/// <summary>
/// Finds an equivalent ValidationResult if one exists.
/// </summary>
/// <param name="collection">ValidationResults to search through.</param>
/// <param name="target">ValidationResult to find.</param>
/// <returns>Equal ValidationResult if found, null otherwise.</returns>
public static ValidationResult FindEqualValidationResult(this ICollection<ValidationResult> collection, ValidationResult target)
{
foreach (ValidationResult oldValidationResult in collection)
{
if (oldValidationResult.ErrorMessage == target.ErrorMessage)
{
bool movedOld = true;
bool movedTarget = true;
IEnumerator<string> oldEnumerator = oldValidationResult.MemberNames.GetEnumerator();
IEnumerator<string> targetEnumerator = target.MemberNames.GetEnumerator();
while (movedOld && movedTarget)
{
movedOld = oldEnumerator.MoveNext();
movedTarget = targetEnumerator.MoveNext();
if (!movedOld && !movedTarget)
{
return oldValidationResult;
}
if (movedOld != movedTarget || oldEnumerator.Current != targetEnumerator.Current)
{
break;
}
}
}
}
return null;
}
/// <summary>
/// Searches through all Bindings on the specified element and returns a list of BindingInfo objects
/// for each Binding that matches the specified criteria.
/// </summary>
/// <param name="element">FrameworkElement to search</param>
/// <param name="dataItem">Only return Bindings with a context element equal to this object</param>
/// <param name="twoWayOnly">If true, only returns TwoWay Bindings</param>
/// <param name="useBlockList">If true, ignores elements not typically used for input</param>
/// <param name="searchChildren">If true, searches through the children</param>
/// <param name="excludedTypes">The Binding search will skip all of these Types</param>
/// <returns>List of BindingInfo for every Binding found</returns>
public static List<BindingInfo> GetBindingInfo(this FrameworkElement element, object dataItem, bool twoWayOnly, bool useBlockList, bool searchChildren, params Type[] excludedTypes)
{
List<BindingInfo> bindingData = new List<BindingInfo>();
if (!searchChildren)
{
if (excludedTypes != null)
{
foreach (Type excludedType in excludedTypes)
{
if (excludedType != null && excludedType.IsInstanceOfType(element))
{
return bindingData;
}
}
}
return element.GetBindingInfoOfSingleElement(element.DataContext ?? dataItem, dataItem, twoWayOnly, useBlockList);
}
Stack<DependencyObject> children = new Stack<DependencyObject>();
Stack<object> dataContexts = new Stack<object>();
children.Push(element);
dataContexts.Push(element.DataContext ?? dataItem);
while (children.Count != 0)
{
bool searchChild = true;
DependencyObject child = children.Pop();
object inheritedDataContext = dataContexts.Pop();
object dataContext = inheritedDataContext;
// Skip this particular child element if it is one of the excludedTypes
if (excludedTypes != null)
{
foreach (Type excludedType in excludedTypes)
{
if (excludedType != null && excludedType.IsInstanceOfType(child))
{
searchChild = false;
break;
}
}
}
// Add the bindings of the child element and push its children onto the stack of remaining elements to search
if (searchChild)
{
FrameworkElement childElement = child as FrameworkElement;
if (childElement != null)
{
dataContext = childElement.DataContext ?? inheritedDataContext;
bindingData.AddRange(childElement.GetBindingInfoOfSingleElement(inheritedDataContext, dataItem, twoWayOnly, useBlockList));
}
int childrenCount = VisualTreeHelper.GetChildrenCount(child);
for (int childIndex = 0; childIndex < childrenCount; childIndex++)
{
children.Push(VisualTreeHelper.GetChild(child, childIndex));
dataContexts.Push(dataContext);
}
}
}
return bindingData;
}
/// <summary>
/// Gets a list of the specified FrameworkElement's DependencyProperties. This method will return all
/// DependencyProperties of the element unless 'useBlockList' is true, in which case all bindings on elements
/// that are typically not used as input controls will be ignored.
/// </summary>
/// <param name="element">FrameworkElement of interest</param>
/// <param name="useBlockList">If true, ignores elements not typically used for input</param>
/// <returns>List of DependencyProperties</returns>
public static List<DependencyProperty> GetDependencyProperties(this FrameworkElement element, bool useBlockList)
{
List<DependencyProperty> dependencyProperties = new List<DependencyProperty>();
bool isBlocklisted = useBlockList &&
(element is Panel || element is Button || element is Image || element is ScrollViewer || element is TextBlock ||
element is Border || element is Shape || element is ContentPresenter);
if (!isBlocklisted)
{
Type type = element.GetType();
FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
foreach (FieldInfo field in fields)
{
if (field.FieldType == typeof(DependencyProperty))
{
dependencyProperties.Add((DependencyProperty)field.GetValue(null));
}
}
}
return dependencyProperties;
}
/// <summary>
/// Determines if the specified exception is un-recoverable.
/// </summary>
/// <param name="exception">The exception.</param>
/// <returns>True if the process cannot be recovered from the exception.</returns>
public static bool IsCriticalException(Exception exception)
{
return (exception is OutOfMemoryException) ||
(exception is StackOverflowException) ||
(exception is AccessViolationException) ||
(exception is ThreadAbortException);
}
/// <summary>
/// Gets a list of active bindings on the specified FrameworkElement. Bindings are gathered
/// according to the same conditions BindingGroup uses to find bindings of descendant elements
/// within the visual tree.
/// </summary>
/// <param name="element">Root FrameworkElement to search under</param>
/// <param name="inheritedDataContext">DomainContext of the element's parent</param>
/// <param name="dataItem">Target DomainContext</param>
/// <param name="twoWayOnly">If true, only returns TwoWay Bindings</param>
/// <param name="useBlockList">If true, ignores elements not typically used for input</param>
/// <returns>List of active bindings on the specified FrameworkElement.</returns>
private static List<BindingInfo> GetBindingInfoOfSingleElement(this FrameworkElement element, object inheritedDataContext, object dataItem, bool twoWayOnly, bool useBlockList)
{
// Now see which of the possible dependency properties are being used
List<BindingInfo> bindingData = new List<BindingInfo>();
foreach (DependencyProperty bindingTarget in element.GetDependencyProperties(useBlockList))
{
// We add bindings according to the same conditions as BindingGroups:
// Element.Binding.Mode == TwoWay
// Element.Binding.Source == null
// DataItem == ContextElement.DataContext where:
// If Element is ContentPresenter and TargetProperty is Content, ContextElement = Element.Parent
// Else if TargetProperty is DomainContext, ContextElement = Element.Parent
// Else ContextElement = Element
BindingExpression bindingExpression = element.GetBindingExpression(bindingTarget);
if (bindingExpression != null &&
bindingExpression.ParentBinding != null &&
(!twoWayOnly || bindingExpression.ParentBinding.Mode == BindingMode.TwoWay) &&
bindingExpression.ParentBinding.Source == null)
{
object dataContext;
if (bindingTarget == FrameworkElement.DataContextProperty
|| (element is ContentPresenter && bindingTarget == ContentPresenter.ContentProperty))
{
dataContext = inheritedDataContext;
}
else
{
dataContext = element.DataContext ?? inheritedDataContext;
}
if (dataItem == dataContext)
{
bindingData.Add(new BindingInfo(bindingExpression, bindingTarget, element));
}
}
}
return bindingData;
}
}
}

Просмотреть файл

@ -0,0 +1,290 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Microsoft.Toolkit.Uwp.UI.Controls.Utilities
{
/// <summary>
/// Names and helpers for visual states in the control.
/// </summary>
internal static class VisualStates
{
// GroupCommon
/// <summary>
/// Normal state
/// </summary>
public const string StateNormal = "Normal";
/// <summary>
/// PointerOver state
/// </summary>
public const string StatePointerOver = "PointerOver";
/// <summary>
/// Pressed state
/// </summary>
public const string StatePressed = "Pressed";
/// <summary>
/// Disabled state
/// </summary>
public const string StateDisabled = "Disabled";
/// <summary>
/// Common state group
/// </summary>
public const string GroupCommon = "CommonStates";
// GroupExpanded
/// <summary>
/// Expanded state
/// </summary>
public const string StateExpanded = "Expanded";
/// <summary>
/// Collapsed state
/// </summary>
public const string StateCollapsed = "Collapsed";
/// <summary>
/// Empty state
/// </summary>
public const string StateEmpty = "Empty";
// GroupFocus
/// <summary>
/// Unfocused state
/// </summary>
public const string StateUnfocused = "Unfocused";
/// <summary>
/// Focused state
/// </summary>
public const string StateFocused = "Focused";
/// <summary>
/// Focus state group
/// </summary>
public const string GroupFocus = "FocusStates";
// GroupSelection
/// <summary>
/// Selected state
/// </summary>
public const string StateSelected = "Selected";
/// <summary>
/// Unselected state
/// </summary>
public const string StateUnselected = "Unselected";
/// <summary>
/// Selection state group
/// </summary>
public const string GroupSelection = "SelectionStates";
// GroupActive
/// <summary>
/// Active state
/// </summary>
public const string StateActive = "Active";
/// <summary>
/// Inactive state
/// </summary>
public const string StateInactive = "Inactive";
/// <summary>
/// Active state group
/// </summary>
public const string GroupActive = "ActiveStates";
// GroupCurrent
/// <summary>
/// Regular state
/// </summary>
public const string StateRegular = "Regular";
/// <summary>
/// Current state
/// </summary>
public const string StateCurrent = "Current";
/// <summary>
/// CurrentWithFocus state
/// </summary>
public const string StateCurrentWithFocus = "CurrentWithFocus";
/// <summary>
/// Current state group
/// </summary>
public const string GroupCurrent = "CurrentStates";
// GroupInteraction
/// <summary>
/// Display state
/// </summary>
public const string StateDisplay = "Display";
/// <summary>
/// Editing state
/// </summary>
public const string StateEditing = "Editing";
/// <summary>
/// Interaction state group
/// </summary>
public const string GroupInteraction = "InteractionStates";
// GroupSort
/// <summary>
/// Unsorted state
/// </summary>
public const string StateUnsorted = "Unsorted";
/// <summary>
/// Sort Ascending state
/// </summary>
public const string StateSortAscending = "SortAscending";
/// <summary>
/// Sort Descending state
/// </summary>
public const string StateSortDescending = "SortDescending";
/// <summary>
/// Sort state group
/// </summary>
public const string GroupSort = "SortStates";
// GroupValidation
/// <summary>
/// Invalid state
/// </summary>
public const string StateInvalid = "Invalid";
/// <summary>
/// RowInvalid state
/// </summary>
public const string StateRowInvalid = "RowInvalid";
/// <summary>
/// RowValid state
/// </summary>
public const string StateRowValid = "RowValid";
/// <summary>
/// Valid state
/// </summary>
public const string StateValid = "Valid";
#if FEATURE_VALIDATION
// RuntimeValidationStates
public const string StateInvalidUnfocused = "InvalidUnfocused";
#endif
/// <summary>
/// Validation state group
/// </summary>
public const string GroupValidation = "ValidationStates";
// GroupScrollBarsSeparator
/// <summary>
/// SeparatorExpanded state
/// </summary>
public const string StateSeparatorExpanded = "SeparatorExpanded";
/// <summary>
/// ScrollBarsSeparatorCollapsed state
/// </summary>
public const string StateSeparatorCollapsed = "SeparatorCollapsed";
/// <summary>
/// SeparatorExpandedWithoutAnimation state
/// </summary>
public const string StateSeparatorExpandedWithoutAnimation = "SeparatorExpandedWithoutAnimation";
/// <summary>
/// SeparatorCollapsedWithoutAnimation state
/// </summary>
public const string StateSeparatorCollapsedWithoutAnimation = "SeparatorCollapsedWithoutAnimation";
/// <summary>
/// ScrollBarsSeparator state group
/// </summary>
public const string GroupScrollBarsSeparator = "ScrollBarsSeparatorStates";
// GroupScrollBars
/// <summary>
/// TouchIndicator state
/// </summary>
public const string StateTouchIndicator = "TouchIndicator";
/// <summary>
/// MouseIndicator state
/// </summary>
public const string StateMouseIndicator = "MouseIndicator";
/// <summary>
/// MouseIndicatorFull state
/// </summary>
public const string StateMouseIndicatorFull = "MouseIndicatorFull";
/// <summary>
/// NoIndicator state
/// </summary>
public const string StateNoIndicator = "NoIndicator";
/// <summary>
/// ScrollBars state group
/// </summary>
public const string GroupScrollBars = "ScrollBarsStates";
/// <summary>
/// Use VisualStateManager to change the visual state of the control.
/// </summary>
/// <param name="control">
/// Control whose visual state is being changed.
/// </param>
/// <param name="useTransitions">
/// true to use transitions when updating the visual state, false to
/// snap directly to the new visual state.
/// </param>
/// <param name="stateNames">
/// Ordered list of state names and fallback states to transition into.
/// Only the first state to be found will be used.
/// </param>
public static void GoToState(Control control, bool useTransitions, params string[] stateNames)
{
Debug.Assert(control != null, "Expected non-null control.");
if (stateNames == null)
{
return;
}
foreach (string name in stateNames)
{
if (VisualStateManager.GoToState(control, name, useTransitions))
{
break;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,79 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace Microsoft.Toolkit.Uwp.Utilities
{
/// <summary>
/// Implements a weak event listener that allows the owner to be garbage
/// collected if its only remaining link is an event handler.
/// Note: Copied from Microsoft.Toolkit.Uwp.Helpers.WeakEventListener to avoid taking a
/// dependency on Microsoft.Toolkit.Uwp.dll and Microsoft.Toolkit.dll.
/// </summary>
/// <typeparam name="TInstance">Type of instance listening for the event.</typeparam>
/// <typeparam name="TSource">Type of source for the event.</typeparam>
/// <typeparam name="TEventArgs">Type of event arguments for the event.</typeparam>
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
internal sealed class WeakEventListener<TInstance, TSource, TEventArgs>
where TInstance : class
{
/// <summary>
/// WeakReference to the instance listening for the event.
/// </summary>
private WeakReference<TInstance> weakInstance;
/// <summary>
/// Initializes a new instance of the <see cref="WeakEventListener{TInstance, TSource, TEventArgs}"/> class.
/// </summary>
/// <param name="instance">Instance subscribing to the event.</param>
public WeakEventListener(TInstance instance)
{
if (instance == null)
{
throw new ArgumentNullException(nameof(instance));
}
weakInstance = new WeakReference<TInstance>(instance);
}
/// <summary>
/// Gets or sets the method to call when the event fires.
/// </summary>
public Action<TInstance, TSource, TEventArgs> OnEventAction { get; set; }
/// <summary>
/// Gets or sets the method to call when detaching from the event.
/// </summary>
public Action<WeakEventListener<TInstance, TSource, TEventArgs>> OnDetachAction { get; set; }
/// <summary>
/// Handler for the subscribed event calls OnEventAction to handle it.
/// </summary>
/// <param name="source">Event source.</param>
/// <param name="eventArgs">Event arguments.</param>
public void OnEvent(TSource source, TEventArgs eventArgs)
{
if (weakInstance.TryGetTarget(out var target))
{
// Call registered action
OnEventAction?.Invoke(target, source, eventArgs);
}
else
{
// Detach from event
Detach();
}
}
/// <summary>
/// Detaches from the subscribed event.
/// </summary>
public void Detach()
{
OnDetachAction?.Invoke(this);
OnDetachAction = null;
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<FileList>
<File Reference="Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.dll">
<ToolboxItems VSCategory="Windows Community Toolkit" BlendCategory="Windows Community Toolkit">
<Item Type="Microsoft.Toolkit.Uwp.UI.Controls.DataGrid" />
</ToolboxItems>
</File>
</FileList>

45
azure-pipelines.yml Normal file
Просмотреть файл

@ -0,0 +1,45 @@
jobs:
- job: Windows
pool:
vmImage: windows-2019
steps:
- task: gitversion/setup@0
displayName: Install GitVersion
inputs:
versionSpec: '5.6.3'
- task: gitversion/execute@0
displayName: GitVersion
inputs:
useConfigFile: true
configFilePath: gitversion.yml
- task: DotNetCoreCLI@2
displayName: Build Uno.WinUI3Convert
inputs:
command: build
arguments: --verbosity detailed --configuration Release "-p:PackageOutputPath=$(Build.ArtifactStagingDirectory)" "-p:PackageVersion=$(GITVERSION.SemVer)"
workingDirectory: src/Uno.WinUI3Convert
- task: DotNetCoreCLI@2
displayName: Install Uno.WinUI3Convert
inputs:
command: custom
custom: tool
arguments: install --global --add-source $(Build.ArtifactStagingDirectory) --version $(GITVERSION.SemVer) uno.winui3convert
- powershell: winui3convert Tests\Microsoft.Toolkit.Uwp.UI.Controls.DataGrid Tests\out\Microsoft.Toolkit.Uwp.UI.Controls.DataGrid
displayName: Convert Microsoft.Toolkit.Uwp.UI.Controls.DataGrid sources
- task: MSBuild@1
displayName: Build Microsoft.Toolkit.Uwp.UI.Controls.DataGrid
inputs:
solution: Tests/out/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid/Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.csproj
configuration: Release
msbuildArguments: /ds /r
maximumCpuCount: true
- task: PublishBuildArtifacts@1
displayName: Publish Artifacts
inputs:
artifactName: Tool

Двоичные данные
build/uno-logo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.0 KiB

54
gitversion.yml Normal file
Просмотреть файл

@ -0,0 +1,54 @@
assembly-versioning-scheme: MajorMinorPatch
mode: Mainline
next-version: 1.0
branches:
master:
mode: ContinuousDeployment
regex: master
tag: dev
increment: Minor
is-source-branch-for: ['beta', 'stable']
pull-request:
regex: ^(pull|pull\-requests|pr)[/-]
mode: ContinuousDeployment
tag: 'PullRequest'
tag-number-pattern: '[/-](?<number>\d+)[-/]'
increment: Inherit
beta:
mode: ContinuousDeployment
regex: ^release/beta/.*
tag: beta
increment: none
source-branches: ['master']
stable:
regex: ^release/stable/.*
tag: ''
increment: Patch
source-branches: ['master','beta']
is-mainline: true
dev:
mode: ContinuousDeployment
regex: ^dev/.*?/(.*?)
tag: dev.{BranchName}
source-branches: ['master', 'release', 'projects', 'feature']
increment: none
projects:
tag: proj-{BranchName}
regex: ^projects/(.*?)
source-branches: ['master']
increment: none
feature:
tag: feature.{BranchName}
regex: ^feature/(.*?)
source-branches: ['master']
increment: none
ignore:
sha: []

24
src/Directory.Build.props Normal file
Просмотреть файл

@ -0,0 +1,24 @@
<Project>
<PropertyGroup>
<Authors>nventive</Authors>
<Copyright>Copyright (C) 2020-$([System.DateTime]::Now.ToString(`yyyy`)) nventive inc. - all rights reserved</Copyright>
<PackageIcon>uno-logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/unoplatform/winui3-convert</PackageProjectUrl>
<RepositoryUrl>$(BUILD_REPOSITORY_URI)</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)..\build\uno-logo.png" Pack="true" Visible="false" PackagePath="\"/>
</ItemGroup>
<PropertyGroup Condition="'$(SourceLinkEnabled)' != 'false'">
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup>
<ItemGroup Condition="'$(SourceLinkEnabled)' != 'false'">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>
</Project>

25
src/Uno.WinUI3Convert.sln Normal file
Просмотреть файл

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30711.63
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.WinUI3Convert", "Uno.WinUI3Convert\Uno.WinUI3Convert.csproj", "{DB254870-0503-4C62-8985-6D50885A3542}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DB254870-0503-4C62-8985-6D50885A3542}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB254870-0503-4C62-8985-6D50885A3542}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB254870-0503-4C62-8985-6D50885A3542}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB254870-0503-4C62-8985-6D50885A3542}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {16F1C62D-11B1-457C-B75C-E6F2105014E1}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Uno.WinUI3Convert
{
public class ConvertCommand
{
public static int Execute(DirectoryInfo source, DirectoryInfo destination, bool overwrite, IHost host)
{
var logger =
host.Services
.GetRequiredService<ILoggerFactory>()
.CreateLogger<ConvertCommand>();
try
{
if (destination.Exists)
{
if (overwrite)
{
destination.Delete(true);
logger.LogInformation($"Directory \"{destination}\" deleted.");
}
else
{
logger.LogError("Destination exists and overwrite flag is not set.");
return -1;
}
}
destination.Create();
logger.LogInformation($"Copying files to \"{destination}\"...");
CopyFiles(source, destination);
logger.LogInformation($"Rewriting files...");
RewriteFiles(destination, logger);
logger.LogInformation($"Rewriting projects...");
RewriteProjects(destination, logger);
logger.LogInformation($"Done.");
return 0;
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred.");
return -1;
}
}
private static void CopyFiles(DirectoryInfo source, DirectoryInfo destination)
{
var subdirectories = source.EnumerateDirectories("*", SearchOption.AllDirectories);
foreach (var directory in subdirectories)
{
var pathFromBase = Path.GetRelativePath(source.FullName, directory.FullName);
Directory.CreateDirectory(Path.Combine(destination.FullName, pathFromBase));
}
var files = source.EnumerateFiles("*", SearchOption.AllDirectories);
foreach (var file in files)
{
var pathFromBase = Path.GetRelativePath(source.FullName, file.FullName);
File.Copy(file.FullName, Path.Combine(destination.FullName, pathFromBase));
}
}
private static void RewriteFiles(DirectoryInfo source, ILogger<ConvertCommand> logger)
{
var files = source.EnumerateFiles("*.cs", SearchOption.AllDirectories);
var mappings = new Dictionary<string, string>()
{
// Discard
{ "using Windows.UI.Input;", string.Empty },
// Usings
{ "using Windows.UI.Text;", "using Microsoft.UI.Text;\r\nusing Windows.UI.Text;" },
{ "using Windows.UI.Xaml.Automation.Peers;", "using Microsoft.UI.Xaml.Automation.Peers;" },
{ "using Windows.UI.Xaml.Automation.Provider;", "using Microsoft.UI.Xaml.Automation.Provider;" },
{ "using Windows.UI.Xaml.Automation;", "using Microsoft.UI.Xaml.Automation;" },
{ "using Windows.UI.Xaml.Controls.Primitives;", "using Microsoft.UI.Xaml.Controls.Primitives;" },
{ "using Windows.UI.Xaml.Controls;", "using Microsoft.UI.Xaml.Controls;" },
{ "using Windows.UI.Xaml.Data;", "using Microsoft.UI.Xaml.Data;" },
{ "using Windows.UI.Xaml.Input;", "using Microsoft.UI.Xaml.Input;" },
{ "using Windows.UI.Xaml.Media.Animation;", "using Microsoft.UI.Xaml.Media.Animation;" },
{ "using Windows.UI.Xaml.Media;", "using Microsoft.UI.Xaml.Media;" },
{ "using Windows.UI.Xaml.Shapes;", "using Microsoft.UI.Xaml.Shapes;" },
{ "using Windows.UI.Xaml;", "using Microsoft.UI.Xaml;" },
{ "using Windows.UI;", "using Microsoft.UI;" },
// Namespaces
{ "Windows.UI.Xaml.Automation.Peers", "Microsoft.UI.Xaml.Automation.Peers" },
{ "Windows.UI.Xaml.Automation", "Microsoft.UI.Xaml.Automation" },
{ "Windows.UI.Xaml.Controls", "Microsoft.UI.Xaml.Controls" },
};
var regexes = new Dictionary<string, string>()
{
// Microsoft.System conflict with System
{ "(global::)?System\\.Collections", "global::System.Collections" },
{ "(global::)?System\\.ComponentModel", "global::System.ComponentModel" },
{ "(global::)?System\\.Globalization", "global::System.Globalization" },
{ "(global::)?System\\.Reflection", "global::System.Reflection" },
};
foreach (var file in files)
{
logger.LogInformation($"Rewriting {file}");
var content = File.ReadAllText(file.FullName);
foreach (var mapping in mappings)
{
content = content.Replace(mapping.Key, mapping.Value);
}
foreach (var regex in regexes)
{
content = Regex.Replace(content, regex.Key, regex.Value);
}
File.WriteAllText(file.FullName, content);
}
}
private static void RewriteProjects(DirectoryInfo source, ILogger<ConvertCommand> logger)
{
var projects = source.EnumerateFiles("*.csproj", SearchOption.AllDirectories);
foreach (var project in projects)
{
logger.LogInformation($"Rewriting {project}");
var document = XDocument.Load(project.FullName);
document.Root.Attribute("Sdk").Value = "MSBuild.Sdk.Extras/3.0.22";
document.Root.Descendants("TargetFramework").Single().Value = "net5.0-windows10.0.18362.0";
var winUIpackageReference = document.Root.Descendants("PackageReference").SingleOrDefault(e => e.Attribute("Include").Value == "Microsoft.WinUI");
if (winUIpackageReference != null)
{
winUIpackageReference.Attribute("Version").Value = "3.0.0-preview3.201113.0";
}
else
{
document.Root.Add(new XElement("ItemGroup", new XElement("PackageReference", new XAttribute("Include", "Microsoft.WinUI"), new XAttribute("Version", "3.0.0-preview3.201113.0"), null)));
}
using (var xw = XmlWriter.Create(project.FullName, new XmlWriterSettings() { Encoding = Encoding.UTF8, OmitXmlDeclaration = true, Indent = true, NamespaceHandling = NamespaceHandling.OmitDuplicates }))
{
document.Save(xw);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,41 @@
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Hosting;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
namespace Uno.WinUI3Convert
{
class Program
{
static Task<int> Main(string[] args)
{
var command = new RootCommand("Migrate UWP projects to WinUI 3")
{
new Argument<DirectoryInfo>("source", "Source directory")
{
Arity = ArgumentArity.ExactlyOne
}
.ExistingOnly(),
new Argument<DirectoryInfo>("destination", "Destination directory")
{
Arity = ArgumentArity.ExactlyOne
},
new Option<bool>("--overwrite", "Overwrite destination"),
};
command.Handler = CommandHandler.Create<DirectoryInfo, DirectoryInfo, bool, IHost>(ConvertCommand.Execute);
return new CommandLineBuilder(command)
.UseHost(_ => Host.CreateDefaultBuilder())
.UseDefaults()
.Build()
.InvokeAsync(args);
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Description>A dotnet tool to migrate UWP projects to WinUI 3</Description>
<GeneratePackageOnBuild Condition="'$(Configuration)'=='Release'">true</GeneratePackageOnBuild>
<PackAsTool>true</PackAsTool>
<ToolCommandName>winui3convert</ToolCommandName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.CommandLine.Hosting" Version="0.3.0-alpha.20574.7" />
</ItemGroup>
</Project>