Change text of “Cancel” button on a UISearchBar using Monotouch? - c#

I need to change the text of the Cancel button to always display "Reset" in my app.
I found many similar questions here on SO, but all answers are for ObjC, while I am working in Monotouch.

Use the extension method below for iOS7+ like this: searchBar.SetCancelTitle("close");
It derives from Kolbjørn Bredrup's comment, which is great, but it wasn't clear to me what the namespaces were for the additional extension methods that it uses internally (OfType and FirstOrDefault) so I added them to this class myself.
I also renamed the class UISearchBarExtensions so that it sat nicely with my other ones.
Thanks to Kolbjørn Bredrup for the original!
As with the original, it is called using:
searchBar.SetCancelTitle("close");
public static class UISearchBarExtensions
{
/// <summary>
/// Finds the Cancelbutton
/// </summary>
/// <returns></returns>
public static UIButton GetCancelButton(this UISearchBar searchBar)
{
//Look for a button, probably only one button, and that is probably the cancel button.
return (UIButton)searchBar.GetAllSubViews().OfType<UIButton>().FirstOrDefault();
}
public static UIView FirstOrDefault(this IEnumerable<UIView> views)
{
return ((List<UIView>)views)[0];
}
public static IEnumerable<UIView> OfType<T>(this IEnumerable<UIView> views)
{
List<UIView> response = new List<UIView>();
foreach(var view in views)
{
if(view.GetType() == typeof(T))
{
response.Add(view);
}
}
return response;
}
/// <summary>
/// Recursively traverses all subviews and returns them in a little list.
/// </summary>
/// <param name="view"></param>
/// <returns></returns>
public static IEnumerable<UIView> GetAllSubViews(this UIView view)
{
List<UIView> retList = new List<UIView>();
retList.AddRange(view.Subviews);
foreach (var subview in view.Subviews)
{
retList.AddRange(subview.GetAllSubViews());
}
return retList;
}
/// <summary>
/// Sets the title of the search bars cancel button
/// </summary>
/// <param name="searchBar"></param>
/// <param name="cancelTitle"></param>
public static void SetCancelTitle(this UISearchBar searchBar, string cancelTitle)
{
searchBar.GetCancelButton().SetTitle(cancelTitle, UIControlState.Normal);
}
}

Note that the subview hierarchy is different in ios6 and ios7.
But by adding the extension method below you can use
searchBar.SetCancelTitle("NO!");
Extension method that works in ios7 and ios5/ios6:
public static class NimbleSearchBarExtensions
{
/// <summary>
/// Finds the Cancelbutton
/// </summary>
/// <returns></returns>
public static UIButton GetCancelButton(this UISearchBar searchBar)
{
//Look for a button, probably only one button, and that is probably the cancel button.
return searchBar.GetAllSubViews().OfType<UIButton>().FirstOrDefault();
}
/// <summary>
/// Recursively traverses all subviews and returns them in a little list.
/// </summary>
/// <param name="view"></param>
/// <returns></returns>
public static IEnumerable<UIView> GetAllSubViews(this UIView view)
{
List<UIView> retList = new List<UIView>();
retList.AddRange(view.Subviews);
foreach (var subview in view.Subviews)
{
retList.AddRange(subview.GetAllSubViews());
}
return retList;
}
/// <summary>
/// Sets the title of the search bars cancel button
/// </summary>
/// <param name="searchBar"></param>
/// <param name="cancelTitle"></param>
public static void SetCancelTitle(this UISearchBar searchBar, string cancelTitle)
{
searchBar.GetCancelButton().SetTitle(cancelTitle,UIControlState.Normal);
}
}

It was very easy -
UIButton btnCancel = (UIButton)SearchBar.Subviews[3];
btnCancel.SetTitle ("test", UIControlState.Normal);

Related

Custom Checkbox Default Text Binding on Xamarin

