i am following the sample in the phonetoolkit longlistselector and msdn. I am trying to add the showmore functionality to my application page. Typically like in longlistselector i have authors displayed alphabetical wise and with show more button for each group.
problem:
the problem here is that i am not able to add a new author by pressing show more button, and also i am not able to update this in my longlistselector. I am finding problem adding an author in the Alphakeygroup class(found in the link i mentioned above). how can i do this?
this is my AlphaKeyGroup class
public class AlphaKeyGroup<T> : List<T>
{
/// <summary>
/// The delegate that is used to get the key information.
/// </summary>
/// <param name="item">An object of type T</param>
/// <returns>The key value to use for this object</returns>
public delegate string GetKeyDelegate(T item);
/// <summary>
/// The Key of this group.
/// </summary>
public string Key { get; private set; }
/// <summary>
/// Public constructor.
/// </summary>
/// <param name="key">The key for this group.</param>
public AlphaKeyGroup(string key)
{
Key = key;
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="slg">The </param>
/// <returns>Theitems source for a LongListSelector</returns>
private static List<AlphaKeyGroup<T>> CreateGroups(SortedLocaleGrouping slg)
{
List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>();
foreach (string key in slg.GroupDisplayNames)
{
list.Add(new AlphaKeyGroup<T>(key));
}
return list;
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="items">The items to place in the groups.</param>
/// <param name="ci">The CultureInfo to group and sort by.</param>
/// <param name="getKey">A delegate to get the key from an item.</param>
/// <param name="sort">Will sort the data if true.</param>
/// <returns>An items source for a LongListSelector</returns>
public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
{
SortedLocaleGrouping slg = new SortedLocaleGrouping(ci);
List<AlphaKeyGroup<T>> list = CreateGroups(slg);
foreach (T item in items)
{
int index = 0;
if (slg.SupportsPhonetics)
{
//check if your database has yomi string for item
//if it does not, then do you want to generate Yomi or ask the user for this item.
//index = slg.GetGroupIndex(getKey(Yomiof(item)));
}
else
{
index = slg.GetGroupIndex(getKey(item));
}
if (index >= 0 && index < list.Count)
{
list[index].Add(item);
}
}
if (sort)
{
foreach (AlphaKeyGroup<T> group in list)
{
group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
}
}
return list;
}
}
this is my xaml page. when clicking the showmorebutton here i am sucessfully taken to the execute function in the morecommandclass . how can i add a author in the function and then update it in my longlistselector? basically i am finding it difficult to work with the AlphaKeyGroup class.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector x:Name="AuthorsList" IsGroupingEnabled="true" HideEmptyGroups="True" LayoutMode="List"
ItemsSource="{Binding Authors}"
ListHeaderTemplate="{StaticResource movieListHeader}"
GroupHeaderTemplate="{StaticResource movieGroupHeader}"
ItemTemplate="{StaticResource movieItemTemplate}"
JumpListStyle="{StaticResource MoviesJumpListStyle}">
<!-- The group footer template, for groups in the main list -->
<phone:LongListSelector.GroupFooterTemplate>
<DataTemplate>
<Button DataContext="{Binding}" Content="Show More Records"
Command="{StaticResource moreCommand}" CommandParameter="{Binding}"/>
</DataTemplate>
</phone:LongListSelector.GroupFooterTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
my xaml.cs file
public CategoryFilter()
{
InitializeComponent();
authorsviewmodel = new AuthorsViewModel();
LoadAuthors();
}
private void LoadAuthors()
{
List<Author> movies = new List<Author>();
authorsviewmodel.GetAllAuthors();
var Authorsgroup = AlphaKeyGroup<Author>.CreateGroups(authorsviewmodel.AuthorsList, System.Threading.Thread.CurrentThread.CurrentUICulture, (Author s) => { return s.AuthorName; }, true);
AuthorsList.ItemsSource = Authorsgroup;
}
Morecommands class
public class MoreCommand : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
AlphaKeyGroup<Author> list = parameter as AlphaKeyGroup<Author>;
Author item = new Author();
item.AuthorName = "BAIG123";
list.Add(item);
AuthorsViewModel authorviewmodel=new AuthorsViewModel();
authorviewmodel.Authors = parameter as List<AlphaKeyGroup<Author>>;
authorviewmodel.Authors.Add(list);
}
#endregion
}
The problem is that when you modify a List your view will not get notified of the change.
You can just change class AlphaKeyGroup<T> : List<T> to class AlphaKeyGroup<T> : ObservableCollection<T> and that should fix this problem.
Related
Re-evaluate all values in xaml page calculated by a markup-extension
I try to implement this solution, but I Have a ObservableCollection which contains Title to binding in my listview in my MasterDetails page and it doesn't work. I have really no idea how implement this, but for only one label I did it successful. If someone can help me. Thanks
My list of items :
public ObservableCollection<MainMenuViewItem> MenuItems {
get {
return new ObservableCollection<MainMenuViewItem>(new[]
{
new MainMenuViewItem { Id = 0, Title = Translator.TranslatorInstance["lblHome"], TargetType=typeof(HybridWebView),ViewModelType=HybridViewTypeEnum.Home },
new MainMenuViewItem { Id = 1, Title = Translator.TranslatorInstance["lblListOfDeliverySlip"], TargetType=typeof(HybridWebView),ViewModelType=HybridViewTypeEnum.ListDeliverySlip },
new MainMenuViewItem { Id = 2, Title = Translator.TranslatorInstance["lblSettings"], TargetType=typeof(ParametersView)}
});
}
}
My view
<ListView Grid.Row="1" x:Name="MenuListPage" SeparatorVisibility="None"
HasUnevenRows="true" ItemsSource="{Binding MenuItems}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,10" HorizontalOptions="FillAndExpand">
<Label VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center"
Text="{Binding Title, StringFormat='{0}',Source={x:Static translate:Translator.TranslatorInstance}}"
FontSize="24"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The translationExtension class
/// <summary>
/// Current culture info
/// </summary>
public static CultureInfo CultureInfoApp { get; private set; }
// Path of folder where is store each file language + Name of file without .en ( language code )
private const string ResourceId = "Landauer.Mobile.Ressources.Language.LanguageRessource";
// Instanciation differed of Ressourcemanager
public static readonly Lazy<ResourceManager> RessourceManagerLanguage = new Lazy<ResourceManager>(() => new ResourceManager(ResourceId, IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly));
/// <summary>
/// Match to the name of the label into .resx file
/// </summary>
public string Text { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="text"></param>
public TranslateExtension()
{
if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
{
// Get dependency in each specific platform
CultureInfoApp = DependencyService.Get<ILanguage>().GetCurrentCultureInfo();
}
//Text = text;
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
{
return ProvideValue(serviceProvider);
}
public BindingBase ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding
{
Mode = BindingMode.OneWay,
Path = $"[{Text}]",
Source = Translator.TranslatorInstance,
};
return binding;
}
And finally my translator class:
public static Translator TranslatorInstance => _uniqueInstance;
/// <summary>
/// When TranslateExtension you create new Binding(), call this "Callback"
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public string this[string text]
{
get
{
return TranslateExtension.RessourceManagerLanguage.Value.GetString(text, TranslateExtension.CultureInfoApp);
}
}
/// <summary>
/// Implementation of notifications
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// At each time you set language use this method to refresh UI
/// </summary>
public void Invalidate()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}
You need to set the culture of the resource when you change the language.
Your language instance class should also invoke the property change handler when you set the culture.
so create a method in the instance class like below and call when you change the language settings..
public void SetCultureInfo(CultureInfo cultureInfo)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}
At the time of language change, the code should be like below
var ci = CultureInfo.CreateSpecificCulture("ar");
NativeLangUtil.SetLocale(ci); // updating Native
Resx.Lang.Strings.Culture = ci; //For .net Resources to work
Application.Current.Properties["Lang"] = ci.TwoLetterISOLanguageName;//
LangResourceLoader.Instance.SetCultureInfo(ci); //for our use
You can find the sample implementation here
I'm using Prism to implement MVVM.
And I have a situation where I have a ListView and have to handle the ItemTapped event and also get the tapped item.
I tried using EventToCommandBehavior.
But I couldn't get it to work cause it was not recognising the references that were added.
The EventToCommandBehavior does not currently exist in the pre1 package available on NuGet. This should be available when pre2 is released.
My recommendation would be that you either copy the EventToCommandBehavior to your project for now, or you could add one that I use:
/// <summary>
/// ListView Item Tapped Behavior.
/// </summary>
public class ItemTappedBehavior : BehaviorBase<ListView>
{
/// <summary>
/// Gets or sets the command.
/// </summary>
/// <value>The command.</value>
public ICommand Command { get; set; }
/// <inheritDoc />
protected override void OnAttachedTo( ListView bindable )
{
base.OnAttachedTo( bindable );
AssociatedObject.ItemTapped += OnItemTapped;
}
/// <inheritDoc />
protected override void OnDetachingFrom( ListView bindable )
{
base.OnDetachingFrom( bindable );
AssociatedObject.ItemTapped -= OnItemTapped;
}
void OnItemTapped( object sender, ItemTappedEventArgs e )
{
if ( Command == null || e.Item == null ) return;
if ( Command.CanExecute( e.Item ) )
Command.Execute( e.Item );
}
}
Then in your Xaml
<ListView.Behaviors>
<behaviors:ItemTappedBehavior Command="{Binding SelectedItemCommand}" />
</ListView.Behaviors>
I would suggest a different approach.
public class AppListView: ListView{
public AppListView(): base(ListViewCachingStrategy.RecycleElement){
this.ItemSelected += (s,e)=>{
this.TapCommand?.Invoke(e.Item);
}
}
#region Property TapCommand
/// <summary>
/// Bindable Property TapCommand
/// </summary>
public static readonly BindableProperty TapCommandProperty = BindableProperty.Create(
nameof(TapCommand),
typeof(System.Windows.Input.ICommand),
typeof(AppListView),
null,
BindingMode.OneWay,
null,
null,
null,
null,
null
);
/// <summary>
/// Property TapCommand
/// </summary>
public System.Windows.Input.ICommand TapCommand
{
get
{
return (System.Windows.Input.ICommand)GetValue(TapCommandProperty);
}
set
{
SetValue(TapCommandProperty, value);
}
}
#endregion
}
Now use AppListView instead of ListView and use TapCommand="{Binding ...}". In order for intellisense to work correctly, I suggest keep this class in a separate library project (one for android, one for iOS and keep this file in shared project between all library projects).
I am trying to figure out a way to make checkbox appear on button click on a page.
It's invisible by default, because I've set checkBox.Visibility = Android.Views.ViewStates.Invisible; in my custom renderer.
I have a button in the page content and a checkbox in the template which resides in pages resources.
From my ViewModel I am able to invoke PropertyChanged in CheckBox control where I can see the old and new value correctly set.
But I need a way to set it on the ViewRenderer. I'm guessing that it needs to handle some kind of event similar to CheckedChanged.
ViewModel
CheckBox c = new CheckBox { IsCheckBoxVisible=true,IsVisible=true };
CheckBox control
public class CheckBox : View
{
/// <summary>
/// The checked state property.
/// </summary>
public static readonly BindableProperty CheckedProperty =
BindableProperty.Create<CheckBox, bool>(
p => p.Checked, false, BindingMode.TwoWay, propertyChanged: OnCheckedPropertyChanged);
**public static readonly BindableProperty IsCheckBoxVisibleProperty =
BindableProperty.Create<CheckBox, bool>(
p => p.IsCheckBoxVisible, false, BindingMode.OneWay, propertyChanged: OnVisibilityPropertyChanged);**
/// <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);
/// <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 EventHandler<EventArgs<bool>> VisibilityChanged;**
/// <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);
}
}
}
**public bool IsCheckBoxVisible
{
get
{
return this.GetValue<bool>(IsCheckBoxVisibleProperty);
}
set
{
if (this.IsCheckBoxVisible != value)
{
this.SetValue(IsCheckBoxVisibleProperty, value);
this.VisibilityChanged.Invoke(this, value);
//OnPropertyChanged("IsCheckBoxVisible");
}
}
}**
/// <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);
}
}
/// <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 static void OnVisibilityPropertyChanged(BindableObject bindable, bool oldvalue, bool newvalue)
{
var checkBox = (CheckBox)bindable;
checkBox.IsCheckBoxVisible = newvalue;
}**
}
CheckBoxRenderer
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (this.Control == null)
{
var checkBox = new Android.Widget.CheckBox(this.Context);
checkBox.Visibility = Android.Views.ViewStates.Invisible;
checkBox.CheckedChange += CheckBoxCheckedChange;
defaultTextColor = checkBox.TextColors;
this.SetNativeControl(checkBox);
}
Control.Text = e.NewElement.Text;
Control.Checked = e.NewElement.Checked;
UpdateTextColor();
if (e.NewElement.FontSize > 0)
{
Control.TextSize = (float)e.NewElement.FontSize;
}
if (!string.IsNullOrEmpty(e.NewElement.FontName))
{
Control.Typeface = TrySetFont(e.NewElement.FontName);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
switch (e.PropertyName)
{
case "Checked":
Control.Text = Element.Text;
Control.Checked = Element.Checked;
break;
case "TextColor":
UpdateTextColor();
break;
case "FontName":
if (!string.IsNullOrEmpty(Element.FontName))
{
Control.Typeface = TrySetFont(Element.FontName);
}
break;
case "FontSize":
if (Element.FontSize > 0)
{
Control.TextSize = (float)Element.FontSize;
}
break;
case "CheckedText":
case "UncheckedText":
Control.Text = Element.Text;
break;
** case "IsCheckBoxVisible":
if(Element.IsCheckBoxVisible==true)
{
Control.Visibility = Android.Views.ViewStates.Visible;
}
else
{
Control.Visibility = Android.Views.ViewStates.Invisible;
}
break;**
default:
System.Diagnostics.Debug.WriteLine("Property change for {0} has not been implemented.", e.PropertyName);
break;
}
}
So this should actually be really simple. right now you have IsCheckBoxVisibleProperty, and you can get rid of it all together. The Xamarin.Forms.View already has an IsVisible property, and each platform specific renderer (VisualElementRenderer) knows how to handle visibility.
Therefore you can do this without issue.
var checkbox = new Checkbox();
checkbox .SetBinding (Checkbox.IsVisibleProperty, "IsCheckboxVisible");
Or in your XAML
<controls:Checkbox IsVisible="{Binding IsCheckboxVisible}" />
Of course this assumes you have a ViewModel similar to.
public class MyViewModel : BaseViewModel
{
private bool _isCheckboxVisible;
public bool IsCheckboxVisible
{
get { return _isCheckboxVisible; }
set { SetField(ref _isCheckboxVisible, value); }
}
}
I'm doing a login view. Problem is that the PasswordBox cant be binded to the view model so im mapping a property of the view to the viewmodel.
This is the View
public partial class LoginView : MetroDataWindow
{
/// <summary>
/// Initializes a new instance of the <see cref="LoginView"/> class.
/// </summary>
public LoginView()
: this(null) { }
/// <summary>
/// Initializes a new instance of the <see cref="LoginView"/> class.
/// </summary>
/// <param name="viewModel">The view model to inject.</param>
/// <remarks>
/// This constructor can be used to use view-model injection.
/// </remarks>
public LoginView(LoginViewModel viewModel)
: base(viewModel)
{
InitializeComponent();
}
[ViewToViewModel(MappingType = ViewToViewModelMappingType.ViewToViewModel)]
public SecureString Contrasena
{
get { return (SecureString)GetValue(ContrasenaPropiedad); }
set { SetValue(ContrasenaPropiedad, value); }
}
// Using a DependencyProperty as the backing store for MapCenter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContrasenaPropiedad = DependencyProperty.Register("Contrasena", typeof(SecureString),
typeof(LoginView), new PropertyMetadata(null, (sender, e) => ((LoginView)sender).UpdateContrasena()));
private void UpdateContrasena()
{
MessageBox.Show("VIEW: FirstName changed to " + ContrasenaPropiedad.ToString());
}
private void tbPassword_PasswordChanged(object sender, RoutedEventArgs e)
{
Contrasena = tbPassword.SecurePassword;
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == ContrasenaPropiedad)
{
int i = 0;
}
}
}
this is the viewmodel part with the property
public static readonly PropertyData ContrasenaPropiedad = RegisterProperty("Contrasena", typeof(SecureString), null, (sender, e) => ((LoginViewModel)sender).OnContrasenaChange());
public void OnContrasenaChange()
{
_messageService.Show("VIEW MODEL: FirstName changed to " + Contrasena.ToString());
}
public SecureString Contrasena
{
get
{
return GetValue<SecureString >(ContrasenaPropiedad);
}
set
{
SetValue(ContrasenaPropiedad, value);
}
}
the onChange function of the viewmodel never triggers.
I based this code on the example given in the last comment in this question
Catel ViewToViewModel attribute
But it does not work. Am I missing something or was the bug commented there never fixed?
Also since the view is the only one changing the property should i use the ViewToViewModelMappingType.ViewToViewModel type instead? does it change the implementation of the mapping in any way?
Passwords are a special kind of breed. But Catel has a solution for that problem, the UpdateBindingOnPasswordChanged behavior:
<PasswordBox>
<i:Interaction.Behaviors>
<catel:UpdateBindingOnPasswordChanged Password="{Binding Password, Mode=TwoWay}" />
</i:Interaction.Behaviors>
</PasswordBox>
ps. are you aware of Catel.Fody? It makes your code more readable and easier to write.
I am using telerik:RadGridView along with telerik:RadContextMenu.ContextMenu to generate a right click menu inside my application. I need to be able to grab the servername and session id from the selected row in order to pass to the Disconnect and Logoff functions. However I ma having difficulty grabbing the data I need.
Here is the XAML for the component
<telerik:RadGridView x:Name="UserSessionGrid" IsReadOnly="True" FontWeight="Bold" AutoGeneratingColumn="UserSessionGrid_AutoGeneratingColumn" CanUserResizeColumns="False" CanUserDeleteRows="False" CanUserResizeRows="False" ClipboardCopyMode="All" Copied="UserSessionGrid_Copied" >
<telerik:RadContextMenu.ContextMenu>
<telerik:RadContextMenu Opened="RadContextMenu_Opened" ItemClick="RadContextMenu_ItemClick">
<telerik:RadContextMenu.Items>
<telerik:RadMenuItem Header="Copy" />
<telerik:RadMenuItem Header="Disconnect" />
<telerik:RadMenuItem Header="Logoff" />
</telerik:RadContextMenu.Items>
</telerik:RadContextMenu>
</telerik:RadContextMenu.ContextMenu>
</telerik:RadGridView>
Here is the relevant code that handles the Right Click
/// <summary>
/// Handles the ItemClick event of the RadContextMenu control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="Telerik.Windows.RadRoutedEventArgs"/> instance containing the event data.</param>
private void RadContextMenu_ItemClick(object sender, Telerik.Windows.RadRoutedEventArgs e)
{
RadContextMenu menu = (RadContextMenu)sender;
RadMenuItem clickedItem = e.OriginalSource as RadMenuItem;
GridViewRow row = menu.GetClickedElement<GridViewRow>();
GridViewCell cell = menu.GetClickedElement<GridViewCell>();
GridViewRowItem rowitem = menu.GetClickedElement<GridViewRowItem>();
if (clickedItem != null && row != null)
{
string header = Convert.ToString(clickedItem.Header);
switch (header)
{
case "Copy":
Clipboard.SetText(cell.Value.ToString());
break;
case "Disconnect":
// Grab Server Name Column and Session ID Column Data
break;
case "Logoff":
// Grab Server Name Column and Session ID Column Data
break;
default:
break;
}
}
}
/// <summary>
/// Handles the Opened event of the RadContextMenu control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
private void RadContextMenu_Opened(object sender, RoutedEventArgs e)
{
RadContextMenu menu = (RadContextMenu)sender;
GridViewRow row = menu.GetClickedElement<GridViewRow>();
if (row != null)
{
row.IsSelected = row.IsCurrent = true;
GridViewCell cell = menu.GetClickedElement<GridViewCell>();
if (cell != null)
{
cell.IsCurrent = true;
}
}
else
{
menu.IsOpen = false;
}
}
And here is my session class
class Session
{
public String Server { get; set; }
public String Domain { get; set; }
public String User { get; set; }
public int sID { get; set; }
public ConnectionState State { get; set; }
public IPAddress IP { get; set; }
public String Workstation { get; set; }
public DateTime? Connect { get; set; }
public DateTime? Login { get; set; }
public TimeSpan Idle { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Session"/> class.
/// </summary>
/// <param name="server">The server.</param>
/// <param name="domain">The domain.</param>
/// <param name="user">The user.</param>
/// <param name="session">The session.</param>
/// <param name="state">The state.</param>
/// <param name="ip">The ip.</param>
/// <param name="workstation">The workstation.</param>
/// <param name="connect">The connect.</param>
/// <param name="login">The login.</param>
/// <param name="idle">The idle.</param>
public Session (string server, string domain, string user, int session, ConnectionState state, IPAddress ip, string workstation, DateTime? connect, DateTime? login, TimeSpan idle)
{
this.Server = server.ToUpper();
this.Domain = domain.ToUpper();
this.User = user;
this.sID = session;
this.State = state;
this.IP = ip;
this.Workstation = workstation.ToUpper();
this.Connect = connect;
this.Login = login;
this.Idle = idle;
}
}
Which is called by using the following code
/// <summary>
/// Handles the DoWork event of the worker control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="DoWorkEventArgs"/> instance containing the event data.</param>
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
App.Current.Dispatcher.Invoke((Action)delegate
{
UserSessionGrid.IsBusy = true;
});
ITerminalServicesManager manager = new TerminalServicesManager();
foreach (var ServerName in ServerList)
{
using (ITerminalServer server = manager.GetRemoteServer(ServerName))
{
try
{
server.Open();
foreach (ITerminalServicesSession session in server.GetSessions())
{
items.Add(new Session(server.ServerName, session.DomainName, session.UserName, session.SessionId, session.ConnectionState, session.ClientIPAddress, session.WindowStationName, session.ConnectTime,session.LoginTime, session.IdleTime));
//worker.ReportProgress(session.SessionId);
}
server.Close();
}
catch (Win32Exception) { }
catch (SystemException) { }
catch (Exception) { }
}
}
}
I found the solution to this by doing the following
RadWindow.Alert(((Session)UserSessionGrid.SelectedItem).Server);
RadWindow.Alert(((Session)UserSessionGrid.SelectedItem).SessionID);