794 lines
32 KiB
C#
794 lines
32 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Controls.Primitives;
|
|
using System.Windows.Data;
|
|
using System.Windows.Input;
|
|
using System.Windows.Markup;
|
|
using System.Windows.Threading;
|
|
using DTS.Common.Base;
|
|
using DTS.Common.Classes.ChannelCodes;
|
|
using DTS.Common.Classes.Groups;
|
|
using DTS.Common.Converters;
|
|
using DTS.Common.Enums;
|
|
using DTS.Common.Enums.Channels;
|
|
using DTS.Common.Events;
|
|
using DTS.Common.Events.Groups.GroupChannelList;
|
|
using DTS.Common.Interface.Channels.ChannelCodes;
|
|
using Microsoft.Practices.Prism.Commands;
|
|
using Microsoft.Practices.Prism.Events;
|
|
using Microsoft.Practices.ServiceLocation;
|
|
|
|
namespace DTS.Common.Controls
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for ChannelCodeBuilder.xaml
|
|
/// </summary>
|
|
public partial class ChannelCodeBuilder : UserControl, IBasePropertyChanged
|
|
{
|
|
private ISOPopup _isoPopup;
|
|
|
|
private LookupPopup _lookupPopup;
|
|
|
|
private DispatcherTimer _possiblesTimer;
|
|
|
|
public ChannelCodeBuilder()
|
|
{
|
|
InitializeComponent();
|
|
Loaded += (sender, args) => { if (!_registered) RegisterCommands(); };
|
|
}
|
|
|
|
public static readonly DependencyProperty CodeTypeProperty =
|
|
DependencyProperty.Register(
|
|
"CodeType", // The name of the DependencyProperty
|
|
typeof(ChannelEnumsAndConstants.ChannelCodeType), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
ChannelEnumsAndConstants.ChannelCodeType.User // The default value of the DependencyProperty
|
|
)
|
|
);
|
|
|
|
public ChannelEnumsAndConstants.ChannelCodeType CodeType
|
|
{
|
|
get => (ChannelEnumsAndConstants.ChannelCodeType) GetValue(CodeTypeProperty);
|
|
set => SetValue(CodeTypeProperty, value);
|
|
}
|
|
|
|
private static readonly DependencyProperty CodeProperty =
|
|
DependencyProperty.Register(
|
|
"Code", // The name of the DependencyProperty
|
|
typeof(string), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
"", // The default value of the DependencyProperty
|
|
OnCodeChanged,
|
|
CoerceCode
|
|
)
|
|
);
|
|
|
|
|
|
public static readonly DependencyProperty CoerceISOCodeProperty =
|
|
DependencyProperty.Register(
|
|
"CoerceISOCode",
|
|
typeof(CoerceISOCodeDelegate),
|
|
typeof(ChannelCodeBuilder),
|
|
new PropertyMetadata(null));
|
|
|
|
/// <summary>
|
|
/// defines a function to use to coerce iso codes
|
|
/// </summary>
|
|
public CoerceISOCodeDelegate CoerceISOCode
|
|
{
|
|
get => (CoerceISOCodeDelegate)GetValue(CoerceISOCodeProperty);
|
|
set => SetValue(CoerceISOCodeProperty, value);
|
|
}
|
|
private static object CoerceCode(DependencyObject d, object baseValue)
|
|
{
|
|
string val = baseValue?.ToString() ?? string.Empty;
|
|
val = Regex.Replace(val, @"[^\u0000-\u007F]+", "?");
|
|
ChannelCodeBuilder ccb = (ChannelCodeBuilder)d;
|
|
//if we have a function defined on how to coerce, use that, otherwise use existing coerce functions
|
|
if (null != ccb.CoerceISOCode && !ccb.MainEditBox.IsKeyboardFocused)
|
|
{
|
|
return ccb.CoerceISOCode(val, ccb.UniqueISOCodesRequired, ccb.UseISOCodeFilterMapping);
|
|
}
|
|
|
|
if (ccb?.CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && ccb.UniqueISOCodesRequired && !ccb.MainEditBox.IsKeyboardFocused)
|
|
{
|
|
val = val.ToUpper().PadRight(ChannelEnumsAndConstants.ISO_CODE_LENGTH, '?');
|
|
/*
|
|
13902
|
|
Cannot save test setup when leaving out one or more characters for a channels' ISO code
|
|
|
|
part of the issue is the CoerceValueCallback is called AFTER the original source is updated, meaning the property and the value on the screen are out of date with each other.
|
|
this code attempts to fix that by updating the property with the coerced value.
|
|
*/
|
|
if( ccb.Code != val )
|
|
{
|
|
ccb.SetCodeProperty(val);
|
|
}
|
|
}
|
|
return val;
|
|
}
|
|
private volatile bool _bInSet = false;
|
|
/*
|
|
13902
|
|
Cannot save test setup when leaving out one or more characters for a channels' ISO code
|
|
|
|
part of the issue is the CoerceValueCallback is called AFTER the original source is updated, meaning the property and the value on the screen are out of date with each other.
|
|
this code attempts to fix that by updating the property with the coerced value.
|
|
*/
|
|
public void SetCodeProperty(string value)
|
|
{
|
|
if( _bInSet ){ return; }
|
|
_bInSet = true;
|
|
SetValue(CodeProperty, value);
|
|
_bInSet = false;
|
|
}
|
|
private static void OnCodeChanged(
|
|
DependencyObject d,
|
|
DependencyPropertyChangedEventArgs e
|
|
)
|
|
{
|
|
ChannelCodeBuilder ccb = (ChannelCodeBuilder)d;
|
|
if (ccb?.CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO)
|
|
{
|
|
ccb.OnPropertyChanged("TestObject");
|
|
ccb.OnPropertyChanged("Position");
|
|
ccb.OnPropertyChanged("MainLocation");
|
|
ccb.OnPropertyChanged("FineLocation1");
|
|
ccb.OnPropertyChanged("FineLocation2");
|
|
ccb.OnPropertyChanged("FineLocation3");
|
|
ccb.OnPropertyChanged("Dimension");
|
|
ccb.OnPropertyChanged("Direction");
|
|
ccb.OnPropertyChanged("FilterClass");
|
|
}
|
|
ccb.UpdatePossibleChannels();//.OnPropertyChanged("PossibleChannels");
|
|
}
|
|
|
|
public string Code
|
|
{
|
|
get => (string) GetValue(CodeProperty);
|
|
set => SetValue(CodeProperty, value);
|
|
}
|
|
|
|
|
|
public static readonly DependencyProperty ChannelCodesFuncProperty =
|
|
DependencyProperty.Register(
|
|
"ChannelCodesFunc",
|
|
typeof(Func<IList<IChannelCode>>),
|
|
typeof(ChannelCodeBuilder),
|
|
new PropertyMetadata(null)
|
|
);
|
|
|
|
public Func<IList<IChannelCode>> ChannelCodesFunc
|
|
{
|
|
get => (Func<IList<IChannelCode>>) GetValue(ChannelCodesFuncProperty);
|
|
set => SetValue(ChannelCodesFuncProperty, value);
|
|
}
|
|
|
|
#region ISO builder properties
|
|
public static readonly DependencyProperty ShowISOStringBuilderProperty =
|
|
DependencyProperty.Register(
|
|
"ShowISOStringBuilder", // The name of the DependencyProperty
|
|
typeof(bool), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
true, // The default value of the DependencyProperty
|
|
OnShowISOCodeBuilderChanged
|
|
)
|
|
);
|
|
|
|
private static void OnShowISOCodeBuilderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
ChannelCodeBuilder ccb = (ChannelCodeBuilder)d;
|
|
if (!(bool)e.NewValue)
|
|
{
|
|
ccb._isoPopup = null;
|
|
}
|
|
}
|
|
|
|
public bool ShowISOStringBuilder
|
|
{
|
|
get => (bool)GetValue(ShowISOStringBuilderProperty);
|
|
set => SetValue(ShowISOStringBuilderProperty, value);
|
|
}
|
|
|
|
private ICommand _pasteCommand;
|
|
public ICommand PasteCommand
|
|
{
|
|
get => _pasteCommand;
|
|
set { _pasteCommand = value; OnPropertyChanged("PasteCommand"); }
|
|
}
|
|
|
|
private static readonly DependencyProperty PasteIdProperty =
|
|
DependencyProperty.Register(
|
|
"PasteId", // The name of the DependencyProperty
|
|
typeof(string), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
DTS.Common.Classes.Groups.GroupChannel.PASTE_ID // The default value of the DependencyProperty
|
|
)
|
|
);
|
|
public string PasteId
|
|
{
|
|
get => (string)GetValue(PasteIdProperty);
|
|
set => SetValue(PasteIdProperty, value);
|
|
}
|
|
|
|
private bool _registered = false;
|
|
private void RegisterCommands()
|
|
{
|
|
// FB13293: In order to add CCB to Channel Codes tile, we have to expand support for paste types
|
|
switch (PasteId)
|
|
{
|
|
case DTS.Common.Classes.ChannelCodes.ChannelCode.PASTE_ID:
|
|
PasteCommand = new DTS.Common.Classes.ChannelCodes.PasteCommandClass(PasteId);
|
|
break;
|
|
case DTS.Common.Classes.Groups.GroupChannel.PASTE_ID:
|
|
default:
|
|
PasteCommand = new DTS.Common.Classes.Groups.PasteCommandClass(PasteId);
|
|
break;
|
|
}
|
|
CommandManager.RegisterClassCommandBinding(GetType(),
|
|
new CommandBinding(PasteCommand, Paste));
|
|
_registered = true;
|
|
}
|
|
private void Paste(object sender, ExecutedRoutedEventArgs e)
|
|
{
|
|
}
|
|
public static readonly DependencyProperty UniqueISOCodesRequiredProperty =
|
|
DependencyProperty.Register(
|
|
"UniqueISOCodesRequired", // The name of the DependencyProperty
|
|
typeof(bool), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
false // The default value of the DependencyProperty
|
|
)
|
|
);
|
|
|
|
public bool UniqueISOCodesRequired
|
|
{
|
|
get => (bool)GetValue(UniqueISOCodesRequiredProperty);
|
|
set => SetValue(UniqueISOCodesRequiredProperty, value);
|
|
}
|
|
|
|
|
|
public static readonly DependencyProperty UseISOCodeFilterMappingProperty =
|
|
DependencyProperty.Register(
|
|
"UseISOCodeFilterMapping", // The name of the DependencyProperty
|
|
typeof(bool), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
false // The default value of the DependencyProperty
|
|
)
|
|
);
|
|
|
|
public bool UseISOCodeFilterMapping
|
|
{
|
|
get => (bool)GetValue(UseISOCodeFilterMappingProperty);
|
|
set => SetValue(UseISOCodeFilterMappingProperty, value);
|
|
}
|
|
|
|
private string ISOPartFilter(string value, uint length)
|
|
{
|
|
if (value != value.PadRight((int)length, '?') && UniqueISOCodesRequired)
|
|
{
|
|
value = value.PadRight((int)length, '?');
|
|
}
|
|
return value.ToUpper().Substring(0, (int)length);
|
|
}
|
|
|
|
private void SpliceIntoCode(string value, uint position)
|
|
{
|
|
//pad code if necessary
|
|
var paddedCode = Code.PadRight((int)position + value.Length, '?');
|
|
//splice in
|
|
var pre = paddedCode.Substring(0, (int) position);
|
|
var post = position + value.Length < paddedCode.Length
|
|
? paddedCode.Substring((int) position + value.Length)
|
|
: string.Empty;
|
|
Code = string.Concat(pre, value, post);
|
|
}
|
|
|
|
public string TestObject
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 0)
|
|
{
|
|
return Code.Substring(0, 1);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 1);
|
|
SpliceIntoCode(value, 0);
|
|
}
|
|
}
|
|
public string Position
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 1)
|
|
{
|
|
return Code.Substring(1, 1);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 1);
|
|
SpliceIntoCode(value, 1);
|
|
}
|
|
}
|
|
public string MainLocation
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 2)
|
|
{
|
|
return Code.PadRight(6, '?').Substring(2, 4);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 4);
|
|
SpliceIntoCode(value, 2);
|
|
}
|
|
}
|
|
|
|
public string FineLocation1
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 6)
|
|
{
|
|
return Code.PadRight(8, '?').Substring(6, 2);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 2);
|
|
SpliceIntoCode(value, 6);
|
|
}
|
|
}
|
|
|
|
public string FineLocation2
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 8)
|
|
{
|
|
return Code.PadRight(10, '?').Substring(8, 2);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 2);
|
|
SpliceIntoCode(value, 8);
|
|
}
|
|
}
|
|
|
|
public string FineLocation3
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 10)
|
|
{
|
|
return Code.PadRight(12, '?').Substring(10, 2);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 2);
|
|
SpliceIntoCode(value, 10);
|
|
}
|
|
}
|
|
|
|
public string Dimension
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 12)
|
|
{
|
|
return Code.PadRight(14, '?').Substring(12, 2);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 2);
|
|
SpliceIntoCode(value, 12);
|
|
}
|
|
}
|
|
|
|
public string Direction
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 14)
|
|
{
|
|
return Code.Substring(14, 1);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 1);
|
|
SpliceIntoCode(value, 14);
|
|
}
|
|
}
|
|
|
|
public string FilterClass
|
|
{
|
|
get
|
|
{
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && Code.Length > 15)
|
|
{
|
|
return Code.Substring(15, 1);
|
|
}
|
|
return "";
|
|
}
|
|
set
|
|
{
|
|
if (null == value) return;
|
|
value = ISOPartFilter(value, 1);
|
|
SpliceIntoCode(value, 15);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region ChannelCode select properties
|
|
|
|
public static readonly DependencyProperty AllChannelCodesProperty =
|
|
DependencyProperty.Register(
|
|
"AllChannelCodes", // The name of the DependencyProperty
|
|
typeof(IEnumerable<IChannelCode>), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
new List<IChannelCode>(), // The default value of the DependencyProperty
|
|
OnAllChannelCodesChanged
|
|
)
|
|
);
|
|
|
|
private static void OnAllChannelCodesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
ChannelCodeBuilder ccb = (ChannelCodeBuilder) d;
|
|
|
|
ccb?.UpdatePossibleChannels();
|
|
}
|
|
|
|
public IList<IChannelCode> AllChannelCodes
|
|
{
|
|
get => (IList<IChannelCode>)GetValue(AllChannelCodesProperty);
|
|
set => SetValue(AllChannelCodesProperty, value);
|
|
}
|
|
|
|
public void UpdatePossibleChannels(bool immediateUpdate = false)
|
|
{
|
|
if (null == _lookupPopup) return;
|
|
if (immediateUpdate)
|
|
{
|
|
_possiblesTimer?.Stop();
|
|
_lookupPopup.PossibleChannels = ChannelCodesFunc?.Invoke().Where(code => code.CodeType == CodeType).Select(code => new {code.Code, code.Name}).Where(m => Utils.Utils.IsLike(m.Code, Code)).ToList() ??
|
|
AllChannelCodes?.Where(code => code.CodeType == CodeType).Select(code => new {code.Code, code.Name}).Where(m => Utils.Utils.IsLike(m.Code, Code)).ToList() ??
|
|
Enumerable.Repeat(new {Code = "", Name = ""}, 0).ToList();
|
|
}
|
|
else
|
|
{
|
|
if (null == _possiblesTimer)
|
|
{
|
|
_possiblesTimer = new DispatcherTimer()
|
|
{
|
|
Interval = TimeSpan.FromMilliseconds(LookupHelperUpdateDelay),
|
|
IsEnabled = false
|
|
};
|
|
_possiblesTimer.Tick += (sender, args) =>
|
|
{
|
|
_possiblesTimer.IsEnabled = false;
|
|
if(_lookupPopup != null)
|
|
{
|
|
_lookupPopup.PossibleChannels = ChannelCodesFunc?.Invoke().Where(code => code.CodeType == CodeType).Select(code => new {code.Code, code.Name}).Where(m => Utils.Utils.IsLike(m.Code, Code)).ToList() ??
|
|
AllChannelCodes?.Where(code => code.CodeType == CodeType).Select(code => new {code.Code, code.Name}).Where(m => Utils.Utils.IsLike(m.Code, Code)).ToList() ??
|
|
Enumerable.Repeat(new {Code = "", Name = ""}, 0).ToList();
|
|
}
|
|
};
|
|
}
|
|
|
|
if (_possiblesTimer.IsEnabled)
|
|
{
|
|
_possiblesTimer.Stop();
|
|
}
|
|
_possiblesTimer.Start();
|
|
}
|
|
}
|
|
|
|
public static readonly DependencyProperty ShowChannelCodeLookupHelperProperty =
|
|
DependencyProperty.Register(
|
|
"ShowChannelCodeLookupHelper", // The name of the DependencyProperty
|
|
typeof(bool), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata( // OnHeaderTitleChanged will be called when HeaderTitle changes
|
|
true, // The default value of the DependencyProperty
|
|
OnShowChannelCodeLookupHelperChanged
|
|
)
|
|
);
|
|
|
|
private static void OnShowChannelCodeLookupHelperChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
ChannelCodeBuilder ccb = (ChannelCodeBuilder)d;
|
|
if (!(bool) e.NewValue)
|
|
{
|
|
ccb._lookupPopup = null;
|
|
}
|
|
}
|
|
|
|
public bool ShowChannelCodeLookupHelper
|
|
{
|
|
get => (bool)GetValue(ShowChannelCodeLookupHelperProperty);
|
|
set => SetValue(ShowChannelCodeLookupHelperProperty, value);
|
|
}
|
|
|
|
public static readonly DependencyProperty LookupHelperUpdateDelayProperty =
|
|
DependencyProperty.Register(
|
|
"LookupHelperUpdateDelay", // The name of the DependencyProperty
|
|
typeof(int), // The type of the DependencyProperty
|
|
typeof(ChannelCodeBuilder), // The type of the owner of the DependencyProperty
|
|
new PropertyMetadata(
|
|
1000,
|
|
LookupHelperUpdateDelayChanged,
|
|
CoerceLookupHelperUpdateDelay
|
|
)
|
|
);
|
|
|
|
private static object CoerceLookupHelperUpdateDelay(DependencyObject d, object baseValue)
|
|
{
|
|
return (int) baseValue < 0 ? 0 : (int) baseValue;
|
|
}
|
|
|
|
private static void LookupHelperUpdateDelayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
{
|
|
if (!(d is ChannelCodeBuilder ccb)) return;
|
|
ccb._possiblesTimer?.Stop();
|
|
ccb._possiblesTimer = null;
|
|
}
|
|
|
|
public int LookupHelperUpdateDelay
|
|
{
|
|
get => (int) GetValue(LookupHelperUpdateDelayProperty);
|
|
set => SetValue(LookupHelperUpdateDelayProperty, value);
|
|
}
|
|
#endregion
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
public delegate void ChannelCodeSelectedEventHandler(object sender, string code, string name, ChannelEnumsAndConstants.ChannelCodeType codeType);
|
|
|
|
public event ChannelCodeSelectedEventHandler ChannelCodeSelected;
|
|
|
|
public void OnPropertyChanged(string propertyName)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
|
|
private void MainEditBox_OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
|
|
{
|
|
if (sender.Equals(MainEditBox))
|
|
{
|
|
MultiBinding lookupMB = null, isoMB = null;
|
|
if (ShowChannelCodeLookupHelper && null == _lookupPopup)
|
|
{
|
|
_lookupPopup = new LookupPopup()
|
|
{
|
|
PlacementTarget = MainEditBox,
|
|
HorizontalOffset = 10,
|
|
Placement = PlacementMode.Custom,
|
|
CustomPopupPlacementCallback = (size, targetSize, offset) =>
|
|
{
|
|
CustomPopupPlacement bottom = new CustomPopupPlacement(new Point(0, targetSize.Height), PopupPrimaryAxis.Horizontal);
|
|
CustomPopupPlacement left = new CustomPopupPlacement(new Point(-size.Width - offset.X, 0), PopupPrimaryAxis.Vertical);
|
|
var topoffset = ShowISOStringBuilder && CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO ? 48 : 0;
|
|
CustomPopupPlacement top = new CustomPopupPlacement(new Point(0, -size.Height - topoffset), PopupPrimaryAxis.Horizontal);
|
|
|
|
return new CustomPopupPlacement[] { bottom, left, top };
|
|
},
|
|
};
|
|
_lookupPopup.ChannelCodeSelected += LookupPopupOnChannelCodeSelected;
|
|
lookupMB = new MultiBinding();
|
|
lookupMB.Converter = new BooleanOrMultiConverter();
|
|
lookupMB.Bindings.Add(new Binding("IsKeyboardFocused") { Source = MainEditBox, Mode=BindingMode.OneWay });
|
|
lookupMB.Bindings.Add(new Binding("IsKeyboardFocusWithin") { Source = _lookupPopup, Mode = BindingMode.OneWay });
|
|
lookupMB.NotifyOnSourceUpdated = true;
|
|
}
|
|
if (CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO && ShowISOStringBuilder &&
|
|
null == _isoPopup)
|
|
{
|
|
_isoPopup = new ISOPopup()
|
|
{
|
|
PlacementTarget = MainEditBox,
|
|
Placement = PlacementMode.Top,
|
|
HorizontalOffset = 10
|
|
};
|
|
isoMB = new MultiBinding();
|
|
isoMB.Converter = new BooleanOrMultiConverter();
|
|
isoMB.Bindings.Add(new Binding("IsKeyboardFocused") { Source = MainEditBox, Mode = BindingMode.OneWay });
|
|
isoMB.Bindings.Add(new Binding("IsMouseOver") { Source = _isoPopup, Mode = BindingMode.OneWay });
|
|
isoMB.Bindings.Add(new Binding("IsKeyboardFocusWithin") { Source = _isoPopup, Mode = BindingMode.OneWay });
|
|
isoMB.NotifyOnSourceUpdated = true;
|
|
}
|
|
if (null != lookupMB)
|
|
{
|
|
if (null != _isoPopup)
|
|
{
|
|
lookupMB.Bindings.Add(new Binding("IsMouseOver") {Source = _isoPopup, Mode = BindingMode.OneWay});
|
|
lookupMB.Bindings.Add(new Binding("IsKeyboardFocusWithin") {Source = _isoPopup, Mode = BindingMode.OneWay});
|
|
}
|
|
_lookupPopup.SetBinding(Popup.IsOpenProperty, lookupMB);
|
|
}
|
|
if (null != _lookupPopup)
|
|
{
|
|
UpdatePossibleChannels(true);
|
|
}
|
|
if (null != isoMB)
|
|
{
|
|
if (null != _lookupPopup)
|
|
{
|
|
isoMB.Bindings.Add(new Binding("IsKeyboardFocusWithin") {Source = _lookupPopup, Mode = BindingMode.OneWay});
|
|
}
|
|
_isoPopup.SetBinding(Popup.IsOpenProperty, isoMB);
|
|
}
|
|
}
|
|
if(sender is TextBox tb)
|
|
{
|
|
tb.SelectAll();
|
|
}
|
|
}
|
|
|
|
private void LookupPopupOnChannelCodeSelected(object sender, string code, string name)
|
|
{
|
|
Code = code;
|
|
ChannelCodeSelected?.Invoke(this, code, name, CodeType);
|
|
Keyboard.ClearFocus();
|
|
}
|
|
|
|
private void MainEditBox_OnPreviewKeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (CodeType != ChannelEnumsAndConstants.ChannelCodeType.ISO) { return; }
|
|
bool isAlpha = (e.Key >= Key.A && e.Key <= Key.Z);
|
|
bool isNumPadNumeric = (e.Key >= Key.NumPad0 && e.Key <= Key.NumPad9);
|
|
bool isNumeric = (e.Key >= Key.D0 && e.Key <= Key.D9);
|
|
bool isControl = e.Key == Key.Enter || e.Key == Key.Return || e.Key == Key.Tab || e.Key == Key.OemBackTab ||
|
|
e.Key == Key.Delete || e.Key == Key.Back || e.Key == Key.Home || e.Key == Key.End;
|
|
bool isDirection = e.Key == Key.Up || e.Key == Key.Down || e.Key == Key.Left || e.Key == Key.Right;
|
|
e.Handled = !(e.Key == Key.OemQuestion || isAlpha || isNumPadNumeric || isNumeric || isControl || isDirection);
|
|
}
|
|
|
|
private void MainEditBox_OnLostFocus(object sender, RoutedEventArgs e)
|
|
{
|
|
if (!IsKeyboardFocusWithin && (!_isoPopup?.IsKeyboardFocusWithin ?? true) && (!_lookupPopup?.IsKeyboardFocusWithin ?? true))
|
|
{
|
|
//now that we've lost focus, we can coerce the code
|
|
Code = Code;
|
|
}
|
|
}
|
|
|
|
private void ChannelCodeBuilder_OnLoaded(object sender, RoutedEventArgs e)
|
|
{
|
|
Window w = Window.GetWindow(this);
|
|
if (w != null)
|
|
{
|
|
w.LocationChanged += delegate
|
|
{
|
|
if (IsKeyboardFocusWithin || (_isoPopup?.IsKeyboardFocusWithin ?? false))
|
|
{
|
|
Keyboard.ClearFocus();
|
|
}
|
|
};
|
|
}
|
|
var scrollParent = Utils.Utils.FindParent<ScrollViewer>(this);
|
|
if (scrollParent != null)
|
|
{
|
|
scrollParent.ScrollChanged += delegate(object o, ScrollChangedEventArgs args)
|
|
{
|
|
if ((IsKeyboardFocusWithin || (_isoPopup?.IsKeyboardFocusWithin ?? false)) &&
|
|
(args.HorizontalChange != 0 || args.VerticalChange != 0))
|
|
{
|
|
Keyboard.ClearFocus();
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
private void TextBoxSourceUpdated(object sender, DataTransferEventArgs e)
|
|
{
|
|
var eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
|
|
eventAggregator.GetEvent<PageModifiedEvent>()
|
|
.Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, null));
|
|
eventAggregator.GetEvent<GroupUpdatedEvent>()
|
|
.Publish(new GroupUpdatedEventArgs(null, GroupUpdatedEventArgs.Status.AssignmentsMade));
|
|
}
|
|
|
|
private void MainEditBox_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
|
{
|
|
if (sender is TextBox tb)
|
|
{
|
|
tb.SelectAll();
|
|
}
|
|
}
|
|
|
|
public event TextChangedEventHandler TextChanged;
|
|
private void MainEditBox_OnTextChanged(object sender, TextChangedEventArgs e)
|
|
{
|
|
TextChanged?.Invoke(this, e);
|
|
}
|
|
|
|
//FB 25725 ISO selection has been changed
|
|
public event RoutedEventHandler SelectionChanged;
|
|
private void MainEditBox_SelectionChanged(object sender, RoutedEventArgs e)
|
|
{
|
|
SelectionChanged?.Invoke(this, e);
|
|
}
|
|
}
|
|
|
|
internal class CodeTypeToMaxLengthConverter : IValueConverter
|
|
{
|
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
{
|
|
if (value is ChannelEnumsAndConstants.ChannelCodeType.ISO)
|
|
{
|
|
return ChannelEnumsAndConstants.ISO_CODE_LENGTH;
|
|
}
|
|
return ChannelEnumsAndConstants.USER_CODE_LENGTH;
|
|
}
|
|
|
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
internal class CodeTypeToCharacterCasingConverter : IValueConverter
|
|
{
|
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
{
|
|
if (value is ChannelEnumsAndConstants.ChannelCodeType.ISO)
|
|
{
|
|
return CharacterCasing.Upper;
|
|
}
|
|
return CharacterCasing.Normal;
|
|
}
|
|
|
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public class UpdatePropertySourceWhenEnterPressedExtension : MarkupExtension
|
|
{
|
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
|
{
|
|
return new DelegateCommand<TextBox>(textbox => textbox.GetBindingExpression(TextBox.TextProperty)?.UpdateSource());
|
|
}
|
|
}
|
|
}
|