adding custom property to webpart with a custom toolpart - sharepoint-2007

I'm trying to add a custom property to my webpart as below:
[Personalizable(PersonalizationScope.Shared)]
[WebBrowsable(true)]
[System.ComponentModel.Category("Settings")]
[WebDisplayName("RSS List Path")]
[WebDescription("")]
public string RSSListURL
{
get
{
if (_myListURL == null)
{
_myListURL = "http://server2003dev/dev/";
}
return _myListURL;
}
set { _myListURL = value; }
}
But within the webpart I am also overriding the GetToolParts() method as below with my own custom toolpart:
public override ToolPart[] GetToolParts()
{
return new ToolPart[] { new RSSCountrySettings(), new WebPartToolPart() };
}
I need to display my custom toolpart (RSSCountrySettings) and my custom propery (RSS List Path) under the catergory Settings.
Any ideas how I do this, I able to only get one but not both to display...?

You are not using the base class's toolparts. Try this instead:
public override ToolPart[] GetToolParts()
{
var result = new List<ToolPart>() ;
var toolparts = base.GetToolParts();
result.AddRange(toolparts.ToList());
result.Add(new WebPartToolPart());
return result.ToArray();
}
The reason you need to do this is that the base class generates a toolpart for your custom property. However, you do not allow it to add that toolpart to the toolpart collection. So, you must get the base class's toolparts as a collection, then add yours in there as well. That's the danger in overriding an existing method. Check this link out for more info

You have to add CustomPropertyToolPart to toolParts list. Like this:
public override Microsoft.SharePoint.WebPartPages.ToolPart[] GetToolParts()
{
List<ToolPart> list = new List<ToolPart>();
list.AddRange(base.GetToolParts());
// adds custom controls
result.Add(new WebPartToolPart());
// adds default controls for properties marked with [WebBrowsable(true)]
list.Add(new CustomPropertyToolPart());
return list.ToArray();
}

Related

How to assign default value for dropdown list in Umbraco?

I have created custom data type based on built-in dropdown list, but cannot figure out how to specify default value for the list. The default value is always blank:
The default dropdown does not support default value
There is two way of achieving what you want
create your own dropdown datatype (or use a plugin someone else has made - I am not sure which one support it, but maybe have a look at nuPickers )
since it is your custom made you can control it. More about how to create one checkout doc Tutorial - Creating a property editor
use a web api handler to intercept the call of getting the content value - and set a default value to your property if it is empty (null)
below is some un-tested code:
first create the web api handler
public class SetDropdownDefaultHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync
(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
var url = request?.RequestUri?.AbsolutePath.ToLower;
// only process when a create (getempty) or editing a specific content (getbyid)
if (url == "/umbraco/backoffice/umbracoapi/content/getempty"
|| url == "/umbraco/backoffice/umbracoapi/content/getbyid")
{
var content = (ObjectContent)response.Content;
var data = content?.Value as PagedResult<ContentItemBasic<ContentPropertyBasic, IContent>>;
if (data?.Items != null)
{
var tempResult = data?.Items?.ToList();
foreach (var item in tempResult)
{
foreach (var prop in item?.Properties?.Where(p => p?.Editor == "Umbraco.DropDown"))
{
var propStr = prop.Value?.ToString();
if (!propStr.IsNullOrWhiteSpace())
{
// set your default value if it is empty
prop.Value = "your default option prevalue id";
}
}
}
data.Items = tempResult;
}
}
return response;
}
}
then register it at started event
public class UmbracoEvent : ApplicationEventHandler
{
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
GlobalConfiguration.Configuration.MessageHandlers.Add(new SetDropdownDefaultHandler());
}
}
your problem maybe you don't know your prevalueid - you can look it up in db or you could use datatype service to get the datatype prevalues then decide which to put as default
Look at: FieldType.DropDownList in the fieldTypes folder.
Replace:<option value=""></option>
With:
var settings = Model.AdditionalSettings;
<option value="">#settings["DefaultValue"]</option>
Then ensure you set the default value property in your dropdown list in the Umbraco Forms backoffice for the given form

MVVMCross ListView - how to populate only with the list items matches certain conditions?

