WebPart Properties Persistence - sharepoint

I've tried to Develop a Web Part that displays the text entered in the Property of a custom EditorPart,
but i have problem with the Properties persistence When i click on OK or Save and open the WebPart Properties the values of the properties revert to default,
same thing when i save the Page after editing the WebPart Properties and clicking on Apply OR OK buttons. Below is the code i implemented :
using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;
using System.Collections.Generic;
using Microsoft.SharePoint.Administration;
namespace SH_Perso.WebPartPerso
{
[ToolboxItemAttribute(false)]
public class WebPartPerso : System.Web.UI.WebControls.WebParts.WebPart
{
[WebBrowsable(false), Personalizable(PersonalizationScope.User), DefaultValue("PERSO")]
public string MyPortalChoice { get; set; }
[WebBrowsable(false), Personalizable(PersonalizationScope.User), DefaultValue("Documents")]
public string MyAppChoice { get; set; }
[WebBrowsable(false), Personalizable(PersonalizationScope.User), DefaultValue("Tous les éléments")]
public string MyViewChoice { get; set; }
protected override void CreateChildControls()
{
base.CreateChildControls();
Controls.Add(new LiteralControl("PORTAIL :" + MyPortalChoice + "<br/> APPLICATION : " + MyAppChoice + "<br/> VUE : " + MyViewChoice));
}
/// <summary>
/// Creates custom editor parts here and assigns a unique id to each part
/// </summary>
/// <returns>All custom editor parts used by this web part</returns>
public override EditorPartCollection CreateEditorParts()
{
PEditorPart editorPart = new PEditorPart();
editorPart.Title = "Choix de la liste à afficher";
editorPart.ID = ID + "_editorPart";
EditorPartCollection editors = new EditorPartCollection(base.CreateEditorParts(), new EditorPart[] { editorPart });
return editors;
}
public override object WebBrowsableObject
{
get
{
return(this);
}
}
}
}
// THE EDITOR PART CLASS
class PEditorPart : EditorPart
{
public TextBox PortalChoices;
public TextBox AppChoices;
public TextBox ListViews;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
PortalChoices = new TextBox();
AppChoices = new TextBox();
ListViews = new TextBox();
}
protected override void CreateChildControls()
{
Controls.Add(new LiteralControl("<div> <span style='font-weight:bold;'>Portail</span> "));
Controls.Add(PortalChoices);
Controls.Add(new LiteralControl("</div>"));
Controls.Add(new LiteralControl("<div> <span style='font-weight:bold;'>Listes disponibles</span> "));
Controls.Add(AppChoices);
Controls.Add(new LiteralControl("</div>"));
Controls.Add(new LiteralControl("<div> <span style='font-weight:bold;'>Listes des vues disponibles</span> "));
Controls.Add(ListViews);
Controls.Add(new LiteralControl("</div>"));
base.CreateChildControls();
ChildControlsCreated = true;
}
/// <summary>
/// Applies change in editor part ddl to the parent web part
/// </summary>
/// <returns></returns>
public override bool ApplyChanges()
{
try
{
EnsureChildControls();
WebPartPerso ParentWebPart = (WebPartPerso)WebPartToEdit;
if (ParentWebPart != null)
{
ParentWebPart.MyAppChoice = AppChoices.Text;
ParentWebPart.MyViewChoice = ListViews.Text;
ParentWebPart.MyPortalChoice = PortalChoices.Text;
}
ParentWebPart.SaveChanges();
// The operation was succesful
return true;
}
catch
{
// Because an error has occurred, the SyncChanges() method won’t be invoked.
return false;
}
}
/// <summary>
/// Reads current value from parent web part and show that in the ddl
/// </summary>
public override void SyncChanges()
{
EnsureChildControls();
WebPartPerso ParentWebPart = (WebPartPerso)WebPartToEdit;
if (ParentWebPart != null)
{
AppChoices.Text = ParentWebPart.MyAppChoice;
PortalChoices.Text = ParentWebPart.MyPortalChoice;
ListViews.Text = ParentWebPart.MyViewChoice.ToString();
}
}
}

