У меня есть небольшая головоломка, которую я пытаюсь решить, и я не уверен, как ее решить ...
Приложение WPF, основанное на подходе MVVM ...
У меня естьКласс SubstitutionionDataSet, который наследуется от DataSet и определяет дополнительную коллекцию:
namespace Lib
{
public class SubstitutionDataSet : DataSet
{
public SubstitutionDataSet()
{
TableNames = new ObservableCollection<SubstitutionDataTable>();
Tables.CollectionChanging += DataTablesCollectionChanging;
}
public ObservableCollection<SubstitutionDataTable> TableNames { get; set; }
private void DataTablesCollectionChanging(object sender, CollectionChangeEventArgs e)
{
var actionTable = (DataTable) e.Element;
if (e.Action == CollectionChangeAction.Add)
{
actionTable.Columns.CollectionChanged += DataColumnCollectionChanged;
TableNames.Add(new SubstitutionDataTable { Name = actionTable.TableName });
}
else if (e.Action == CollectionChangeAction.Remove)
{
actionTable.Columns.CollectionChanged -= DataColumnCollectionChanged;
TableNames.Remove(TableNames.First(tn => tn.Name == actionTable.TableName));
}
}
private void DataColumnCollectionChanged(object sender, CollectionChangeEventArgs e)
{
var actionColumn = (DataColumn) e.Element;
var hostTable = (DataTable) actionColumn.Table;
var hostSubsitutionTable = TableNames.First(tn => tn.Name == hostTable.TableName);
if (e.Action == CollectionChangeAction.Add)
{
hostSubsitutionTable.ColumnNames.Add(actionColumn.ColumnName);
}
else if (e.Action == CollectionChangeAction.Remove)
{
hostSubsitutionTable.ColumnNames.Remove(hostSubsitutionTable.ColumnNames.First(cn => cn == actionColumn.ColumnName));
}
}
}
}
С таблицей SubstitutionDataTable, определенной ниже:
namespace Lib
{
public sealed class SubstitutionDataTable: INotifyPropertyChanged
{
private string _name;
/// <summary>
/// The <see cref="Name" /> property's name.
/// </summary>
private const string NamePropertyName = "Name";
public SubstitutionDataTable()
{
ColumnNames = new ObservableCollection<string>();
}
/// <summary>
/// Gets the Name property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string Name
{
get
{
return _name;
}
set
{
if (_name == value)
{
return;
}
_name = value;
RaisePropertyChanged(NamePropertyName);
}
}
public ObservableCollection<string> ColumnNames { get; set; }
#region Implementation of INotifyPropertyChanged
/// <summary>
/// A property has changed - update bindings
/// </summary>
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
... Теперь это суть головоломки..
Приведенные выше классы используются для определения новой таблицы данных в наборе данных, а также для добавления столбцов, строк и времени выполнения.У меня есть другой класс, который позволяет настраивать процесс запутывания, часть конфигурации позволяет выбрать DataTable и DataColumn из SubstituionDataSet, определенного выше.
namespace Lib
{
public class ObfuscationParams : INotifyPropertyChanged
{
private string _dataColumn;
private string _dataTable;
private char _maskCharacter;
private int _numberCharacters;
/// <summary>
/// The <see cref="MaskCharacter" /> property's name.
/// </summary>
private const string MaskCharacterPropertyName = "MaskCharacter";
/// <summary>
/// The <see cref="DataColumn" /> property's name.
/// </summary>
private const string DataColumnPropertyName = "DataColumn";
/// <summary>
/// The <see cref="DataTable" /> property's name.
/// </summary>
private const string DataTablePropertyName = "DataTable";
# region Mask Obfuscation Properties
/// <summary>
/// Defines whether whitespace is to be trimmed or not for a Mask obfuscation.
/// </summary>
public bool IsWhiteSpaceTrimmed { get; set; }
/// <summary>
/// Defines the mask character to be used for a Mask obfuscation.
/// </summary>
public char MaskCharacter
{
get { return _maskCharacter; }
set
{
if (_maskCharacter == value)
return;
_maskCharacter = value;
RaisePropertyChanged(MaskCharacterPropertyName);
}
}
/// <summary>
/// Defines the number of masking characters to apply.
/// </summary>
public int NumberCharacters
{
get { return _numberCharacters; }
set { _numberCharacters = value < 1 ? 1 : (value > 16 ? 16 : value); }
}
/// <summary>
/// Defines the mask position for a Mask obfuscation.
/// </summary>
public MaskPosition MaskPosition { get; set; }
#endregion
# region Substitute Obfuscation Properties
/// <summary>
/// Defines which datacolumn is to be used for a Substitution obfuscation.
/// </summary>
public string DataColumn
{
get { return _dataColumn; }
set
{
if (_dataColumn == value)
return;
_dataColumn = value;
RaisePropertyChanged(DataColumnPropertyName);
}
}
/// <summary>
/// Defines which datatable is to be used for a substitition obfuscation.
/// </summary>
public string DataTable
{
get { return _dataTable; }
set
{
if (_dataTable == value)
return;
_dataTable = value;
RaisePropertyChanged(DataTablePropertyName);
_dataTable = value;
}
}
#endregion
#region Implementation of INotifyPropertyChanged
/// <summary>
/// A property has changed - update bindings
/// </summary>
[field: NonSerialized]
public virtual event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
У меня есть работающая конфигурация, и я могу настроить несколько запутыванийи затем сериализовать конфигурацию на диск.
Когда я десериализую, я обнаружил, что привязки в графическом интерфейсе не показывают правильные выборы DataTable и DataColumn, DataTable просто показывает полное имя объекта.
В настоящее время я просто пытаюсь заставить работать привязку DataTable - я знаю, что мне нужно переработать привязку DataColumn.
Графический интерфейс пользователя (usercontrol) определяется следующим образом:
<UserControl xmlns:igEditors="http://infragistics.com/Editors" x:Class="SubstitutionOptions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="421" d:DesignWidth="395">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="23" />
<RowDefinition Height="23" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0"
Grid.Column="0"
Text="Dataset" />
<igEditors:XamComboEditor Grid.Row="0"
Grid.Column="2"
Name="tablesComboBox"
NullText="select a dataset..."
ItemsSource="{Binding DataContext.Project.SubstitutionDataSet.TableNames, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
DisplayMemberPath="Name"
SelectedItem="{Binding DataContext.SelectedFieldSubstitutionDataTable, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="Column" />
<igEditors:XamComboEditor Grid.Row="1"
Grid.Column="2"
NullText="select a column..."
ItemsSource="{Binding DataContext.SelectedFieldSubstitutionDataTable.ColumnNames, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
SelectedItem="{Binding DataColumn, Mode=TwoWay}"/>
</Grid>
</UserControl>
Я надеюсь,Я объяснил проблему достаточно.Кто-нибудь получил какие-либо идеи о том, как я могу заставить его работать, используя текущий дизайн, или изменить подход к достижению того, что мне нужно?