Ну, я, наконец, выяснил, как сделать это сам, на тот случай, если кто-то еще захочет использовать тот же метод, что и я. Вот как вы обновляете свое представление в памяти:
public interface INewViewLocationResultProvider
{
bool UseCachedView { get; set; }
ViewLocationResult GetNewerVersion(string viewName, NancyContext context);
void UpdateCachedView(IDictionary<string, ViewLocationResult> replacements);
}
public class ConcurrentNewViewLocationResultProvider : INewViewLocationResultProvider
{
private Dictionary<string, ViewLocationResult> _cachedViewLocationResults;
private readonly object _cacheLock = new object();
public bool UseCachedView { get; set; }
public ConcurrentNewViewLocationResultProvider()
{
lock (_cacheLock)
{
if(_cachedViewLocationResults == null)_cachedViewLocationResults = new Dictionary<string, ViewLocationResult>();
}
}
public ViewLocationResult GetNewerVersion(string viewName, NancyContext context)
{
if (UseCachedView)
{
if (Monitor.TryEnter(_cacheLock, TimeSpan.FromMilliseconds(20)))
{
try
{
if (_cachedViewLocationResults != null && _cachedViewLocationResults.ContainsKey(viewName))
{
return _cachedViewLocationResults[viewName];
}
}
finally
{
Monitor.Exit(_cacheLock);
}
}
}
return null;
}
public void UpdateCachedView(IDictionary<string, ViewLocationResult> replacements)
{
lock (_cacheLock)
{
if(_cachedViewLocationResults == null)_cachedViewLocationResults = new Dictionary<string, ViewLocationResult>();
foreach (var replace in replacements)
{
if (_cachedViewLocationResults.ContainsKey(replace.Key))
{
_cachedViewLocationResults[replace.Key] = replace.Value;
}
else
{
_cachedViewLocationResults.Add(replace.Key,replace.Value);
}
}
}
}
}
container.Register<INewViewLocationResultProvider, ConcurrentNewViewLocationResultProvider>().AsSingleton();
public class OneTimeUsedViewLocationResult : ViewLocationResult
{
private bool _used = false;
public OneTimeUsedViewLocationResult(string location, string name, string extension, Func<TextReader> contents)
: base(location, name, extension, contents)
{
}
public override bool IsStale()
{
if (_used) return false;
_used = true;
return true;
}
}
public class CachedViewLocator : IViewLocator
{
private readonly INewViewLocationResultProvider _newVersion;
private readonly DefaultViewLocator _fallbackViewLocator;
public CachedViewLocator(IViewLocationProvider viewLocationProvider, IEnumerable<IViewEngine> viewEngines, INewViewLocationResultProvider newVersion)
{
_fallbackViewLocator = new DefaultViewLocator(viewLocationProvider, viewEngines);
_newVersion = newVersion;
}
public ViewLocationResult LocateView(string viewName, NancyContext context)
{
if (_newVersion.UseCachedView)
{
var result = _newVersion.GetNewerVersion(viewName, context);
if (result != null) return result;
}
return _fallbackViewLocator.LocateView(viewName, context);
}
public IEnumerable<ViewLocationResult> GetAllCurrentlyDiscoveredViews()
{
return _fallbackViewLocator.GetAllCurrentlyDiscoveredViews();
}
}
}
[1119 ] protected override NancyInternalConfiguration InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides
(
nic =>
{
nic.ViewLocationProvider = typeof(ResourceViewLocationProvider);//use this or your equivalent
nic.ViewLocator = typeof(CachedViewLocator);
}
);
}
}
public class YourModule : NancyModule
{
public YourModule(INewViewLocationResultProvider provider)
{
Get["/yourupdateinterface"] = param =>
{
if(!provider.UseCachedView) return HttpStatusCode.BadRequest;//in case you turn off the hot update
//you can serialize your OneTimeUsedViewLocationResult with Newtonsoft.Json and store those views in any database, like mysql, redis, and load them here
//data mock up
TextReader tr = new StringReader(Resources.TextMain);
var vlr = new OneTimeUsedViewLocationResult("","index","cshtml",()=>tr);
var dir = new Dictionary<string, ViewLocationResult> {{"index",vlr}};
//mock up ends
provider.UpdateCachedView(dir);
return HttpStatusCode.OK;
}
}
}
Примечание: Приведенный выше код не решает вручную сопоставить все элементы Location, Name, Extension для элементов ViewLocationResult в моем вопросе, но, поскольку я в конечном итоге создаю редактор представлений для моих колледжей, чтобы загружать их представления, мне не нужно его решать больше.
1) создайте пользовательское управление updatepanel (скопировать/вставить от SingingEels)
2) используйте это пользовательское управление updatepanel с атрибутом RenderedElement="TBODY"
3) вложите свою таблицу следующим образом:
<TABLE>
<TR>
<TD>outside updatepanel</TD>
</TR>
<SingingEels:SemanticUpdatePanel ID="myUpdatePanel" runat="server" RenderedElement="TBODY">
<ContentTemplate>
<TR>
<TD>inside updatepanel - 1th row</TD>
</TR>
<TR>
<TD>inside updatepanel - 2nd row</TD>
</TR>
<TR>
<TD>inside updatepanel - last row</TD>
</TR>
</ContentTemplate>
</SingingEels:SemanticUpdatePanel>
<TR>
<TD>outside updatepanel</TD>
</TR>
</TABLE>
Я полагаю, что это происходит из-за того, как Вы - вложение панель Update. Если Вы изменяете панель обновления, чтобы быть ребенком td, а не таблицы:
<tr>
<td>
Some Field:
</td>
<td>
<asp:UpdatePanel ID="uxUpdatePanel" runat="server" RenderMode="Inline" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="ddSomeField" runat="server" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ddCheckbox" EventName="CheckedChanged" />
</Triggers>
</asp:UpdatePanel>
</td>
</tr>
Вы должны быть все согласованы.
Вы сделали источник представления, чтобы подтвердить, что он на самом деле представляет его в том месте в самом HTML? Браузеры будут иногда представлять теги за пределами таблицы, если таблица будет уродлива. Это, может казаться, определяется правильно в самом HTML, но недостающий закрывающий тэг и т.д. может заставить это представлять тот путь.
Когда Панель Обновления отправляет назад на сервер, она отправляет все назад (включая состояние отображения). Почему не только делают некоторый простой JavaScript? Это было бы намного более эффективно.