Make WebBrowsable true
[WebBrowsable(true), Personalizable(PersonalizationScope.User), DefaultValue("PERSO")]
public string MyPortalChoice { get; set; }

Related

Error in Process screen when attaching report to email

We have a requirement to attach custom report to email as an attachment. As per our requirement we created a process screen for this. Issue we are facing is, when we use below line of code we are getting “OBJECT REFERENCE ERROR”, can you please have a look at below sample code.
public class ProcessReports : PXGraph<ProcessReports>
{
[InjectDependency]
protected IReportLoaderService ReportLoader { get; private set; }
[InjectDependency]
protected IReportRenderer ReportRenderer { get; private set; }
public PXCancel<DACName> Cancel;
public PXProcessing<DACName, Where<DACName.DACName, Equal<OPR>>> QueueList;
public ProcessReports()
{
QueueList.SetProcessDelegate(delegate (List<DACName> list)
{
SaveFile(list, true);
});
}
public static void SaveFile(List<DACName> list, bool aIsMassProcess)
{
new KWProcessWorkCenterOpenJobReports().save(list, aIsMassProcess);
}
public virtual void save(List<DACName> list, bool aIsMassProcess)
{
//here at this point we are getting error
Report _report = ReportLoader.LoadReport("AA501108", null);
}
}
Looking at your code my inference is the object with the IReportLoaderService and IReportRenderer interface decleration never properly gets initialized with PXGraph.CreateInstance<...> before calling save method.
new KWProcessWorkCenterOpenJobReports().save(list, aIsMassProcess);
The following code snippet will generate a report from the given paramaters provided and then save the file within the Acumatica system, though it can be further emailed out as mentioned in your original prompt.
using PX.Data;
using PX.Objects.AR;
using PX.Reports;
using PX.Reports.Controls;
using PX.Reports.Data;
using PX.SM;
using System.Collections.Generic;
using MailMessage = PX.Reports.Mail.Message;
namespace StackOverflow
{
public class EmailReportProc : PXGraph<EmailReportProc>
{
#region Constructor
public EmailReportProc()
{
Documents.SetProcessDelegate(generateAcumaticaReports);
}
#endregion
#region Properties
[InjectDependency]
protected IReportLoaderService ReportLoader { get; set; }
[InjectDependency]
protected IReportDataBinder ReportDataBinder { get; set; }
#endregion
#region Views
public PXCancel<ARInvoice> Cancel;
public PXProcessing<ARInvoice, Where<ARInvoice.status, Equal<ARDocStatus.pendingEmail>>> Documents;
#endregion
#region Methods
private static void generateAcumaticaReports(List<ARInvoice> Documents)
{
//Initialize new graph instance for use within static processing method.
EmailReportProc graph = PXGraph.CreateInstance<EmailReportProc>();
foreach (ARInvoice document in Documents)
{
//Paramaters for report
Dictionary<string, string> parameters = new Dictionary<string, string>
{
{ "ARInvoice.DocType", document.DocType },
{ "ARInvoice.RefNbr", document.RefNbr }
};
//Load report - ReportID must be valid sitemap entry in system
Report report = graph.ReportLoader.LoadReport("AR622000", null);
//Initialize the parameters for the report
graph.ReportLoader.InitDefaultReportParameters(report, parameters);
ReportNode reportNode = graph.ReportDataBinder.ProcessReportDataBinding(report);
//Generate PDF Report and creates Acumatica file.
FileInfo fileInfo = new FileInfo(reportNode.ExportFileName + ".pdf", null, MailMessage.GenerateReport(reportNode, RenderType.FilterPdf)[0]);
UploadFileMaintenance uploadFileMaintenance = PXGraph.CreateInstance<UploadFileMaintenance>();
//Save Generated file into system
_ = uploadFileMaintenance.SaveFile(fileInfo);
}
}
#endregion
}
}

How do I communicate between two sibling Blazor components?