I have a custom Checkbox is implemented as below;
public class CheckBox : View, INotifyPropertyChanged
{
/// <summary>
/// The checked state property.
/// </summary>
public static readonly BindableProperty CheckedProperty =
BindableProperty.Create<CheckBox, bool>(
p => p.Checked, false, BindingMode.TwoWay, propertyChanged: OnCheckedPropertyChanged);
/// <summary>
/// The checked text property.
/// </summary>
public static readonly BindableProperty CheckedTextProperty =
BindableProperty.Create<CheckBox, string>(
p => p.CheckedText, string.Empty, BindingMode.TwoWay);
/// <summary>
/// The unchecked text property.
/// </summary>
public static readonly BindableProperty UncheckedTextProperty =
BindableProperty.Create<CheckBox, string>(
p => p.UncheckedText, string.Empty);
/// <summary>
/// The default text property.
/// </summary>
public static readonly BindableProperty DefaultTextProperty =
BindableProperty.Create<CheckBox, string>(
p => p.Text, string.Empty,BindingMode.TwoWay, propertyChanged: OnDefaultTextChanged);
/// <summary>
/// Identifies the TextColor bindable property.
/// </summary>
///
/// <remarks/>
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create<CheckBox, Color>(
p => p.TextColor, Color.Default);
/// <summary>
/// The font size property
/// </summary>
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create<CheckBox, double>(
p => p.FontSize, -1);
/// <summary>
/// The font name property.
/// </summary>
public static readonly BindableProperty FontNameProperty =
BindableProperty.Create<CheckBox, string>(
p => p.FontName, string.Empty);
/// <summary>
/// The checked changed event.
/// </summary>
public event EventHandler<EventArgs<bool>> CheckedChanged;
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Gets or sets a value indicating whether the control is checked.
/// </summary>
/// <value>The checked state.</value>
public bool Checked
{
get
{
return this.GetValue<bool>(CheckedProperty);
}
set
{
if (this.Checked != value)
{
this.SetValue(CheckedProperty, value);
this.CheckedChanged.Invoke(this, value);
}
}
}
/// <summary>
/// Gets or sets a value indicating the checked text.
/// </summary>
/// <value>The checked state.</value>
/// <remarks>
/// Overwrites the default text property if set when checkbox is checked.
/// </remarks>
public string CheckedText
{
get
{
return this.GetValue<string>(CheckedTextProperty);
}
set
{
this.SetValue(CheckedTextProperty, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether the control is checked.
/// </summary>
/// <value>The checked state.</value>
/// <remarks>
/// Overwrites the default text property if set when checkbox is checked.
/// </remarks>
public string UncheckedText
{
get
{
return this.GetValue<string>(UncheckedTextProperty);
}
set
{
this.SetValue(UncheckedTextProperty, value);
}
}
/// <summary>
/// Gets or sets the text.
/// </summary>
public string DefaultText
{
get
{
return this.GetValue<string>(DefaultTextProperty);
}
set
{
this.SetValue(DefaultTextProperty, value);
NotifyPropertyChanged("DefaultTextProperty");
NotifyPropertyChanged("DefaultText");
}
}
/// <summary>
/// Gets or sets the color of the text.
/// </summary>
/// <value>The color of the text.</value>
public Color TextColor
{
get
{
return this.GetValue<Color>(TextColorProperty);
}
set
{
this.SetValue(TextColorProperty, value);
}
}
/// <summary>
/// Gets or sets the size of the font.
/// </summary>
/// <value>The size of the font.</value>
public double FontSize
{
get
{
return (double)GetValue(FontSizeProperty);
}
set
{
SetValue(FontSizeProperty, value);
}
}
/// <summary>
/// Gets or sets the name of the font.
/// </summary>
/// <value>The name of the font.</value>
public string FontName
{
get
{
return (string)GetValue(FontNameProperty);
}
set
{
SetValue(FontNameProperty, value);
}
}
/// <summary>
/// Gets the text.
/// </summary>
/// <value>The text.</value>
public string Text
{
get
{
return this.Checked
? (string.IsNullOrEmpty(this.CheckedText) ? this.DefaultText : this.CheckedText)
: (string.IsNullOrEmpty(this.UncheckedText) ? this.DefaultText : this.UncheckedText);
}
}
/// <summary>
/// Called when [checked property changed].
/// </summary>
/// <param name="bindable">The bindable.</param>
/// <param name="oldvalue">if set to <c>true</c> [oldvalue].</param>
/// <param name="newvalue">if set to <c>true</c> [newvalue].</param>
private static void OnCheckedPropertyChanged(BindableObject bindable, bool oldvalue, bool newvalue)
{
var checkBox = (CheckBox)bindable;
checkBox.Checked = newvalue;
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I have default text bindable property, that I want to set the value from coming web service via Binding.
The code I tried on Xaml is as below;
<uikit:CheckBox x:Name="CheckBox" WidthRequest="250" HeightRequest="100" FontSize="13" DefaultText="{Binding FirstText,Mode=TwoWay}" CheckedChanged="CheckBox_Clicked" TextColor="#263238" />
I am not able to do so... I tried setting Binding Context in both Xaml and Codebehind.
What am I doing wrong?
Could you please help me?
I have also added PropertyChanged Event Handler, my updated code is as above. It still does not update.
BR,
add this at end
public void RaiseCheckedChanged (bool val)
{
if (CheckedChanged != null)
CheckedChanged (this, new EventArgs<bool> (val));
}
and add this class in same file
public class EventArgs<T> : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="EventArgs"/> class.
/// </summary>
/// <param name="value">Value of the argument</param>
public EventArgs(T value)
{
this.Value = value;
}
/// <summary>
/// Gets the value of the event argument
/// </summary>
public T Value { get; private set; }
}
public static class BindableObjectExtensions
{
/// <summary>
/// Gets the value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="bindableObject">The bindable object.</param>
/// <param name="property">The property.</param>
/// <returns>T.</returns>
public static T GetValue<T>(this BindableObject bindableObject, BindableProperty property)
{
return (T)bindableObject.GetValue(property);
}
}
public static class EventExtensions
{
/// <summary>
/// Raise the specified event.
/// </summary>
/// <param name="handler">Event handler.</param>
/// <param name="sender">Sender object.</param>
/// <param name="value">Argument value.</param>
/// <typeparam name="T">The value type.</typeparam>
public static void Invoke<T>(this EventHandler<EventArgs<T>> handler, object sender, T value)
{
var handle = handler;
if (handle != null)
{
handle(sender, new EventArgs<T>(value));
}
}
/// <summary>
/// Tries the invoke.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="handler">The handler.</param>
/// <param name="sender">The sender.</param>
/// <param name="args">The arguments.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
public static bool TryInvoke<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs
{
var handle = handler;
if (handle == null) return false;
handle(sender, args);
return true;
}
}

How to move through all controls inside controls in Asp.Net WebForm?

How to move through all controls inside Panel Web Control or any other control?
control.FindControls("name") finds only controls in the same level only
below is an answer with high speed and lower resources with multitasking
/// <summary>
/// Start from Control and move through all inside controls to check if can execute and
/// execute ctrlAction if canExecute results true
/// </summary>
/// <typeparam name="T">
/// Any Control or object inherits System.Web.UI.Control
/// </typeparam>
/// <param name="ctrl">
/// the System.Web.UI.Control to traverse from and inside
/// </param>
/// <param name="ctrlAction">
/// the action to execute on the valid control
/// </param>
/// <param name="canExecute">
/// to check if the current reached control is valid for ctrlAction execution
/// </param>
public static void ExApply<T>(
this Control ctrl, Action<T> ctrlAction, Predicate<T> canExecute = null) where T : Control
{
// if ctrl is null return null
if (ctrl == null) { return; }
// to handle multitasking on the valid controls
LinkedList<Task> taskList = new LinkedList<Task>();
// start control traverse through all controls from and inside
ctrl._exApply(canExecute, ctrlAction, taskList);
// Waiting not finished, clean and clear resources
taskList._exWaitAndDispose();
}
/// <summary>
/// Start from ControlCollection and move through all inside controls to check if can execute and
/// execute ctrlAction if canExecute results true
/// </summary>
/// <typeparam name="T">
/// Any Control or object inherits System.Web.UI.Control
/// </typeparam>
/// <param name="ctrls">
/// the System.Web.UI.ControlCollection to traverse from and inside
/// </param>
/// <param name="ctrlAction">
/// the action to execute on the valid control
/// </param>
/// <param name="canExecute">
/// to check if the current reached control is valid for ctrlAction execution
/// </param>
public static void ExApply<T>(
this ControlCollection ctrls, Action<T> ctrlAction, Predicate<T> canExecute = null)
where T : Control
{
// if ctrls is null return null
if (ctrls == null) { return; }
// to handle multitasking on the valid controls
LinkedList<Task> taskList = new LinkedList<Task>();
// start control traverse through all controls from and inside
ctrls._exApply(canExecute, ctrlAction, taskList);
// Waiting not finished, clean and clear resources
taskList._exWaitAndDispose();
}
private static void _exApply<T>(
this Control ctrl, Predicate<T> canExecute, Action<T> ctrlAction, LinkedList<Task> taskList)
where T : Control
{
// if ctrl is null no more moves needed
if (ctrl == null) { return; }
// if ctrl can be casted and has no empty id
if ((ctrl is T castedCtrl) && castedCtrl.ID.ExIsNotNone())
{
// if canExecute is null or returned true result
if (canExecute == null || (canExecute != null && canExecute(castedCtrl)))
{
// add castedCtrl as an asynchronous task
taskList.AddLast(Task.Run(() => ctrlAction(castedCtrl)));
// check first node task if completed to remove and dispose
taskList._exDisposeFirsts();
}
}
// move more deep into inside controls
if (ctrl.Controls != null && ctrl.Controls.Count > 0)
{
ctrl.Controls._exApply(canExecute, ctrlAction, taskList);
}
}
private static void _exApply<T>(
this ControlCollection ctrls, Predicate<T> canExecute, Action<T> ctrlAction,
LinkedList<Task> taskList) where T : Control
{
for (int index = 0; index < ctrls.Count; index++)
{
// move through control to validate and apply ctrlAction
ctrls[index]?._exApply(canExecute, ctrlAction, taskList);
}
}
private static void _exDisposeFirsts(this LinkedList<Task> taskList)
{
while (taskList.Count > 0 && taskList.First.Value.IsCompleted)
{
taskList.First.Value.Dispose();
taskList.RemoveFirst();
}
}
private static void _exWaitAndDispose(this LinkedList<Task> taskList)
{
taskList._exDisposeFirsts();
if (taskList.Count < 1) { return; }
Task[] tasks = new Task[taskList.Count];
taskList.CopyTo(tasks, 0);
taskList.Clear();
Task.WaitAll(tasks);
tasks.ExDispose();
}
/// <summary>
/// Smaller Size name and usage from "string.IsNullOrWhiteSpace(text)" Indicates whether a
/// specified string is null, empty, or consists only of white-space characters.
/// </summary>
/// <param name="text">The string to test</param>
/// <returns>
/// true if the value parameter is null or System.String.Empty, or if value consists
/// exclusively of white-space characters.
/// </returns>
public static bool ExIsNone(this string text) => string.IsNullOrWhiteSpace(text);
/// <summary>
/// Smaller Size name and usage from "!string.IsNullOrWhiteSpace(text)" Indicates whether a
/// specified string is not null, not empty, or not consists only of white-space characters.
/// </summary>
/// <param name="text">The string to test</param>
/// <returns>
/// true if the value parameter is not null or not System.String.Empty, or if value not consists
/// exclusively of white-space characters.
/// </returns>
public static bool ExIsNotNone(this string text) => text.ExIsNone().ExIs(false);
/// <summary>
/// Use for easier code reading instead of inverse ! character and ambiguous names
/// </summary>
/// <param name="value">value to test</param>
/// <param name="compareValue">value to compare with</param>
/// <returns>true is equal otherwise false</returns>
public static bool ExIs(this bool value, bool compareValue) => value == compareValue;

RadGrid Wrapper Passing a NeedDataSource callback

I am attempting to write a simple helper class that will make managing Telerik RadGrids in our application consistent.
The relevant portions of the class are shown below:
public delegate object NeedDataSource(object aSender);
public class TelerikGridViewHelper
{
private readonly string _CommandNameDelete; //String checked for in ItemCommand to determine if we have a delete button click
private readonly string _CommandNameEdit; //String checked for in ItemCommand to determine if we have a edit button click
private readonly RadGrid _GridView;
private NeedDataSource _NeedDataSourceCallBack;
private RecordDelete _RecordDeleteCallback;
private RecordEdit _RecordEditCallback;
/// <summary>
/// Class constructor
/// </summary>
/// <param name="aGridView"></param>
public TelerikGridViewHelper(RadGrid aGridView)
{
//Save params supplied
_GridView = aGridView;
//Create resources required
_CommandNameDelete = Guid.NewGuid() + "_Delete";
_CommandNameEdit = Guid.NewGuid() + "_Edit";
Options = new TelerikGridViewHelperOptions();
}
/// <summary>
/// Defines how the grid view will be configured when the Configure() method is called.
/// </summary>
public TelerikGridViewHelperOptions Options { get; set; }
/// <summary>
/// Call this method after setting the appropriate Options to configure the grid view behaviours.
/// </summary>
/// <param name="aKeyFieldNames">List of fields that uniquely identify each record.</param>
/// <param name="aNeedDataSourceCallback">Method returning the contents of the datasource to be displayed by the grid.</param>
/// <param name="aRecordDeleteCallback">Called when a record is to be deleted as a consequence of the user pressing the Delete button automatically added by this class when Options.CommandDelete is true.</param>
/// <param name="aRecordEditCallback">Called when a record is to be edit as a consequence of the user pressing the Edit button automatically added by this class when Options.CommandEdit is true.</param>
public void Configure(string[] aKeyFieldNames, NeedDataSource aNeedDataSourceCallback, RecordDelete aRecordDeleteCallback, RecordEdit aRecordEditCallback)
{
//Save / Apply the parameters supplied
//Datasource
_NeedDataSourceCallBack = aNeedDataSourceCallback;
_RecordDeleteCallback = aRecordDeleteCallback;
_RecordEditCallback = aRecordEditCallback;
//Key fields
_GridView.MasterTableView.DataKeyNames = aKeyFieldNames;
//Now configure the grid based on the configured behaviours
ConfigureGrid(_GridView, Options);
}
/// <summary>
/// Internal helper method to configure the various aspects of the grid based on the options specified.
/// </summary>
/// <param name="aGridView">Gridview to configure.</param>
/// <param name="aOptions">Options to use when configuring the grid.</param>
private void ConfigureGrid(RadGrid aGridView, TelerikGridViewHelperOptions aOptions)
{
//Grid Options
aGridView.AllowFilteringByColumn = aOptions.Filtering;
aGridView.AllowPaging = aOptions.Paging;
aGridView.AutoGenerateColumns = aOptions.AutoGenerateColumns;
aGridView.AutoGenerateHierarchy = true;
aGridView.EnableHeaderContextMenu = true;
aGridView.GroupPanelPosition = GridGroupPanelPosition.Top;
aGridView.Skin = aOptions.ThemeName;
//Table view options
aGridView.MasterTableView.PagerStyle.AlwaysVisible = true;
aGridView.MasterTableView.PagerStyle.Position = GridPagerPosition.TopAndBottom;
aGridView.MasterTableView.PageSize = aOptions.PageSize;
//Events hookup
_GridView.NeedDataSource += CustomGridViewOnNeedDataSource;
}
/// <summary>
/// Hooked to the managed grid view's OnNeedDataSource event. We use this to call what the developer has supplied for
/// the datasource callback.
/// </summary>
/// <param name="aSender">Gridview instance that has fired this event</param>
/// <param name="aEventArgs">Contains the information about the need for the rebind of the datasource.</param>
private void CustomGridViewOnNeedDataSource(object aSender, GridNeedDataSourceEventArgs aEventArgs)
{
(aSender as RadGrid).DataSource = _NeedDataSourceCallBack;
}
/// <summary>
/// Internal helper method to raise the exception class associated with this class
/// </summary>
/// <param name="aExceptionMessage">Message to use when raising the exception.</param>
private void RaiseException(string aExceptionMessage)
{
throw new TelerikGridViewHelperException(aExceptionMessage);
}
}
The class is then invoked from code behind as follows:
public partial class TimeSheetList : BasePage
{
private readonly TimeSheetProcess _TimeSheetProcess;
/// <summary>
/// Class constructor
/// </summary>
public TimeSheetList()
{
_TimeSheetProcess = new TimeSheetProcess();
}
/// <summary>
/// Called when the page is loaded
/// </summary>
/// <param name="aSender"></param>
/// <param name="aEventArgs"></param>
protected void Page_Load(object aSender, EventArgs aEventArgs)
{
TelerikGridViewHelper gridViewHelper = new TelerikGridViewHelper(RadGrid2);
gridViewHelper.Configure(new []{"TimeSheetId"}, DataRetrieve, null, null);
}
private object DataRetrieve(object aSender)
{
//List of timesheets ordered by date and then user within that
DateTime todaysDate = DateTime.Now;
//List of page contents ordered by url
List<Timesheet> timesheetsFromDb = _TimeSheetProcess.GetTimeSheets()
.ToList();
MembershipCache membershipCache = new MembershipCache();
ClockedInBrowseViewModel timesheetsViewModel = new ClockedInBrowseViewModel();
foreach (Timesheet timeSheet in timesheetsFromDb)
{
MembershipUser userInfo = membershipCache.GetUserById(timeSheet.UserId.ToString());
timesheetsViewModel.Items.Add(new ClockedInItemViewModel
{
ClockedInAt = timeSheet.Start.HasValue ? string.Format("{0:dd MMM HH:mm}", timeSheet.Start) : "-",
ClockedOutAt = timeSheet.Finish.HasValue ? string.Format("{0:dd MMM HH:mm}", timeSheet.Finish) : "-",
TimesheetId = timeSheet.TimesheetID,
Username = userInfo.UserName
});
}
return timesheetsViewModel.Items;
}
}
Now the issue that I am having is that the passed in TimeSheetList.DataRetrieve() is not being called and I get the exception "Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource" as soon as the line "(aSender as RadGrid).DataSource = _NeedDataSourceCallBack;" is hit in the helper class. So I am guessing that I have not setup either the hooking on the NeedDataSource event or how the callback is invoked as I know that DataRetrieve() is returning a suitable list of objects.
Can someone point me in the right direction please?
Needed to call Invoke() as follows:
(aSender as RadGrid).DataSource = _NeedDataSourceCallBack.Invoke(aSender);

PRISM 5 MEF AvalonDock 2.0 DataAdapter Registered Views and Parent IsSelected

I am attempting to build an MVVM Windows Application Using PRISM 5 and I have wrapped my main content window with an AvalonDock (Wrapping Code Below).
using Microsoft.Practices.Prism.Regions;
using Xceed.Wpf.AvalonDock;
using System.Collections.Specialized;
using System.Windows;
using Xceed.Wpf.AvalonDock.Layout;
namespace Central.Adapters
{
using System.Linq;
public class AvalonDockRegionAdapter : RegionAdapterBase<DockingManager>
{
/// <summary>
/// This ties the adapter into the base region factory.
/// </summary>
/// <param name="factory">The factory that determines where the modules will go.</param>
public AvalonDockRegionAdapter(IRegionBehaviorFactory factory)
: base(factory)
{
}
/// <summary>
/// Since PRISM does not support the Avalon DockingManager natively this adapter provides the needed support.
/// </summary>
/// <param name="region">This is the region that resides in the DockingManager.</param>
/// <param name="regionTarget">The DockingManager that needs the window added.</param>
protected override void Adapt(IRegion region, DockingManager regionTarget)
{
region.Views.CollectionChanged += (sender, e) =>
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
AddAnchorableDocument(regionTarget, e);
break;
case NotifyCollectionChangedAction.Remove:
break;
}
};
}
/// <summary>
/// This adds the window as an anchorable document to the Avalon DockingManager.
/// </summary>
/// <param name="regionTarget">The DockingManager instance.</param>
/// <param name="e">The new window to be added.</param>
private static void AddAnchorableDocument(DockingManager regionTarget, NotifyCollectionChangedEventArgs e)
{
foreach (FrameworkElement element in e.NewItems)
{
var view = element as UIElement;
var documentPane = regionTarget.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
if ((view == null) || (documentPane == null))
{
continue;
}
var newContentPane = new LayoutAnchorable
{
Content = view,
Title = element.ToolTip.ToString(),
CanHide = true,
CanClose = false
};
documentPane.Children.Add(newContentPane);
}
}
/// <summary>
/// This returns the region instance populated with all of its contents.
/// </summary>
/// <returns>DockingManager formatted region.</returns>
protected override IRegion CreateRegion()
{
return new AllActiveRegion();
}
}
}
I then register this adapter in the bootstrapper this way:
protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
var mappings = base.ConfigureRegionAdapterMappings();
if (mappings == null)
{
return null;
}
mappings.RegisterMapping(typeof(DockingManager), new AvalonDockRegionAdapter(ConfigureDefaultRegionBehaviors()));
return mappings;
}
The problem that I am facing is that other region UI elements will require certain LayoutAnchorable windows to become the active and selected window. The content I am feeding into the LayoutAnchorable object is a ContentControl.
In my View's ViewModel I have a property that I am successfully setting using another UI element's interaction. However I am unable to make the connection from ViewModel(Property) -> ContentContro(View) -> LayoutAnchorable(View's Parent).IsSelected or ,IsActive.
I know how to bind to a parent object but that eats up the property and does not allow me to bind it to the ViewModel property as well. I also have no problem binding to a ViewModel property, but that is useless unless I can get it to set the parent property. I have also attempted View based events. Problem with this is that once the view loads it doe not like calling its own events anymore unless it is caused by user interaction directly with that view.
In short I just want to display the appropriate window when needed based on an interaction in another part of my program. Maybe I am making this more complicated than it needs to be. Any assistance on this would be greatly appreciated.
Thanks
James
As I took a break from the problem at had I looked at it from another perspective. To solve the issue I decided to store the instance of the content panes containing the views into a singleton dictionary class:
using System;
using System.Collections.Generic;
using Xceed.Wpf.AvalonDock.Layout;
namespace Central.Services
{
public class DockinWindowChildObjectDictionary
{
private static Dictionary<string, LayoutAnchorable> _contentPane = new Dictionary<string, LayoutAnchorable>();
private static readonly Lazy<DockinWindowChildObjectDictionary> _instance =
new Lazy<DockinWindowChildObjectDictionary>(()=> new DockinWindowChildObjectDictionary(), true);
public static DockinWindowChildObjectDictionary Instance
{
get
{
return _instance.Value;
}
}
/// <summary>
/// Causes the constructor to be private allowing for proper use of the Singleton pattern.
/// </summary>
private DockinWindowChildObjectDictionary()
{
}
/// <summary>
/// Adds a Content Pane instance to the dictionary.
/// </summary>
/// <param name="title">The title given to the Pane during instantiation.</param>
/// <param name="contentPane">The object instance.</param>
public static void Add(string title, LayoutAnchorable contentPane)
{
_contentPane.Add(title, contentPane);
}
/// <summary>
/// If a window needs to be removed from the dock this should be used
/// to also remove it from the dictionary.
/// </summary>
/// <param name="title">The title given to the Pane during instantiation.</param>
public static void Remove(string title)
{
_contentPane.Remove(title);
}
/// <summary>
/// This will return the instance of the content pane that holds the view.
/// </summary>
/// <param name="title">The title given to the Pane during instantiation.</param>
/// <returns>The views Parent Instance.</returns>
public static LayoutAnchorable GetInstance(string title)
{
return _contentPane[title];
}
}
}
In the adapter I modified this code as follows:
private static void AddAnchorableDocument(DockingManager regionTarget, NotifyCollectionChangedEventArgs e)
{
foreach (FrameworkElement element in e.NewItems)
{
var view = element as UIElement;
var documentPane = regionTarget.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
if ((view == null) || (documentPane == null))
{
continue;
}
var newContentPane = new LayoutAnchorable
{
Content = view,
Title = element.ToolTip.ToString(),
CanHide = true,
CanClose = false
};
DockinWindowChildObjectDictionary.Add(element.ToolTip.ToString(),** newContentPane);
documentPane.Children.Add(newContentPane);
}
}
Then I added the following to the ViewModel to gain the effect I was going after:
public void OnNavigatedTo(NavigationContext navigationContext)
{
var viewParentInstance = DockinWindowChildObjectDictionary.GetInstance("Belt Plan");
viewParentInstance.IsSelected = true;
}
One hurdle done and on to the next. For a base to all the information in this post the ViewSwitchingNavigation.sln included with the PRISM 5.0 download will get you started. If you are wondering about the ConfigureDefaultRegionBehaviors() referenced in the adapter registration I got that from the StockTraderRI_Desktop.sln in the sample downloads.
I hope this post helps someone else that finds themselves in the same pickle this technology sandwich provides.
Sincerely
James

Hub Tiles (In App Tiles) Windows Phone 8.1 (Universal Apps)

Basic Requirement - Displaying In App tiles in Universal Apps.
I have gone through samples of Hub Tiles from the following link Hub Tiles which applies to Windows Phone 7 and 8, 8.1 (Silverlight), but there is no mentioning of windows Phone 8.1 (Universal Applications). Even if i include the assembly separately it throws an error that Microsoft.Phone cannot be resolved.
As a work around I have even downloaded the source of hub Tiles from Windows phone Toolkit Source and resolved the assemblies, modified the templates and edited it accordingly. But I might be missing on some points, Although It is showing as a control in the tool box but it is not even visible when I add it to XAML. I am adding the edited code for all the three files available from the source of the toolkit.
HubTiles.cs
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
using System.Windows;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
namespace Microsoft.Phone.Controls
{
/// <summary>
/// Represents an animated tile that supports an image and a title.
/// Furthermore, it can also be associated with a message or a notification.
/// </summary>
/// <QualityBand>Preview</QualityBand>
[TemplateVisualState(Name = Expanded, GroupName = ImageStates)]
[TemplateVisualState(Name = Semiexpanded, GroupName = ImageStates)]
[TemplateVisualState(Name = Collapsed, GroupName = ImageStates)]
[TemplateVisualState(Name = Flipped, GroupName = ImageStates)]
[TemplatePart(Name = NotificationBlock, Type = typeof(TextBlock))]
[TemplatePart(Name = MessageBlock, Type = typeof(TextBlock))]
[TemplatePart(Name = BackTitleBlock, Type = typeof(TextBlock))]
[TemplatePart(Name = TitlePanel, Type = typeof(Panel))]
public class HubTile : Control
{
/// <summary>
/// Common visual states.
/// </summary>
private const string ImageStates = "ImageState";
/// <summary>
/// Expanded visual state.
/// </summary>
private const string Expanded = "Expanded";
/// <summary>
/// Semiexpanded visual state.
/// </summary>
private const string Semiexpanded = "Semiexpanded";
/// <summary>
/// Collapsed visual state.
/// </summary>
private const string Collapsed = "Collapsed";
/// <summary>
/// Flipped visual state.
/// </summary>
private const string Flipped = "Flipped";
/// <summary>
/// Nofitication Block template part name.
/// </summary>
private const string NotificationBlock = "NotificationBlock";
/// <summary>
/// Message Block template part name.
/// </summary>
private const string MessageBlock = "MessageBlock";
/// <summary>
/// Back Title Block template part name.
/// </summary>
private const string BackTitleBlock = "BackTitleBlock";
/// <summary>
/// Title Panel template part name.
/// </summary>
private const string TitlePanel = "TitlePanel";
/// <summary>
/// Notification Block template part.
/// </summary>
private TextBlock _notificationBlock;
/// <summary>
/// Message Block template part.
/// </summary>
private TextBlock _messageBlock;
/// <summary>
/// Title Panel template part.
/// </summary>
private Panel _titlePanel;
/// <summary>
/// Back Title Block template part.
/// </summary>
private TextBlock _backTitleBlock;
/// <summary>
/// Represents the number of steps inside the pipeline of stalled images
/// </summary>
internal int _stallingCounter;
/// <summary>
/// Flag that determines if the hub tile has a primary text string associated to it.
/// If it does not, the hub tile will not drop.
/// </summary>
internal bool _canDrop;
/// <summary>
/// Flag that determines if the hub tile has a secondary text string associated to it.
/// If it does not, the hub tile will not flip.
/// </summary>
internal bool _canFlip;
#region Source DependencyProperty
/// <summary>
/// Gets or sets the image source.
/// </summary>
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
/// <summary>
/// Identifies the Source dependency property.
/// </summary>
public static readonly DependencyProperty SourceProperty =
DependencyProperty.Register("Source", typeof(ImageSource), typeof(HubTile), new PropertyMetadata(null));
#endregion
#region Title DependencyProperty
/// <summary>
/// Gets or sets the title.
/// </summary>
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
/// <summary>
/// Identifies the Title dependency property.
/// </summary>
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(HubTile), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnTitleChanged)));
/// <summary>
/// Prevents the hub tile from transitioning into a Semiexpanded or Collapsed visual state if the title is not set.
/// </summary>
/// <param name="obj">The dependency object.</param>
/// <param name="e">The event information.</param>
private static void OnTitleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
HubTile tile = (HubTile)obj;
if (string.IsNullOrEmpty((string)e.NewValue))
{
tile._canDrop = false;
tile.State = ImageState.Expanded;
}
else
{
tile._canDrop = true;
}
}
#endregion
#region Notification DependencyProperty
/// <summary>
/// Gets or sets the notification alert.
/// </summary>
public string Notification
{
get { return (string)GetValue(NotificationProperty); }
set { SetValue(NotificationProperty, value); }
}
/// <summary>
/// Identifies the Notification dependency property.
/// </summary>
public static readonly DependencyProperty NotificationProperty =
DependencyProperty.Register("Notification", typeof(string), typeof(HubTile), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnBackContentChanged)));
/// <summary>
/// Prevents the hub tile from transitioning into a Flipped visual state if neither the notification alert nor the message are set.
/// </summary>
/// <param name="obj">The dependency object.</param>
/// <param name="e">The event information.</param>
private static void OnBackContentChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
HubTile tile = (HubTile)obj;
// If there is a new notification or a message, the hub tile can flip.
if ((!(string.IsNullOrEmpty(tile.Notification)) && tile.DisplayNotification)
|| (!(string.IsNullOrEmpty(tile.Message)) && !tile.DisplayNotification))
{
tile._canFlip = true;
}
else
{
tile._canFlip = false;
tile.State = ImageState.Expanded;
}
}
#endregion
#region Message DependencyProperty
/// <summary>
/// Gets or sets the message.
/// </summary>
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
/// <summary>
/// Identifies the Message dependency property.
/// </summary>
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(HubTile), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnBackContentChanged)));
#endregion
#region DisplayNotification DependencyProperty
/// <summary>
/// Gets or sets the flag for new notifications.
/// </summary>
public bool DisplayNotification
{
get { return (bool)GetValue(DisplayNotificationProperty); }
set { SetValue(DisplayNotificationProperty, value); }
}
/// <summary>
/// Identifies the DisplayNotification dependency property.
/// </summary>
public static readonly DependencyProperty DisplayNotificationProperty =
DependencyProperty.Register("DisplayNotification", typeof(bool), typeof(HubTile), new PropertyMetadata(false, new PropertyChangedCallback(OnBackContentChanged)));
#endregion
#region IsFrozen DependencyProperty
/// <summary>
/// Gets or sets the flag for images that do not animate.
/// </summary>
public bool IsFrozen
{
get { return (bool)GetValue(IsFrozenProperty); }
set { SetValue(IsFrozenProperty, value); }
}
/// <summary>
/// Identifies the IsFrozen dependency property.
/// </summary>
public static readonly DependencyProperty IsFrozenProperty =
DependencyProperty.Register("IsFrozen", typeof(bool), typeof(HubTile), new PropertyMetadata(false, new PropertyChangedCallback(OnIsFrozenChanged)));
/// <summary>
/// Removes the frozen image from the enabled image pool or the stalled image pipeline.
/// Adds the non-frozen image to the enabled image pool.
/// </summary>
/// <param name="obj">The dependency object.</param>
/// <param name="e">The event information.</param>
private static void OnIsFrozenChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
HubTile tile = (HubTile)obj;
if ((bool)e.NewValue)
{
HubTileService.FreezeHubTile(tile);
}
else
{
HubTileService.UnfreezeHubTile(tile);
}
}
#endregion
#region GroupTag DependencyProperty
/// <summary>
/// Gets or sets the group tag.
/// </summary>
public string GroupTag
{
get { return (string)GetValue(GroupTagProperty); }
set { SetValue(GroupTagProperty, value); }
}
/// <summary>
/// Identifies the GroupTag dependency property.
/// </summary>
public static readonly DependencyProperty GroupTagProperty =
DependencyProperty.Register("GroupTag", typeof(string), typeof(HubTile), new PropertyMetadata(string.Empty));
#endregion
#region State DependencyProperty
/// <summary>
/// Gets or sets the visual state.
/// </summary>
internal ImageState State
{
get { return (ImageState)GetValue(StateProperty); }
set { SetValue(StateProperty, value); }
}
/// <summary>
/// Identifies the State dependency property.
/// </summary>
private static readonly DependencyProperty StateProperty =
DependencyProperty.Register("State", typeof(ImageState), typeof(HubTile), new PropertyMetadata(ImageState.Expanded, OnImageStateChanged));
/// <summary>
/// Triggers the transition between visual states.
/// </summary>
/// <param name="obj">The dependency object.</param>
/// <param name="e">The event information.</param>
private static void OnImageStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
((HubTile)obj).UpdateVisualState();
}
#endregion
#region Size DependencyProperty
/// <summary>
/// Gets or sets the visual state.
/// </summary>
public TileSize Size
{
get { return (TileSize)GetValue(SizeProperty); }
set { SetValue(SizeProperty, value); }
}
/// <summary>
/// Identifies the State dependency property.
/// </summary>
public static readonly DependencyProperty SizeProperty =
DependencyProperty.Register("Size", typeof(TileSize), typeof(HubTile), new PropertyMetadata(TileSize.Default, OnSizeChanged));
/// <summary>
/// Triggers the transition between visual states.
/// </summary>
/// <param name="obj">The dependency object.</param>
/// <param name="e">The event information.</param>
private static void OnSizeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
HubTile hubTile = (HubTile)obj;
// And now we'll update the width and height to match the new size.
switch (hubTile.Size)
{
case TileSize.Default:
hubTile.Width = 173;
hubTile.Height = 173;
break;
case TileSize.Small:
hubTile.Width = 99;
hubTile.Height = 99;
break;
case TileSize.Medium:
hubTile.Width = 210;
hubTile.Height = 210;
break;
case TileSize.Large:
hubTile.Width = 432;
hubTile.Height = 210;
break;
}
hubTile.SizeChanged += OnHubTileSizeChanged;
HubTileService.FinalizeReference(hubTile);
}
static void OnHubTileSizeChanged(object sender, SizeChangedEventArgs e)
{
HubTile hubTile = (HubTile)sender;
hubTile.SizeChanged -= OnHubTileSizeChanged;
// In order to avoid getting into a bad state, we'll shift the HubTile
// back to the Expanded state. If we were already in the Expanded state,
// then we'll manually shift the title panel to the right location,
// since the visual state manager won't do it for us in that case.
if (hubTile.State != ImageState.Expanded)
{
hubTile.State = ImageState.Expanded;
VisualStateManager.GoToState(hubTile, Expanded, false);
}
else if (hubTile._titlePanel != null)
{
CompositeTransform titlePanelTransform = hubTile._titlePanel.RenderTransform as CompositeTransform;
if (titlePanelTransform != null)
{
titlePanelTransform.TranslateY = -hubTile.Height;
}
}
HubTileService.InitializeReference(hubTile);
}
#endregion
/// <summary>
/// Updates the visual state.
/// </summary>
private void UpdateVisualState()
{
string state;
// If we're in the Small size, then we should just display the image
// instead of having animations.
if (Size != TileSize.Small)
{
switch (State)
{
case ImageState.Expanded:
state = Expanded;
break;
case ImageState.Semiexpanded:
state = Semiexpanded;
break;
case ImageState.Collapsed:
state = Collapsed;
break;
case ImageState.Flipped:
state = Flipped;
break;
default:
state = Expanded;
break;
}
}
else
{
state = Expanded;
}
VisualStateManager.GoToState(this, state, true);
}
/// <summary>
/// Gets the template parts and sets binding.
/// </summary>
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_notificationBlock = base.GetTemplateChild(NotificationBlock) as TextBlock;
_messageBlock = base.GetTemplateChild(MessageBlock) as TextBlock;
_backTitleBlock = base.GetTemplateChild(BackTitleBlock) as TextBlock;
_titlePanel = base.GetTemplateChild(TitlePanel) as Panel;
//Do binding in code to avoid exposing unnecessary value converters.
if (_notificationBlock != null)
{
Binding bindVisible = new Binding();
bindVisible.Source = this;
bindVisible.Path = new PropertyPath("DisplayNotification");
bindVisible.Converter = new VisibilityConverter();
bindVisible.ConverterParameter = false;
_notificationBlock.SetBinding(TextBlock.VisibilityProperty, bindVisible);
}
if(_messageBlock != null)
{
Binding bindCollapsed = new Binding();
bindCollapsed.Source = this;
bindCollapsed.Path = new PropertyPath("DisplayNotification");
bindCollapsed.Converter = new VisibilityConverter();
bindCollapsed.ConverterParameter = true;
_messageBlock.SetBinding(TextBlock.VisibilityProperty, bindCollapsed);
}
if(_backTitleBlock != null)
{
Binding bindTitle = new Binding();
bindTitle.Source = this;
bindTitle.Path = new PropertyPath("Title");
bindTitle.Converter = new MultipleToSingleLineStringConverter();
_backTitleBlock.SetBinding(TextBlock.TextProperty, bindTitle);
}
UpdateVisualState();
}
/// <summary>
/// Initializes a new instance of the HubTile class.
/// </summary>
public HubTile()
{
DefaultStyleKey = typeof(HubTile);
Loaded += HubTile_Loaded;
Unloaded += HubTile_Unloaded;
}
/// <summary>
/// This event handler gets called as soon as a hub tile is added to the visual tree.
/// A reference of this hub tile is passed on to the service singleton.
/// </summary>
/// <param name="sender">The hub tile.</param>
/// <param name="e">The event information.</param>
void HubTile_Loaded(object sender, RoutedEventArgs e)
{
HubTileService.InitializeReference(this);
}
/// <summary>
/// This event handler gets called as soon as a hub tile is removed from the visual tree.
/// Any existing reference of this hub tile is eliminated from the service singleton.
/// </summary>
/// <param name="sender">The hub tile.</param>
/// <param name="e">The event information.</param>
void HubTile_Unloaded(object sender, RoutedEventArgs e)
{
HubTileService.FinalizeReference(this);
}
}
/// <summary>
/// Represents the visual states of a Hub tile.
/// </summary>
internal enum ImageState
{
/// <summary>
/// Expanded visual state value.
/// </summary>
Expanded = 0,
/// <summary>
/// Semiexpanded visual state value.
/// </summary>
Semiexpanded = 1,
/// <summary>
/// Collapsed visual state value.
/// </summary>
Collapsed = 2,
/// <summary>
/// Flipped visual state value.
/// </summary>
Flipped = 3,
};
/// <summary>
/// Represents the size of a Hub tile.
/// </summary>
public enum TileSize
{
/// <summary>
/// Default size (173 px x 173 px).
/// </summary>
Default,
/// <summary>
/// Small size (99 px x 99 px).
/// </summary>
Small,
/// <summary>
/// Medium size (210 px x 210 px).
/// </summary>
Medium,
/// <summary>
/// Large size (432 px x 210 px).
/// </summary>
Large,
};
}
Note: We can edit the same for HubTileConverters and HubTileService but still it doesnt work.
If any one has a solution or has edited the same for Universal Application Or if there is any Toolkit from Microsoft for the same then please let me know.
TIA.
I have ported the toolkit HubTile stuff. Done with a sample for your refrence please find in the following link.
HubTile sample for universal app
Hope this will help you.
Maybe you should check the Generic.xaml file in toolkit source code, it is placed in Themes folder. All toolkit control default styles are stored in this file. It seems your problem is lack of this style file.
Because HubTile is a custom control, it will read the \Themes\Generic.xaml in solution by using DefaultStyleKey = typeof(HubTile) in its constructor. You should port this file to your solution.

Categories