Image Carousel using Twitter Bootstrap and Orchard CMS - content-management-system

I am using Orchard CMS and the Bootstrap theme. I have been trying to use the carousel built in bootstrap to work as shown in the following blog post: http://www.stevetaylor.me.uk/image-carousel-using-twitter-bootstrap-and-orchard-cms-projections. I have followed the tutorial but i cannot get my new layout file to appear in the query under grid and html list. I believe i have copied the code word for word but still can get it to work. Anybody please help with this as think it would be a great feature to add. if i get it to work i will request it gets added to the bootstrap theme here: http://orchardbootstrap.codeplex.com/
See code below:
CarouselLayoutForm.cs
using System;
using Orchard.DisplayManagement;
using Orchard.Forms.Services;
using Orchard.Localization;
namespace Orchard.Projections.Providers.Layouts {
public class CarouselLayoutForms : IFormProvider {
protected dynamic Shape { get; set; }
public Localizer T { get; set; }
public CarouselLayoutForms(
IShapeFactory shapeFactory) {
Shape = shapeFactory;
T = NullLocalizer.Instance;
}
public void Describe(DescribeContext context) {
Func<IShapeFactory, object> form =
shape => {
var f = Shape.Form(
Id: "CarouselLayout",
_HtmlProperties: Shape.Fieldset(
Title: T("Html properties"),
_ListId: Shape.TextBox(
Id: "outer-grid-id", Name: "OuterDivId",
Title: T("Outer div id"),
Description: T("The id to provide on the div element."),
Classes: new[] { "textMedium", "tokenized" }
),
_ListClass: Shape.TextBox(
Id: "outer-div-class", Name: "OuterDivClass",
Title: T("Outer div class"),
Description: T("The class to provide on the div element."),
Classes: new[] { "textMedium", "tokenized" }
),
_InnerClass: Shape.TextBox(
Id: "inner-div-class", Name: "InnerDivClass",
Title: T("Inner div class"),
Description: T("The class to provide on the inner div element."),
Classes: new[] { "textMedium", "tokenized" }
),
_FirstItemClass: Shape.TextBox(
Id: "first-item-class", Name: "FirstItemClass",
Title: T("First item class"),
Description: T("The class to provide on the first item element."),
Classes: new[] { "textMedium", "tokenized" }
),
_ItemClass: Shape.TextBox(
Id: "item-class", Name: "ItemClass",
Title: T("Item class"),
Description: T("The class to provide on the item element."),
Classes: new[] { "textMedium", "tokenized" }
)
)
);
return f;
};
context.Form("CarouselLayout", form);
}
}
/*
public class CarouselLayoutFormsValitator : FormHandler {
public Localizer T { get; set; }
public override void Validating(ValidatingContext context) {
if (context.FormName == "CarouselLayout") {
if (context.ValueProvider.GetValue("Alignment") == null) {
context.ModelState.AddModelError("Alignment", T("The field Alignment is required.").Text);
}
if (context.ValueProvider.GetValue("Columns") == null) {
context.ModelState.AddModelError("Columns", T("The field Columns/Lines is required.").Text);
}
else {
int value;
if (!Int32.TryParse(context.ValueProvider.GetValue("Columns").AttemptedValue, out value)) {
context.ModelState.AddModelError("Columns", T("The field Columns/Lines must be a valid number.").Text);
}
}
}
}
}
*/
}
CarouselLayout.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Projections.Descriptors.Layout;
using Orchard.Projections.Models;
using Orchard.Projections.Services;
namespace Orchard.Projections.Providers.Layouts {
public class CarouselLayout : ILayoutProvider {
private readonly IContentManager _contentManager;
protected dynamic Shape { get; set; }
public CarouselLayout(IShapeFactory shapeFactory, IContentManager contentManager) {
_contentManager = contentManager;
Shape = shapeFactory;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public void Describe(DescribeLayoutContext describe) {
describe.For("Html", T("Html"),T("Html Layouts"))
.Element("Carousel", T("Carousel"), T("Organizes content items in a carousel."),
DisplayLayout,
RenderLayout,
"CarouselLayout"
);
}
public dynamic RenderLayout(LayoutContext context, IEnumerable<LayoutComponentResult> layoutComponentResults) {
string outerDivClass = context.state.outerDivClass;
string OuterDivId = context.state.OuterDivID;
string innerDivClass = context.state.InnerDicClass;
string firstItemClass = context.state.FirstItemClass;
string itemClass = context.state.ItemClass;
IEnumerable<dynamic> shapes =
context.LayoutRecord.Display == (int)LayoutRecord.Displays.Content
? layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType))
: layoutComponentResults.Select(x => x.Properties);
return Shape.Carousel(Id: outerDivId, Items: shapes, OuterClasses: new[] { outerDivClass },
InnerClasses: new[] {innerDivClass}, FirstItemClasses: new[] {firstItemClass}, ItemClasses: new[] {itemClass});
}
}
}
LayoutShapes.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Mvc.Html;
using Orchard.Utility.Extensions;
namespace Orchard.Projections.Providers.Layouts {
public class LayoutShapes : IDependency {
public LayoutShapes() {
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
[Shape]
public void Carousel(dynamic Display, TextWriter Output, HtmlHelper Html, string Id, IEnumerable<dynamic> Items,
IEnumerable<string> OuterClasses, IDictionary<string, string> OuterAttributes,
IEnumerable<string> InnerClasses, IDictionary<string, string> InnerAttributes,
IEnumerable<string> FirstItemClasses, IDictionary<string, string> FirstItemAttributes, IEnumerable<string> ItemClasses, IDictionary<string, string> ItemAttributes )
{
if (Items == null) return;
var items = Items.ToList();
var itemsCount = items.Count;
if (itemsCount < 1) return;
var outerDivTag = GetTagBuilder("div", Id, OuterClasses, OuterAttributes);
var innerDivTag = GetTagBuilder("div", string.Empty, InnerClasses, InnerAttributes);
var firstItemTag = GetTagBuilder("div", string.Empty, FirstItemClasses, FirstItemAttributes);
var itemTag = GetTagBuilder("div", string.Empty, ItemClasses, ItemAttributes);
Output.Write(outerDivTag.ToString(TagRenderMode.StartTag));
Output.Write(innerDivTag.ToString(TagRenderMode.StartTag));
int i = 0;
foreach (var item in items)
{
if (i== 0)
Output.Write(firstItemTag.ToString(TagRenderMode.StartTag));
else
Output.Write(itemTag.ToString(TagRenderMode.StartTag));
Output.Write(Display(item));
Output.Write(itemTag.ToString(TagRenderMode.EndTag));
i++;
}
Output.Write(innerDivTag.ToString(TagRenderMode.EndTag));
Output.Write("‹",id);
Output.Write("‹",id);
Output.Write(outerDivTag.ToString(TagRenderMode.EndTag));
Output.Write("<script>$(function () {$('"+ Id +"').carousel();}); </script>");
}
static TagBuilder GetTagBuilder(string tagName, string id, IEnumerable<string> classes, IDictionary<string, string> attributes) {
var tagBuilder = new TagBuilder(tagName);
tagBuilder.MergeAttributes(attributes, false);
foreach (var cssClass in classes ?? Enumerable.Empty<string>())
tagBuilder.AddCssClass(cssClass);
if (!string.IsNullOrWhiteSpace(id))
tagBuilder.GenerateId(id);
return tagBuilder;
}
}
}

Did you add your code to the module Orchard.Projections as explained?
You need to add the files in Visual Studio and to save the project for them to be included in the .csproj (unless, the dynamic compilation won't take the files in account), or you can build the module.

You are missing the definition for DisplayLayout() in your CarouselLayou.cs file:
public LocalizedString DisplayLayout(LayoutContext context)
{
string columns = context.State.Columns;
bool horizontal = Convert.ToString(context.State.Alignment) != "vertical";
return horizontal
? T("{0} columns grid", columns)
: T("{0} lines grid", columns);
}
Also, variable 'id' in LayourShapes.cs should be 'Id', and there are other incorrect casings in the declarations:
string outerDivClass = context.state.outerDivClass;
string OuterDivId = context.state.OuterDivID;
string innerDivClass = context.state.InnerDicClass;
string firstItemClass = context.state.FirstItemClass;
string itemClass = context.state.ItemClass;
should be:
string outerDivClass = context.State.OuterDivClass;
string outerDivId = context.State.OuterDivID;
string innerDivClass = context.State.InnerDicClass;
string firstItemClass = context.State.FirstItemClass;
string itemClass = context.State.ItemClass;

Related

context.GetArgument() returning null with ByteGraphType

I´m learning how to use CustomScalar in graphql-dotnet.
I have a tinyint column in my table and from what I have read, I´m supposed to use byte on this column in C#. After research I found out that I need to create a ByteGraphType, but I´m having trouble doing that.
I got the ByteGraphType example from this link https://github.com/graphql-dotnet/graphql-dotnet/issues/458, so I think it will work.
With this code, I can query the table, however, my mutation is not working. I didn´t find an example to demonstrate how the mutation would look like with a byte column. I tried as is stated in my code example, but in this line (var avaliacao = context.GetArgument("avaliacao");), my argument avaliacao.Nota is returning null and I´m not sure on how to proceed.
Can someone help me?
Thank you
THAT´S MY CODE
//Model
[Column("nota")]
public byte Nota { get; set; }
//Type
Field<ByteGraphType>("Nota", resolve: context => context.Source.Nota);
//InputType
Field<ByteGraphType>("nota");
//Query
Field<ListGraphType<AvaliacaoType>>(
"avaliacoes",
resolve: context => contextServiceLocator.AvaliacaoRepository.All());
//Mutation
Field<AvaliacaoType>(
"createAvaliacao",
arguments: new QueryArguments(
new QueryArgument<NonNullGraphType<AvaliacaoInputType>> { Name = "avaliacao" }
),
resolve: context =>
{
var schema = new Schema();
schema.RegisterValueConverter(new ByteValueConverter());
var avaliacao = context.GetArgument<Avaliacao>("avaliacao");
avaliacao.Nota.AstFromValue(schema, new ByteGraphType());
return contextServiceLocator.AvaliacaoRepository.Add(avaliacao);
});
//ByteGraphType
using GraphQL.Language.AST;
using GraphQL.Types;
using System;
namespace Api.Helpers
{
public class ByteGraphType : ScalarGraphType
{
public ByteGraphType()
{
Name = "Byte";
}
public override object ParseLiteral(IValue value)
{
var byteVal = value as ByteValue;
return byteVal?.Value;
}
public override object ParseValue(object value)
{
if (value == null)
return null;
try
{
var result = Convert.ToByte(value);
return result;
}
catch (FormatException)
{
return null;
}
}
public override object Serialize(object value)
{
return ParseValue(value).ToString();
}
public class ByteValueConverter : IAstFromValueConverter
{
public bool Matches(object value, IGraphType type)
{
return value is byte;
}
public IValue Convert(object value, IGraphType type)
{
return new ByteValue((byte)value);
}
}
public class ByteValue : ValueNode<byte>
{
public ByteValue(byte value)
{
Value = value;
}
protected override bool Equals(ValueNode<byte> node)
{
return Value == node.Value;
}
}
}
}
What I need is to be able to save a record of a table that has a tinyint column. If I change the type in my code to int, I can mutate, but can´t query.
I changed my CustomScalar and it worked:
using GraphQL.Language.AST;
using GraphQL.Types;
using System;
namespace Api.Helpers
{
public class ByteGraphType : ScalarGraphType
{
public ByteGraphType()
{
Name = "Byte";
Description = "ByteGraphType";
}
/// <inheritdoc />
public override object Serialize(object value)
{
return ParseValue(value).ToString();
}
/// <inheritdoc />
public override object ParseValue(object value)
{
byte result;
if (byte.TryParse(value?.ToString() ?? string.Empty, out result))
{
return result;
}
return null;
}
/// <inheritdoc />
public override object ParseLiteral(IValue value)
{
if (value is StringValue)
{
return ParseValue(((StringValue)value).Value);
}
return null;
}
}
}

How to create custom model binder for Mongodb ObjectId in Nancy?

In asp.net mvc I did it like this.
public class ObjectIdBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
return new ObjectId(result.AttemptedValue);
}
}
How would I do that in Nancy?
Also how do you register it in bootstrapper? code sample?
So I ended up creating an extension to Nancy's Request class.
I created a new Body method that takes a type and uses Json.Net contract to
bind any property in the model that is type ObjectId.
public static class BodyBinderExtension
{
public static T Body<T>(this Request request)
{
request.Body.Position = 0;
string bodyText;
using (var bodyReader = new StreamReader(request.Body))
{
bodyText = bodyReader.ReadToEnd();
}
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
ContractResolver = new ObjectIDContractResolver()
};
return JsonConvert.DeserializeObject<T>(bodyText);
}
}