I have a Blazor page with two components. One component has a button which generates a random number when clicked. The other component has a text area which should display the generated random number.
<h1>Parent Page</h1>
<ProvideNumberComponent />
<DisplayNumberComponent />
#code {
}
<h3>Provides Number</h3>
<button class="btn btn-primary" #onclick="CalculateNumber">Provide Number</button>
#code {
private void CalculateNumber(MouseEventArgs e)
{
Random rnd = new Random();
Int32 nextNumber = rnd.Next();
}
}
<h3>Displays number</h3>
<textarea cols="9" rows="1" readonly style="font-family:monospace;" />
#code {
}
What is the cleanest way to get the number from the calculate sibling component to appear in the display sibling component?
A problem with my code is that the Random object is instantiated on every button click, instead of once on initialization. Is this best addressed by placing the Random object in a singleton service class, and injecting that into the calculate component?
The best solution, to my mind, is to create a service which implements the state pattern and the notifier pattern. The following code describes how communication between two sibling can be done through an intermediary
NotifierService.cs
public class NotifierService
{
public NotifierService()
{
}
int rnd;
public int RandomNumber
{
get => rnd;
set
{
if (rnd != value)
{
rnd= value;
if (Notify != null)
{
Notify?.Invoke();
}
}
}
}
public event Func<Task> Notify;
}
Add this: services.AddScoped<NotifierService>();
ProvideNumberComponent.razor
#inject NotifierService Notifier
#implements IDisposable
<h3>Provides Number</h3>
<button class="btn btn-primary" #onclick="CalculateNumber">Provide
Number</button>
#code
{
private void CalculateNumber(MouseEventArgs e)
{
Random rnd = new Random();
Int32 nextNumber = rnd.Next();
Notifier.RandomNumber = nextNumber;
}
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
DisplayNumberComponent.cs
#inject NotifierService Notifier
#implements IDisposable
<hr />
<h3>Displays number</h3>
<textarea cols="9" rows="1" readonly style="font-family:monospace;">
#Notifier.RandomNumber
</textarea>
#code {
public async Task OnNotify()
{
await InvokeAsync(() =>
{
StateHasChanged();
});
}
protected override void OnInitialized()
{
Notifier.Notify += OnNotify;
}
public void Dispose()
{
Notifier.Notify -= OnNotify;
}
}
Of course you can inject and use the service in multiple components, as well as adding more features that the service can provide.
Implementing communication by means of event handlers may be problematic, unless it is between a parent and its child...
Hope this works...
Indeed there are many ways to accomplish your goal, I just want to show you the way I like more:
Parent Component:
<EditForm Model="Message">
<PageOne #bind-Send="Message.Text"/>
<PageTwo #bind-Receive="Message.Text"/>
</EditForm>
#code{
public Content Message { get; set; }=new Index.Content();
public class Content
{
public string Text { get; set; } = "Hello world";
}
}
PageOne component - the one who send the value:
<button #onclick="#GetGuid">Change value</button>
#code{
[Parameter] public string Send { get; set; }
[Parameter] public EventCallback<string> SendChanged { get; set; }
async void GetGuid()
{
await SendChanged.InvokeAsync(Guid.NewGuid().ToString());
}
}
PageTwo the component which will receive the data
<h1>#Receive</h1>
#code{
[Parameter] public string Receive { get; set; }
[Parameter] public EventCallback<string> ReceiveChanged { get; set; }
}
Explanations:
Usually when we need to communicate, we need a third party service, and in this case I used the EditForm component, which can store a Model and the properties of this model can be shared by all child components.
I also made a custom component, with less functionality, and I named PhoneBox (to be used instead EditForm), just to be obvious the role :)
PhoneBox - third party communication service :)
<CascadingValue Value="EditContext">
#ChildContent(EditContext)
</CascadingValue>
#code {
[Parameter] public object Model { get; set; }
[Parameter]public EditContext EditContext { get; set; }
[Parameter] public RenderFragment<EditContext> ChildContent { get; set; }
protected override void OnInitialized()
{
EditContext = new EditContext(Model);
}
}
I like more this approach because look's more "blazor way" :)
Look how nice is "blazor way"
<PhoneBox Model="Message">
<PageOne #bind-Send="Message.Text"/>
<PageTwo #bind-Receive="Message.Text"/>
</PhoneBox>
You can see a working example Working Example
I think interfaces are the best way to do this.
This is from my Nuget package, DataJugger.Blazor.Components
Interface IBlazorComponent:
#region using statements
using System.Collections.Generic;
#endregion
namespace DataJuggler.Blazor.Components.Interfaces
{
#region interface IBlazorComponent
/// <summary>
/// This interface allows communication between a blazor componetn and a parent component or page.
/// </summary>
public interface IBlazorComponent
{
#region Methods
#region ReceiveData(Message message)
/// <summary>
/// This method is used to send data from a child component to the parent component or page.
/// </summary>
/// <param name="data"></param>
void ReceiveData(Message message);
#endregion
#endregion
#region Properties
#region Name
/// <summary>
/// This property gets or sets the Name.
/// </summary>
public string Name { get; set; }
#endregion
#region Parent
/// <summary>
/// This property gets or sets the Parent componet or page for this object.
/// </summary>
public IBlazorComponentParent Parent { get; set; }
#endregion
#endregion
}
#endregion
}
Interface IBlazorComponentParent
#region using statements
using System.Collections.Generic;
#endregion
namespace DataJuggler.Blazor.Components.Interfaces
{
#region interface IBlazorComponentParent
/// <summary>
/// This interface is used to host IBlazorComponent objects
/// </summary>
public interface IBlazorComponentParent
{
#region Methods
#region FindChildByName(string name)
/// <summary>
/// This method is used to find a child component that has registered with the parent.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
IBlazorComponent FindChildByName(string name);
#endregion
#region ReceiveData(Message message)
/// <summary>
/// This method is used to send data from a child component to the parent component or page.
/// </summary>
/// <param name="data"></param>
void ReceiveData(Message message);
#endregion
#region Refresh()
/// <summary>
/// This method will call StateHasChanged to refresh the UI
/// </summary>
void Refresh();
#endregion
#region Register(IBlazorComponent component)
/// <summary>
/// This method is called by the Sprite to a subscriber so it can register with the subscriber, and
/// receiver events after that.
/// </summary>
void Register(IBlazorComponent component);
#endregion
#endregion
#region Properties
#region Children
/// <summary>
/// This property gets or sets the value for Children.
/// </summary>
public List<IBlazorComponent> Children { get; set; }
#endregion
#endregion
}
#endregion
}
For usage, here is the most relevant parts:
In your component, which is an IBlazorCompoent (child), there is a Parent property.
In your component, you set the parent like this:
<Login Parent=this></Login>
Then in your component, you alter the parent property like this:
[Parameter]
public IBlazorComponentParent Parent
{
get { return parent; }
set
{
// set the value
parent = value;
// if the Parent exists
(Parent != null)
{
// Register with the parent
Parent.Register(this);
}
}
}
Next, in your parent component that implements IBlazorComponentParent, add a property for your component and change the Register method to this:
// Login component reference
public Login LoginComponent { get; set; }
public void Register(IBlazorComponent component)
{
if (component is Login)
{
// Store the LoginComponent
LoginComponent = component as Login;
}
else if (component is Join)
{
// Store the compoent
SignUpComponent = component as Join;
}
}
Now at this point, my Login component knows about the parent and the parent knows about the Login, so I can sent messages like this:
From the child, send a simple message:
if (Parent != null)
{
Message message = new Message();
message.Text = "Some message";
Parent.SendMessage(message);
}
Or send a complex message
// create a message
DataJuggler.Blazor.Components.Message message = new DataJuggler.Blazor.Components.Message();
// Create the parameters to pass to the component
NamedParameter parameter = new NamedParameter();
// Set the name
parameter.Name = "PixelInformation Update";
parameter.Value = pixel;
// Create a new collection of 'NamedParameter' objects.
message.Parameters = new List<NamedParameter>();
// Add this parameter
message.Parameters.Add(parameter);
// Send this to the component
ColorPickerComponent.ReceiveData(message);
Then in the parent to receive the message:
public void ReceiveData(Message message)
{
// If the message object exists and has parameters
if ((message != null) && (message.HasParameters))
{
// if this a PixelInformation update from the Index page
if (message.Parameters[0].Name == "PixelInformation Update")
{
// this is only relevant to my app, just showing an example of
// \what I do with the data after it is received.
// Set the SelectedPixel
SelectedPixel = (PixelInformation) message.Parameters[0].Value;
// Set the properties from the Pixel to display
SetupColorPicker();
}
}
}
The above code is used in my newest site, PixelDatabase.Net https://pixeldatabase.net
The Nuget package code is all open source if anyone wants it:
DataJuggler.Blazor.Components
https://github.com/DataJuggler/DataJuggler.Blazor.Components
I come from a Windows Forms background, so I love being able to communicate between components like this, which data binding doesn't always work.
this.Login.DoSomething(data);
You can also cast the parent as a specific type like this:
public IndexPage ParentIndexPage
{
get
{
// cast the Parent object as an Index page
return this.Parent as IndexPage;
}
}
So your child can call methods or set properties on the parent, if the parent exists of course, so always add a:
public bool HasParentIndexPage
{
get
{
// return true if the ParentIndexPage exists
return (ParentIndexPage != null);
}
}
So then for easy usage from the child:
// if the parent index page exists
if (HasParentIndexPage)
{
// Safely call your parent page
ParentIndexPage.SomeMethod();
}
On way to do it would absolutely be to use the session pattern and inject the same instance in both components and then notify them onchange. A faster way would probably be to use the two way binding and eventcallbacks.
In ProvideNumberComponent.razor
<button class="btn btn-primary" #onclick="CalculateNumber">Provide Number</button>
#code {
[Parameter]
public EventCallback<int> OnRandomNumberSet{get; set;}
private void CalculateNumber(MouseEventArgs e)
{
Random rnd = new Random();
Int32 nextNumber = rnd.Next();
OnRandomNumberSet.InvokeAsync(nextNumber);
}
}
In ParentComponent.razor
<h1>Parent Page</h1>
<ProvideNumberComponent OnRandomNumberSet="((r) => SetRandomNumber(r))"/>
<DisplayNumberComponent TextAreaValue="_randomNumber" />
#code {
private int _randomNumber;
private void SetRandomNumber(int randomNumber)
{
_randomNumber = randomNumber;
}
}
In DisplayNumberComponent.razor
<h3>Displays number</h3>
<textarea cols="9" rows="1" bind:value="TextAreaValue" readonly style="font-family:monospace;" />
#code
{
[Parameter]
public int TextAreaValue{get; set;}
}
MDSN has an example using DI injected Notifier service
invoke component methods externally to update state, which should work for any component-relation (not only siblings).
At a steeper learning curve, but more maintenance-friendly + scaleable in the long run is the Flux/Redux library Fluxor
For anyone trying to get an overview of more "design-pattern"'ish solutions, MVVM is also a posibility, example here: MVVM example implementation 4 Blazor

