1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
|
//------------------------------------------------------------------------------
// <copyright file="EntityDataSourceConfigureObjectContext.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner [....]
// @backupOwner [....]
//
// Manages the properties that can be set on the first page of the wizard
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Web.UI.Design.WebControls.Util;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Forms;
namespace System.Web.UI.Design.WebControls
{
// delegate for event handler to process notifications when the DefaultContainerName is changed
internal delegate void EntityDataSourceContainerChangedEventHandler(object sender, EntityDataSourceContainerNameItem newContainerName);
internal class EntityDataSourceConfigureObjectContext
{
#region Private readonly fields
private readonly EntityDataSourceConfigureObjectContextPanel _panel;
private readonly EntityDataSourceDesignerHelper _helper;
#endregion
#region Private writeable fields
private EntityDataSourceContainerChangedEventHandler _containerNameChanged; // used to notify the DataSelection panel that a change has been made
#endregion
#region Private fields for temporary storage of property values
private EntityConnectionStringBuilderItem _selectedConnectionStringBuilder;
private bool _connectionStringHasValue;
private List<EntityConnectionStringBuilderItem> _namedConnections;
private List<EntityDataSourceContainerNameItem> _containerNames;
private EntityDataSourceContainerNameItem _selectedContainerName;
private readonly EntityDataSourceState _entityDataSourceState;
private readonly EntityDataSourceWizardForm _wizardForm;
#endregion
#region Constructors
internal EntityDataSourceConfigureObjectContext(EntityDataSourceConfigureObjectContextPanel panel, EntityDataSourceWizardForm wizardForm, EntityDataSourceDesignerHelper helper, EntityDataSourceState entityDataSourceState)
{
try
{
Cursor.Current = Cursors.WaitCursor;
_panel = panel;
_helper = helper;
// Explicitly load metadata here to ensure that we get the latest changes in the project
_helper.ReloadResources();
_panel.Register(this);
_wizardForm = wizardForm;
_entityDataSourceState = entityDataSourceState;
}
finally
{
Cursor.Current = Cursors.Default;
}
}
#endregion
#region Events
internal event EntityDataSourceContainerChangedEventHandler ContainerNameChanged
{
add
{
_containerNameChanged += value;
}
remove
{
_containerNameChanged -= value;
}
}
// Fires the event to notify that a container has been chosen from the list
private void OnContainerNameChanged(EntityDataSourceContainerNameItem selectedContainerName)
{
if (_containerNameChanged != null)
{
_containerNameChanged(this, selectedContainerName);
}
}
#endregion
#region Methods to manage temporary state and wizard contents
// Save current wizard settings back to the EntityDataSourceState
internal void SaveState()
{
SaveConnectionString();
SaveContainerName();
}
// Load the initial state of the wizard
internal void LoadState()
{
LoadConnectionStrings();
LoadContainerNames(_entityDataSourceState.DefaultContainerName, true /*initialLoad*/);
}
#region DefaultContainerName
/// <summary>
/// Populates the DefaultContainerName ComboBox with all of the EntityContainers in the loaded metadata
/// If the specified DefaultContainerName property on the data source control is not empty and 'initialLoad' is true,
/// it is added to the list and selected in the control
/// </summary>
/// <param name="containerName">The container name to find</param>
/// <param name="initialLoad">if true, this is the initial load so the container name is added to the list if it is not found.</param>
private void LoadContainerNames(string containerName, bool initialLoad)
{
// Get a list of EntityContainers from the metadata in the connection string
_containerNames = _helper.GetContainerNames(false /*sortResults*/);
// Try to find the specified container in list
_selectedContainerName = FindContainerName(containerName, initialLoad /*addIfNotFound*/);
// Sort the list now, after we may have added a new entry above
_containerNames.Sort();
// Update the controls
_panel.SetContainerNames(_containerNames);
_panel.SetSelectedContainerName(_selectedContainerName, initialLoad /*initialLoad*/);
}
/// <summary>
/// Find the current container in the current list of containers
/// </summary>
/// <param name="containerName">The container name to find</param>
/// <param name="addIfNotFound">if true, adds the container name to the list if it is not found.</param>
/// <returns></returns>
private EntityDataSourceContainerNameItem FindContainerName(string containerName, bool addIfNotFound)
{
Debug.Assert(_containerNames != null, "_containerNames have already been initialized and should not be null");
if (!String.IsNullOrEmpty(containerName))
{
EntityDataSourceContainerNameItem containerToSelect = null;
foreach (EntityDataSourceContainerNameItem containerNameItem in _containerNames)
{
// Ignore case here when searching the list for a matching item, but set the temporary state property to the
// correctly-cased version from metadata so that if the user clicks Finish, the correct one will be saved. This
// allows some flexibility the designer without preserving an incorrectly-cased value that could cause errors at runtime.
if (String.Equals(containerName, containerNameItem.EntityContainerName, StringComparison.OrdinalIgnoreCase))
{
containerToSelect = containerNameItem;
}
}
// didn't find a matching container, so just create a placeholder for one using the specified name and add it to the list
if (containerToSelect == null && addIfNotFound)
{
containerToSelect = new EntityDataSourceContainerNameItem(containerName);
_containerNames.Add(containerToSelect);
}
Debug.Assert(addIfNotFound == false || containerToSelect != null, "expected a non-null EntityDataSourceContainerNameItem");
return containerToSelect;
}
return null;
}
// Set the container name in temporary storage, update the connection string, and fire the event so the EntitySet will know there has been a change
internal void SelectContainerName(EntityDataSourceContainerNameItem selectedContainer)
{
_selectedContainerName = selectedContainer;
UpdateWizardState();
OnContainerNameChanged(_selectedContainerName);
}
private void SaveContainerName()
{
Debug.Assert(_selectedContainerName != null, "wizard data should not be saved if container name is empty");
_entityDataSourceState.DefaultContainerName = _selectedContainerName.EntityContainerName;
}
#endregion
#region ConnectionString
// Populates the NamedConnection ComboBox with all of the EntityClient connections from the web.config.
// If the specified connectionString is a named connection (if it contains "name=ConnectionName"), it is added to the list and selected.
// If the specified connectionString is not a named connection, the plain connection string option is selected and populated with the specified value.
private void LoadConnectionStrings()
{
// Get a list of all named EntityClient connections in the web.config
_namedConnections = _helper.GetNamedEntityClientConnections(false /*sortResults*/);
EntityConnectionStringBuilderItem connStrBuilderItem = _helper.GetEntityConnectionStringBuilderItem(_entityDataSourceState.ConnectionString);
Debug.Assert(connStrBuilderItem != null, "expected GetEntityConnectionStringBuilder to always return non-null");
if (connStrBuilderItem.IsNamedConnection)
{
// Try to find the specified connection in the list or add it
connStrBuilderItem = FindCurrentNamedConnection(connStrBuilderItem);
Debug.Assert(connStrBuilderItem != null, "expected a non-null connStrBuilderItem for the named connection because it should have added it if it didn't exist");
}
// Sort results now, after we may have added a new item above
_namedConnections.Sort();
SelectConnectionStringBuilder(connStrBuilderItem, false /*resetContainer*/);
// Update the controls
_panel.SetNamedConnections(_namedConnections);
_panel.SetConnectionString(_selectedConnectionStringBuilder);
}
// Find the current named connection in the list of connections
// The returned item may refer to the same connection as the specified item, but it will be the actual reference from the list
private EntityConnectionStringBuilderItem FindCurrentNamedConnection(EntityConnectionStringBuilderItem newBuilderItem)
{
Debug.Assert(_namedConnections != null, "_namedConnections should have already been initialized and should not be null");
Debug.Assert(newBuilderItem != null && newBuilderItem.IsNamedConnection, "expected non-null newBuilderItem");
foreach (EntityConnectionStringBuilderItem namedConnectionItem in _namedConnections)
{
if (((IComparable<EntityConnectionStringBuilderItem>)newBuilderItem).CompareTo(namedConnectionItem) == 0)
{
// returning the one that was actually in the list, so we can select it in the control
return namedConnectionItem;
}
}
// didn't find it in the list, so add it
_namedConnections.Add(newBuilderItem);
return newBuilderItem;
}
internal EntityConnectionStringBuilderItem GetEntityConnectionStringBuilderItem(string connectionString)
{
return _helper.GetEntityConnectionStringBuilderItem(connectionString);
}
// Set the connection string in temporary storage
// Returns true if the metadata was successfully loaded for the specified connections
internal bool SelectConnectionStringBuilder(EntityConnectionStringBuilderItem selectedConnection, bool resetContainer)
{
_selectedConnectionStringBuilder = selectedConnection;
bool metadataLoaded = false;
if (selectedConnection != null)
{
if (selectedConnection.EntityConnectionStringBuilder != null)
{
metadataLoaded = _helper.LoadMetadata(selectedConnection.EntityConnectionStringBuilder);
}
else
{
// Since we don't have a valid connection string builder, we don't have enough information to load metadata.
// Clear any existing metadata so we don't see an old item collection on any subsequent calls that access it.
// Don't need to display an error here because that was handled by the caller who created the builder item
_helper.ClearMetadata();
}
}
// Reset the list of containers if requested and set the ComboBox to have no selection.
// In some cases the containers do not need to be reset because the caller wants to delay that until a later event or wants to preserve a specific value
if (resetContainer)
{
string defaultContainerName = _selectedConnectionStringBuilder.EntityConnectionStringBuilder == null ? null : _selectedConnectionStringBuilder.EntityConnectionStringBuilder.Name;
LoadContainerNames(defaultContainerName, false /*initialLoad*/);
}
// Update the controls
UpdateWizardState();
return metadataLoaded;
}
// Set a flag indicating that the connection string textbox or named connection dropdown has a value
// This value has not be verified at this point, or may not even be complete, so we don't want to validate it yet and turn it into a builder
internal void SelectConnectionStringHasValue(bool connectionStringHasValue)
{
_connectionStringHasValue = connectionStringHasValue;
// Update the controls
UpdateWizardState();
}
private void SaveConnectionString()
{
Debug.Assert(_selectedConnectionStringBuilder != null, "wizard data should not be saved if connection string is empty");
_entityDataSourceState.ConnectionString = _selectedConnectionStringBuilder.ConnectionString;
}
#endregion
#endregion
#region Wizard button state management
// Update the state of the wizard buttons
internal void UpdateWizardState()
{
_wizardForm.SetCanNext(this.CanEnableNext);
// Finish button should never be enabled at this stage
_wizardForm.SetCanFinish(false);
}
// Next button can only be enabled when the following are true:
// (1) DefaultContainerName has a value
// (2) Either a named connection is selected or the connection string textbox has a value
internal bool CanEnableNext
{
get
{
return _selectedContainerName != null && _connectionStringHasValue;
}
}
#endregion
}
}
|