MVVMCross ListView - How to display a list of items in a listview grouped by a status? For exampled activate or deactivated
I have added two listview to the layout and set the datasource to have two lists (activatedItems and deactivatedItems => both of them derived from ListOfItems. ) using the xaml data binding with now code behind. But had a problem in the data not updated when there is a change to the underlying list (ListOfItems).
To resolve this, I have to re create the UI by setting the content view whenever there a change to the data set.
This is not an elegant solution and I would like to have one listview with sections "Activated" and "Deactivated". Then on touching the Activated item should get added to the Deactivated list and the UI should reflect the same.
Since you have a LoginItemModel with a Title property (let's assume it's a string property), I would recommend you to extract this to an ILoginItemModel interface and also add a bool IsHeader property. This way:
public interface ILoginItemModel {
public bool IsHeader { get; }
public LoginSection ItemGroup { get; }
public string Title { get; }
}
Make your LoginItemModel extend this ILoginItemModel interface and make IsHeader always return false.
public bool IsHeader => false;
Write a second class extending this same interface, let's call it LoginItemHeaderModel. This class will just have these three properties:
public class LoginItemHeaderModel : ILoginItemModel {
public bool IsHeader => true;
LoginSection _itemGroup;
public LoginSection ItemGroup => _itemGroup;
string _title;
public string Title => _title;
public LoginItemHeaderModel(LoginSection itemGroup, string title) {
_itemGroup = itemGroup;
_title = title;
}
}
Now we have two models that fits into a single IList<ILoginItemModel>.
Back to your view model, you can declare a fourth list property and put it all together along with your new headers:
public List<ILoginItemModel> SectionedLoginItems {
get {
var values = Enum.GetValues(typeof(LoginSection)).Cast<LoginSection>();
List<ILoginItemModel> list = new List<ILoginItemModel>();
foreach (LoginSection loginSection : values) {
list.Add(new LoginItemHeaderModel(loginSection, loginSection.ToString()));
list.AddRange(LoginItems.Where(l => l.ItemGroup == loginSection));
}
return list;
}
}
Now you have your single sorted and with section headers list.
You should now write a new layout for those header items (aren't you going to make them look like the common items, right?) and, in your custom MvxAdapter, inside the GetBindableView method, check whether the object source (which will be an ILoginItemModel object) is a header item or not.
Whenever you make a change to ActiveLoginItems or DeactivatedLoginItems, make a call to RaisePropertyChanged in your ViewModel i.e.
RaisePropertyChanged(() => ActiveLoginItems);
or
RaisePropertyChanged(() => DeactivatedLoginItems);
That should make the MvxListView update with the changes.

Simple getter logic in ViewModels

Is it ok to have simple logic (without any dependencies) in ViewModels getters or it should contain just automatic properties? in this case just checking for null so I don't have to do that in controller each time I am using this ViewModel. TicketSearchParameters is a simple model containing string and date properties, there is no Repository or any other dependencies.
public class MyViewModel
{
private TicketSearchParameters _searchParams;
public TicketSearchParameters SearchParams
{
get
{
if (_searchParams == null)
{
_searchParams = new TicketSearchParameters();
_searchParams.CreatedFrom = DateTime.Now.AddDays(-7);
_searchParams.CreatedTo = DateTime.Now;
}
return _searchParams;
}
set
{
_searchParams = value;
}
}
/*** other properties ***/
}
You code is fairly ok. But you can use NULL Object Design Pattern to check null and create NullObject.
make a class named NullSearchParams inherited from SearchParams and initialize it when needed.
You can see Null design pattern documentation here.
https://sourcemaking.com/design_patterns/null_object

WP7 Insert all linq results in an ObservableCollection

I parse an xml results from a webservice using linq :
XElement items = XElement.Parse(e.Result);
MyListBox.ItemsSource = from item in items.Descendants("node")
select new MyViewModel
{
...
};
This automatically populate my ListBox. But the problem is, I usually access my ObservableCollection like this :
App.MyViewModel.MyItems;
having in my xaml :
ItemsSource="{Binding MyItems,}"
How can I modify directly my ObservableCollection ? I read Cast LINQ result to ObservableCollection
and tried this :
var v = from item in items.Descendants("node")
select new MyViewModel
{
...
};
OApp.MyViewModel.MyItems = new ObservableCollection<MyViewModel>(v);
But I can't since this in WP7 (Silverlight 3), and there is no constructor like this
Thanks !
I'd just invent a static method like this:-
public static ObservableCollection<T> CreateObservableCollect<T>(IEnumerable<T> range)
{
var result = new ObservableCollection<T>();
foreach (T item in range)
{
result.Add(item);
}
return result;
}
Now your last line of code becomes:-
OApp.MyViewModel.MyItems = new CreateObservableCollection<MyViewModel>(v);
The constructor you're trying to use is in Silverlight, just not available on the phone. (as per MSDN)
Unfortunately, you'll have to populate your ObservableCollection yourself.
Do you need ObservableCollection? Do you need add or delete objects from collection or just update?
If only update, you can change MyViewModel.MyItems to:
public MyTypeOfCollection MyItems
{
get { return _myItems; }
set
{
_myItems = value;
OnNotifyPropertyChanged("MyItems");//invoke INotifyPropertyChanged.PropertyChanged
}
}
If you need adding or deleting of items, you can extend your collection to:
public static class Extend
{
// Extend ObservableCollection<T> Class
public static void AddRange(this System.Collections.ObjectModel.ObservableCollection o, T[] items)
{
foreach (var item in items)
{
o.Add(item);
}
}
}

How to get and set http headers in an Action, the testable way

I have an action that returns either a FileContentResult or a NotModifiedResult, which is a custom result type that returns HTTP 304 to indicate that the requested resource has not been modified, like this:
[ReplaceMissingPicture(Picture = "~/Content/Images/nothumbnail.png", MimeType = "image/png")]
public ActionResult Thumbnail(int id)
{
var item = Service.GetItem(id);
var requestTag = Request.Headers["If-None-Match"] ?? string.Empty;
var tag = Convert.ToBase64String(item.Version.ToArray());
if (tag == requestTag)
{
return new NotModifiedResult();
}
if (item.Thumbnail != null)
{
var thumbnail = item.Thumbnail.ToArray();
var mime = item.PictureMime;
Response.AppendHeader("ETag", tag);
return File(thumbnail, mime);
}
else
{
return null;
}
}
This action needs to access the Response object, which is of course not present during testing, so that makes this action untestable. I could add conditional statements around it, so that it runs during testing, but then I can't test for the headers being set correctly.
What would be a solution to this problem?
FYI, the ReplaceMissingPicture filter returns a specific resource in case null was returned from this action, to keep the MapPath() call out of the controller for the very same reason.
The first step would be to create an interface which simplifies the services you need:-
public interface IHeaders
{
public string GetRequestHeader(string headerName);
public void AppendResponseHeader(string headerName, string headerValue);
}
Now create a default implementation:-
public Headers : IHeaders
{
public string GetRequestHeader(string headerName)
{
return HttpContext.Current.Request[headerName];
}
public void AppendResponseHeader(string headerName, string headerValue)
{
HttpContext.Current.Response.AppendHeader(headerName, headerValue);
}
}
Now add a new field to your Controller:-
private IHeaders myHeadersService;
add new constructor to you controller:-
public MyController(IHeaders headersService)
{
myHeadersService = headersService;
}
modify or add the default constructor:-
public MyController()
{
myHeadersService = new Headers();
}
now in your Action code use myHeadersService instead of the Response and Request objects.
In your tests create your own implementation of the IHeaders interface to emulate/test the Action code and pass that implementation when constructing the Controller.
How about creating a subclass of FileResult--say ETagFileResult--that in its ExecuteResult() method sets the ETag header, and then defaults to the base class implementation? You can test that class with a mocked context (as you presumably are with your NotModifiedResult) to be sure that it's doing the right thing. And remove the entire complication from the testing of the controller.
Failing that, it's possible to set a mocked context on the controller in your test (after instantiating the class, before calling the action method). See this question, for instance. But that seems like more work.
(Also, by the way, it looks like you're quoting the tag value twice there: once when tag is set, and once more when you actually set the header....)

Resources