OxyPlot EventTrigger

I am trying to handle event in OxyPlot using EventTrigger. But it does not work like I want.
<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:oxy="http://oxyplot.org/wpf"
Title="MainWindow" Height="350" Width="525">
<Grid>
<oxy:PlotView Model="{Binding PlotModel}" DefaultTrackerTemplate="{x:Null}">
<i:Interaction.Triggers >
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding Move}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</oxy:PlotView>
</Grid>
And code look's like
using OxyPlot;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using OxyPlot.Axes;
using GalaSoft.MvvmLight.Command;
namespace WpfApplication14
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public partial class MainWindow : Window
{
public class DataGeneration
{
public PlotModel PlotModel { get; set; }
public ICommand Move { get; set; }
public int _NumberOf;
public Dictionary<int, List<int>> Test { get; set; }
OxyPlot.Series.LineSeries LS;
Random rnd;
LinearAxis LA;
public int EndPosition = 0;
public DataGeneration(int NumberOf)
{
LA = new LinearAxis()
{
Position=AxisPosition.Bottom,
Minimum=0,
Maximum = EndPosition
};
Move = new RelayCommand(() => TestMove());
_NumberOf = NumberOf;
rnd = new Random();
Test = new Dictionary<int, List<int>>();
PlotModel = new PlotModel();
PlotModel.Axes.Add(LA);
LS = new OxyPlot.Series.LineSeries();
PlotModel.Series.Add(LS);
}
public void TestMove()
{
PlotModel.Axes[0].Reset();
}
public void AddPoint()
{
do
{
LS.Points.Add(new DataPoint(++_NumberOf, rnd.Next(1, 10)));
System.Threading.Thread.Sleep(1000);
EndPosition += 1;
LA.Maximum = EndPosition+3;
LA.Minimum = EndPosition;
Update();
} while (true);
}
public void Update()
{
PlotModel.InvalidatePlot(true);
}
}
public delegate void BeginUpdate();
private Stopwatch stopwatch = new Stopwatch();
private long lastUpdateMilliSeconds;
DataGeneration Data;
public MainWindow()
{
Data = new DataGeneration(1);
BeginUpdate BU = new BeginUpdate(Data.AddPoint);
IAsyncResult result = BU.BeginInvoke(null, null);
this.DataContext = Data;
CompositionTarget.Rendering += CompositionTargetRendering;
InitializeComponent();
}
private void CompositionTargetRendering(object sender, EventArgs e)
{
if (stopwatch.ElapsedMilliseconds > lastUpdateMilliSeconds + 300)
{
Data.Update();
}
}
}
}
why it firing when I make double click on OxyPlot? Genaraly i am trying to pan chart by left mousebutton.It's implemented in oxyplot by default(right mouse button).