Autofac PropertiesAutowired - Is it possible to ignore a one or more properties?

Despite the advice to pass dependencies through the constructor I've found that the development cost of having parameterless constructors and then autowiring all of the properties on everything is significantly less and makes the application much easier to develop out and maintain. However sometimes (on a view model for example) I have a property that is registered with the container, but that I don't want to populate at construction (for example the selected item bound to a container).
Is there any way to tell the container to ignore certain properties when it autowires the rest?
At the moment I'm just resetting the properties marked with an attribute in the on activated event a la:
public static IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle>
PropertiesAutowiredExtended<TLimit, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle> builder)
{
builder.ActivatorData.ConfigurationActions.Add(
(type, innerBuilder) =>
{
var parameter = Expression.Parameter(typeof(object));
var cast = Expression.Convert(parameter, type);
var assignments = type.GetProperties()
.Where(candidate => candidate.HasAttribute<NotAutowiredAttribute>())
.Select(property => new { Property = property, Expression = Expression.Property(cast, property) })
.Select(data => Expression.Assign(data.Expression, Expression.Default(data.Property.PropertyType)))
.Cast<Expression>()
.ToArray();
if (assignments.Any())
{
var #action = Expression
.Lambda<Action<object>>(Expression.Block(assignments), parameter)
.Compile();
innerBuilder.OnActivated(e =>
{
e.Context.InjectUnsetProperties(e.Instance);
#action(e.Instance);
});
}
else
{
innerBuilder.OnActivated(e => e.Context.InjectUnsetProperties(e.Instance));
}
});
return builder;
}
Is there a better way to do this?
Not sure that this is a better one, but you can go from another side, register only needed properties via WithProperty syntax. Pros is that Autofac doesn't resolve unnecessary services. Here's a working example:
public class MyClass
{
public MyDependency MyDependency { get; set; }
public MyDependency MyExcludeDependency { get; set; }
}
public class MyDependency {}
public class Program
{
public static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.RegisterType<MyClass>().WithPropertiesAutowiredExcept("MyExcludeDependency");
using (var container = builder.Build())
{
var myClass = container.Resolve<MyClass>();
Console.WriteLine(myClass.MyDependency == null);
Console.WriteLine(myClass.MyExcludeDependency == null);
}
}
}
public static class PropertiesAutowiredExtensions
{
// Extension that registers only needed properties
// Filters by property name for simplicity
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle>
WithPropertiesAutowiredExcept<TLimit, TReflectionActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> registrationBuilder,
params string[] propertiesNames)
where TReflectionActivatorData : ReflectionActivatorData
{
var type = ((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType;
foreach (var property in type
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.CanWrite && !propertiesNames.Contains(pi.Name)))
{
// There's no additional checks like in PropertiesAutowired for simplicity
// You can add them from Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties
var localProperty = property;
registrationBuilder.WithProperty(
new ResolvedParameter(
(pi, c) =>
{
PropertyInfo prop;
return pi.TryGetDeclaringProperty(out prop) &&
prop.Name == localProperty.Name;
},
(pi, c) => c.Resolve(localProperty.PropertyType)));
}
return registrationBuilder;
}
// From Autofac.Util.ReflectionExtensions
public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop)
{
var mi = pi.Member as MethodInfo;
if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal)
&& mi.DeclaringType != null)
{
prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4));
return true;
}
prop = null;
return false;
}
}

ASP.NET Web Api CRUD operation in VS 2010 web application

I tried to make ASP.NET Web Api CRUD operation in VS 2010 web application, but why the result is not returning all entire row from source table.
This is my code :
Route/Globax.asax
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}", // browse with localhost:7031/api/product
//routeTemplate: "{controller}/{id}", // browse with localhost:7031/product
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
Controller/ProductController.cs :
public class ProductController : ApiController
{
NorthwindEntities db = new NorthwindEntities();
public List<Product> GetAll()
{
return db.Products.ToList<Product>();// ;
}
View/ViewProduct.aspx :
<script src="Script/jquery-1.7.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$('#<%= cviewproduct.ClientID %>').click(function (e) {
getProducts();
e.preventDefault();
});
});
function getProducts() {
$.getJSON("/api/product",
function (data) {
$.each(data, function (key, val) {
//var str = val.ProductName;
// alert(str);
var row = '<tr> <td>' + val.ProductName + '</td><td>' + val.ProductID + '</td><tr/>';
$(row).appendTo($('#tblproduct'));
});
});
}
</script>
Bellow Is The Result of product Controller via 'http://localhost:7031/api/product' :
Bellow Is The Result of getProducts() function :
Please help me.
Any idea or suggestion ?
When you execute $.getJSON("/api/product", ..., you are not getting back XML as you posted. You are getting back JSON.
As a first step, I suggest you download and install Fiddler2. Open it, and use the Composer tab to execute a GET for http://localhost:7031/api/product. That should show you the JSON returned, which will be different from the XML. Post that JSON to your original question and we should be able to help further.
My guess is that the JSON is not properly formatted. What does your WebApiConfig.cs class look like?
Update
Yes, there is a better way. First, create an ApiModel (ApiModel is to WebAPI what ViewModel is to MVC):
public class ProductApiModel
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
Now, return this instead of an entity from your controller:
public class ProductController : ApiController
{
public IEnumerable<ProductApiModel> GetAll()
{
var products = db.Products
.OrderBy(x => x.ProductID)
.Select(x => new ProductApiModel
{
ProductId = x.ProductID,
ProductName = x.ProductName
});
return products;
}
}
If you used AutoMapper, you could make your controller code a bit shorter:
public class ProductController : ApiController
{
public IEnumerable<ProductApiModel> GetAll()
{
var entities = db.Products.OrderBy(x => x.ProductID);
var models = Mapper.Map<ProductApiModel[]>(entities);
return models;
}
}
After do some research, i finaly found (Please Correct Me, if i'm wrong) :
JavaScriptSerializer failed to serialize the entire objects tree from relations
between the entity and other entities (Product and Catagory).
So .. I made ​​some changes to my code, and the results are as expected
Controller/ProductController.cs :
From :
public class ProductController : ApiController
{
NorthwindEntities db = new NorthwindEntities();
public List<Product> GetAll()
{
return db.Products.ToList<Product>();// ;
}
To :
public class ProductController : ApiController
{
public string GetAll()
{
var product = db.Products.OrderBy(x => x.ProductID).Select(x => new
{
ProductId = x.ProductID,
ProductName = x.ProductName
});
return JsonConvert.SerializeObject(product);
}
View/ViewProduct.aspx :
From :
function getProducts() {
$.getJSON("/api/product",
function (data) {
$.each(data, function (key, val) {
var row = '<tr> <td>' + val.ProductName
+ '</td><td>' + val.ProductID + '</td><tr/>';
$(row).appendTo($('#tblproduct'));
});
});
To :
$.getJSON("/api/product",
function (data) {
var obj = $.parseJSON(data);
$.each(obj, function (key, val) {
var row = '<tr> <td>' + val.ProductId
+ '</td><td>' + val.ProductName + '</td><tr/>';
$(row).appendTo($('#tblproduct'));
});
});
Or... is there a better way than this,
if I still want to pass an entity object instead of a string object
(List GetAll ()... instead GetAll string ()....)
Regards,
Andrian
So.. This My Final Working Code
Models :
namespace MyLabs1.Models
{
public class ProductApi
{
[Key]
public Int32 ProductID { get; set; }
public string ProductName { get; set; }
}
}
Controller/ProductController.cs :
public IEnumerable<ProductApi> getall()
{
Mapper.CreateMap<Product, ProductApi>();
var entities = db.Products.OrderBy(x => x.ProductID).ToList();
var models = Mapper.Map<ProductApi[]>(entities);
return models;
}
OR
public List<ProductApi> GetAll()
{
var products = db.Products
.OrderBy(x => x.ProductID)
.Select(x => new ProductApi
{
ProductID = x.ProductID,
ProductName = x.ProductName
}).ToList();
return products;
}
View/ViewProduct.aspx :
function getProducts() {
$.getJSON("/api/product",
function (data) {
$.each(data, function (key, val) {
var row = '<tr> <td>' + val.ProductName + '</td><td>' + val.ProductID + '</td><tr/>';
$(row).appendTo($('#tblproduct'));
});
});
}
Hope This Will Be Helpful to Others
Regards,
Andrian

Using base View Model Class with GalaSoft MVVM Light

I am creating a project using WPF and MVVM-Light library from GalaSoft. I will have a base abstract View Model class, which will be used by all other View Model classes implemented. There I will have MVVM-Light base class as my base class. However, inside this base class, when I try to use RaisePropertyChanged function I get the following error:
An object reference is required for the non-static field, method, or property 'GalaSoft.MvvmLight.ViewModelBase.RaisePropertyChanged(string)'
The code will look like this:
AnalysisViewModelBase : ViewModelBase
{
public const string TagDescriptionStringListPropertyName = "TagDescriptionStringList";
protected static List<string> m_tagDescriptionStringList;
public static List<string> TagDescriptionStringList
{
get
{ return m_tagDescriptionStringList; }
set
{
if (m_tagDescriptionStringList == value)
return;
m_tagDescriptionStringList = value;
RaisePropertyChanged(TagDescriptionStringListPropertyName);
}
}
protected AnalysisViewModelBase()
{
m_tagDescriptionStringList = new List<string>();
m_tagDescriptionStringList.AddRange(new string[] { "North Position", "East Position", "Depth" });
}
}
AnotherViewModel : AnalysisViewModelBase
{ ... }
Could anyone please help me understand what is wrong with my RaiseProperyChanged function?
You are trying to access a Non Static Method From a Static Method... It does not have access to this value, you have to make your method non static.
here is a web page which explains about static methods if you want to have a better understanding of why you can't do what you are trying to do.
Link
You simply must declare your property "Tax DescriptionStringList " as non static. Since the backingfield (m_tagDescriptionStringList) is static it remains the same thing. Make this :
class AnalysisViewModelBase : ViewModelBase
{
public const string TagDescriptionStringListPropertyName = "TagDescriptionStringList";
protected static List<string> m_tagDescriptionStringList;
public List<string> TagDescriptionStringList
{
get
{ return m_tagDescriptionStringList; }
set
{
if (m_tagDescriptionStringList == value)
return;
m_tagDescriptionStringList = value;
RaisePropertyChanged(TagDescriptionStringListPropertyName);
}
}
protected AnalysisViewModelBase()
{
m_tagDescriptionStringList = new List<string>();
m_tagDescriptionStringList.AddRange(new string[] { "North Position", "East Position", "Depth" });
}
}
AnotherViewModel : AnalysisViewModelBase
{ ... }
If it is absolutely necessary to keep the property as a static property in this case, here is a solution: raise the property changes (using RaisePropertyChanged("TagDescriptionStringList")) when it happens, as I indicated in the code below
class AnalysisViewModelBase : ViewModelBase
{
public const string TagDescriptionStringListPropertyName = "TagDescriptionStringList";
protected static List<string> m_tagDescriptionStringList;
public static List<string> TagDescriptionStringList
{
get
{ return m_tagDescriptionStringList; }
set
{
if (m_tagDescriptionStringList != value)
{
m_tagDescriptionStringList = value;
}
}
}
protected AnalysisViewModelBase()
{
m_tagDescriptionStringList = new List<string>();
m_tagDescriptionStringList.AddRange(new string[] { "North Position", "East Position", "Depth" });
RaisePropertyChanged("TagDescriptionStringList");
}
}
AnotherViewModel : AnalysisViewModelBase
{ ... }