Automapper ObservableCollection – refreshing is not working

I have small WPF application. There are 5 projects in solution.
I want separate DOMAIN classes with UI ENTITIES and I want to use AUTOMAPPER.
You can download whole solution here: TestWPFAutomapper.zip
Domain class(Domain.Source.cs) with UI Entity(Entities.Destination.cs) have same signature.
In Entities.Destination.cs I would like to put other logic.
namespace DOMAIN
{
public class Source
{
public int Id { get; set; }
public int Position { get; set; }
}
}
using System.ComponentModel;
namespace ENITITIES
{
public class Destination : INotifyPropertyChanged
{
private int _id;
private int _position;
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged("Id");
}
}
public int Position
{
get { return _position; }
set
{
_position = value;
OnPropertyChanged("Position");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
My data comes from DAL.DataContext using Entity Framework with CodeFirst. Here I´m using Source class.
using System.Data.Entity;
using DOMAIN;
namespace DAL
{
public class DataContext : DbContext
{
public DbSet<Source> Sources { get; set; }
}
}
Mapping is in BL.MyAppLogic.cs . In this class I have property Items which is ObservableCollection.
After puting another item into DB for Source class collection get refresh but for Destination is not refreshing.
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using AutoMapper;
using DAL;
using DOMAIN;
using ENITITIES;
namespace BL
{
public class MyAppLogic
{
private readonly DataContext _dataContext = new DataContext();
public ObservableCollection<Source> Items { get; set; }
//public ObservableCollection<Destination> Items { get; set; }
public MyAppLogic()
{
Database.SetInitializer(new MyInitializer());
Mapping();
_dataContext.Sources.Load();
Items = _dataContext.Sources.Local;
//Items = Mapper.Map<ObservableCollection<Source>, ObservableCollection<Destination>>(_dataContext.Sources.Local);
}
private void Mapping()
{
Mapper.CreateMap<Source, Destination>().ReverseMap();
// I tried also Mapper.CreateMap<ObservableCollection<Source>, ObservableCollection<Destination>>().ReverseMap();
}
public int GetLastItem()
{
return _dataContext.Database.SqlQuery<int>("select Position from Sources").ToList().LastOrDefault();
}
public void AddNewItem(Destination newItem)
{
_dataContext.Sources.Add(Mapper.Map<Destination, Source>(newItem));
_dataContext.SaveChanges();
}
}
}
My problem is not with mapping, that’s works good, but with refreshing collection after adding or removing items from db. If I use DOMAIN.Source class everything works, collection is refreshing. But when I’m using ENTITIES.Destination data comes from DB and also I can put som new data to DB but refresing ObservableCollection is not working.
Please try to comment lines(14 & 23) in BL.MyAppLogic.cs and uncomment(15 & 24) and you’ll see what I mean.
Thank you for any help.
I got it but I don´t know if is correct.
Local has CollectionChanged event
so in constructor I put these lines
public MyAppLogic()
{
Database.SetInitializer(new MyInitializer());
Mapping();
_dataContext.Sources.Load();
_dataContext.Sources.Local.CollectionChanged += SourcesCollectionChanged;
Items = Mapper.Map<ObservableCollection<Source>, ObservableCollection<Destination>>(_dataContext.Sources.Local);
}
and handler looks
private void SourcesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var source = sender as ObservableCollection<Source>;
Mapper.Map(source, Items);
}
Now is my collection automating refreshing when I put something to DB in my UI.
Looks like automapper don´t put reference into Items, but create new instance.

The entity type IdentityRole is not part of the model for the current context

I am having trouble implementing ASPNetIdentity on my MVC project
I am getting this error in the var line (The entity type IdentityRole is not part of the model for the current context.):
using System;
using System.Linq;
using System.Web.Mvc;
using EZ.Models;
using Microsoft.AspNet.Identity.EntityFramework;
namespace EZ.Controllers
{
public class RoleController : Controller
{
ApplicationDbContext context;
public RoleController()
{
context = new ApplicationDbContext();
}
/// <summary>
/// Get All Roles
/// </summary>
/// <returns></returns>
public ActionResult Index()
{
var roles = context.Roles.ToList();
return View(roles);
}
/// <summary>
/// Create a New role
/// </summary>
/// <returns></returns>
// GET: /Roles/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Roles/Create
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
context.Roles.Add(new Microsoft.AspNet.Identity.EntityFramework.IdentityRole()
{
Name = collection["RoleName"]
});
context.SaveChanges();
ViewBag.ResultMessage = "Role created successfully !";
return RedirectToAction("Index");
}
catch
{
return View();
}
}
/// <summary>
/// Set Role for Users
/// </summary>
/// <returns></returns>
public ActionResult SetRoleToUser()
{
var list = context.Roles.OrderBy(role => role.Name).ToList().Select(role => new SelectListItem { Value = role.Name.ToString(), Text = role.Name }).ToList();
ViewBag.Roles = list;
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UserAddToRole(string uname, string rolename)
{
ApplicationUser user = context.Users.Where(usr => usr.UserName.Equals(uname, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
// Display All Roles in DropDown
var list = context.Roles.OrderBy(role => role.Name).ToList().Select(role => new SelectListItem { Value = role.Name.ToString(), Text = role.Name }).ToList();
ViewBag.Roles = list;
if (user != null)
{
var account = new AccountController();
account.UserManager.AddToRoleAsync(user.Id, rolename);
ViewBag.ResultMessage = "Role created successfully !";
return View("SetRoleToUser");
}
else
{
ViewBag.ErrorMessage = "Sorry user is not available";
return View("SetRoleToUser");
}
}
}
}
I have scripted the tables in my DB.
This is the exact same code as in the role-security-mvc5-master project from CodeProject.com. The only difference is that I moved the tables in my DB ana dI changed the connection string. What is the piece I am missing?
in my IdentityModel.cs I have:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
If you need more code, please let me know and I will post.
When the project was created, identity, a database at locadb. when I moved the tables in my DB I overwrote the entire Default connection string with the one I created for E. The big probelm here was that the default connection needs providerName="System.Data.SqlClient" /> and NOT providerName="System.Data.EntityClient". Be careful there. Credit needs to go to this excellent article from Daniel Eagle: http://danieleagle.com/blog/2014/05/setting-up-asp-net-identity-framework-2-0-with-database-first-vs2013-update-2-spa-template/. Tons of detail on how to use Identity with DB first.

Resources