I want to add a tooltip to a menu item. On the menu there is the word "DELETE" and when the mouse hovers over the word I want a tooltip displayed. I though of using 'ToolTipService.SetToolTip();'.
This is where the items contained in the menu are set...
protected virtual void SetContextMenuItems()
{
// -- Add condition for ReadOnly + ReadOnly Attribute to AreaEntity
if (this.ViewMode == Common.Core.ViewModes.RealTime)
{
AreaEntity ae = viewModel.EntityViewContext as AreaEntity;
if (((UserContext.Instance.IsAdmin() && (ae.Scope.Value == "global" || ae.Scope.Value == string.Empty)) ||
ae.OwnerPosition.Value == CoreServices.Instance.CurrentPosition.Configuration.Name)
&& !((this.MapInstance.Parent as Grid).Parent is PIPMap))
{
menuItem = new ContextMenuItem();
//menuItem.DisplayText = "Delete"; // -- Could be dynamic based off type "Edit Polygon (Circle, etc.)"
menuItem.DisplayText = CoreServices.Instance.GetString("Delete");
cmd = new MR.CommandBridge.Common.Command.DelegateCommand(DeleteShape, CanDelete);
menuItem.Command = cmd;
this.ContextMenu.MenuItems.Add(menuItem);
}
}
}
Methods 'DeleteShape' and 'CanDelete':
public void DeleteShape(object param)
{
EntityStore.Instance.DeleteEntity(this.ViewModel.EntityViewContext);
}
public bool CanDelete(object param)
{
GetRulesForShape();
bool isInFilter = false;
EntityCollection<Entity> lists = EntitySync.Instance.Cache["entityCollection"];
foreach (Entity list in lists)
{
isInFilter = (list as ListEntity).FilterList.Filters.Count(a => (a.FilterType == FilterTypes.WithinZone && a.Value == this.viewModel.EntityViewContext.Uri) ||
(a.FilterType == FilterTypes.MultipleFilter && a.Filters.Count(b => b.FilterType == FilterTypes.WithinZone && b.Value == this.viewModel.EntityViewContext.Uri) > 0)) > 0;
if (isInFilter) break;
}
return !HasRules && !CoreServices.Instance.ZoneFilters.Contains(this.viewModel.Area.Uri) && gfEditor.dm != GeofenceEditor.DrawMode.DrawEdit && !isInFilter;
}
Ok I made some adjustments to your class.
Somehow I got the feeling your mixing up things like control and bindings.
We'll see. ;)
I've also made some comments, maybe you can shed some light over then.
public class ContextMenuItem : MenuItem
{
public ContextMenuItem()
:base()
{
}
//Replace by Header
//
//public string DisplayText { get; set; }
//Can this be replaced by build in CommandParameter
//
private Dictionary<string, object> _parameters = new Dictionary<string, object>();
private Func<ContextMenuItem, List<ContextMenuItem>> _getMenuItems = null;
//Already available
//public DelegateCommand Command { get; set; }
//What does this function do?
public Func<ContextMenuItem, List<ContextMenuItem>> GetMenuItems
{
get
{
return _getMenuItems;
}
set
{
_getMenuItems = value;
}
}
public Dictionary<string, object> Parameters
{
get
{
return _parameters;
}
}
//Can be replaced by base Items
//
//private List<ContextMenuItem> _menuItems = new List<ContextMenuItem>();
//public List<ContextMenuItem> ChildMenuItems
//{
// get
// {
// return _menuItems;
// }
//}
private bool _isChecked = false;
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; }
}
// -- Command or implementer could provide a handler for all commands - might be simpler for now
// -- I think there could be a better way to route commands but I'll thin on it.
Could this simply be done in .css?
.yourclass:hover{
cursor:pointer;
}
or target it with jquery?
Have you tried this?
menuitem.ToolTip = "Delete";
Normally a contextmenu can exist of regular MenuItems. I used it often.
;)
Context menu items have the ToolTipText property:
menuItem.ToolTipText = "ToolTip Text Here";
Related
I'm filtering a listcollectionview in viewModel 1 based on selectionchanged of datagrid in viewModel 2. To do this I use mvvm messaging. Each time the selection of the datagrid changes a message is send to update my listcollectionview. This all works well.
Now I need to use the string value of this message to pass into the filter. The problem is that I can only use the string value in the updateShotList method but not into the bool IsMatch. How can I make this work, or how can I use the string value of the message as a variable in my viewmodel.
This is how my viewmodel looks like.
private ObservableCollection<Shot> _allShots = new ObservableCollection<Shot>();
public ObservableCollection<Shot> AllShots
{
get { return _allShots; }
set { _allShots = value; RaisePropertyChanged();}
}
private ListCollectionView _allShotsCollection;
public ListCollectionView AllShotsCollection
{
get
{
if (_allShotsCollection == null)
{
_allShotsCollection = new ListCollectionView(this.AllShots);
}
return _allShotsCollection;
}
set
{
_allShotsCollection = value; RaisePropertyChanged();
}
}
private void UpdateShotList(string SceneNr) // value sceneNr comes from message from viewmodel 2
{
_allShotsCollection.IsLiveFiltering = true;
_allShotsCollection.Filter = new Predicate<object>(IsMatchFound);
}
bool IsMatchFound(object obj)
{
=====> if (obj as Shot != null && (obj as Shot).SceneNumber == "?????") // Here I need the value of string ScenNr that comes from the message.
{
return true;
}
return false;
}
public ShotListViewModel()
{
Messenger.Default.Register<string>(this, "UpdateShotList", UpdateShotList);
}
You can create your predicate as a lambda expression and close over SceneNr to capture it:
_allShotsCollection.Filter = o =>
{
var shot = o as Shot;
return shot != null && shot.SceneNumber == SceneNr;
};
Alternatively, simply introduce an instance variable to contain your filter string and update it each time you receive a message:
private string _sceneNr;
private void UpdateShotList(string sceneNr)
{
// ...
_sceneNr = sceneNr;
}
bool IsMatchFound(object obj)
{
var shot = obj as Shot;
return shot != null && shot.SceneNumber == _sceneNr;
}
I have two drop down lists. Niether of them have a relation ship with each other. But I need to filter one drop down list based on the chosen value of another drop down list.
I can filter it in code. When I debug I can see the filtered results on the property. However when I run the app, it does not work. Here is my code so far:
private BindingList<Commodity> _AllocationCommodities;
[Browsable(false)]
public BindingList<Commodity> AllocationCommodities
{
get
{
if (_AllocationCommodities == null)
{
_AllocationCommodities = new BindingList<Commodity>();
ChangeCommodities();
}
return _AllocationCommodities;
}
}
private SourceEntity _SourceEntity;
[ImmediatePostData]
[Association("SourceEntity-LimitAllocations")]
[RuleRequiredField("RuleRequiredField_LimitAllocation_SourceEntity", DefaultContexts.Save)]
public SourceEntity SourceEntity
{
get
{
return _SourceEntity;
}
set
{
//New Code
if (SetPropertyValue<SourceEntity>("SourceEntity", value))
{
if (IsSaving || IsLoading) return;
ChangeCommodities();
}
}
}
private Commodity _Commodity;// This is the drop down to be filtered
[ImmediatePostData]
[DataSourceProperty("AllocationCommodities")] //// This Attribute Should filter Commodities
[RuleRequiredField("RuleRequiredField_LimitAllocation_Commodity", DefaultContexts.Save)]
public Commodity Commodity
{
get
{
return _Commodity;
}
set
{
SetPropertyValue("Commodity", ref _Commodity, value);
if (Commodity.Oid != Guid.Empty)
AllocationVolumeUnits.Reload();
}
}
private void ChangeCommodities()
{
if (!this.IsLoading && _SourceEntity != null)
{
_AllocationCommodities.RaiseListChangedEvents = false;
_AllocationCommodities.Clear();
OperandValue[] _params;
System.Collections.Generic.List<CMSBOD.SourceCommodity> _sc = new System.Collections.Generic.List<SourceCommodity>();
BindingList<Commodity> _Commodities = new BindingList<Commodity>();
foreach (SourceCommodityEntity _tempSCE in _SourceEntity.SourceCommodityEntities)
{
if (_tempSCE.SourceCommodity != null)
_sc.Add(_tempSCE.SourceCommodity);
}
foreach (SourceCommodity _tempSC in _sc)
{
if (_tempSC.Commodity != null && !_Commodities.Contains<Commodity>(_tempSC.Commodity) && _tempSC.Commodity.IsActive)
_Commodities.Add(_tempSC.Commodity);
}
_AllocationCommodities.RaiseListChangedEvents = true;
_AllocationCommodities = _Commodities;///This is where I can see the filtered list when debugging.
}
}
You can find a DataSourceCriteria useful in this scenario, instead of DataSourceProperty.
Assuming you have collection properties that associates Commodity back to SourceCommodityEntity, you can use this criteria:
[DataSourceCriteria("IsActive And SourceCommodities[SourceCommodityEntities[SourceEntity = '#SourceEntity'] ]")]
Even if its designed to be a 1x1 assocation, you can find that associations can be useful for filtering purposes.
I've the following:
public enum ValidationSeverity
{
Error = 1,
Warning = 2
}
Public class Errors
{
public ValidationSeverity Severity { set; get; }
public string Desc { set; get; }
}
in the ViewModel defined ObservableCollection, and I bound it to DataGrid of the sdk, now I've two toggle buttons:
Show Errors
Show Warnings
-
When I click on "Show Errors", the data grid will just have the rows that the Severity of them is "Error".
I'm trying to use ICollectionView, like that when I click on "Show Errors", it will go to:
private void OnShowErrors()
{
if (IsErrorButtonChecked)
Show(ValidationSeverity.Error);
else
Hide(ValidationSeverity.Error);
}
private void Hide(ValidationSeverity sev)
{
var lcv = _collectionViewSourceHelper.GetCollectionView(ErrorsList);
if (lcv == null || !lcv.CanFilter) return;
lcv.Filter = item =>
{
var error = item as Error;
if (error == null) return false;
return error.Severity != sev;
};
}
private void Show(ValidationSeverity sev)
{
var lcv = _collectionViewSourceHelper.GetCollectionView(ErrorsList);
if (lcv == null || !lcv.CanFilter) return;
lcv.Filter = item =>
{
var error = item as Error;
if (error == null) return false;
return error.Severity == sev;
};
}
_collectionViewSourceHelper - I added this, cause in the Silverlight we can't use the GetCollectionView directly, now my question is how I can do that, I wrote two predicates, but how I can continues, if I edit the collectionView does it cause changing the view?
Thanks
The view is just a wrapper around the collection, if you edit the collection the changes will be reflected in the collectionview also, so basically you must edit the ErrorList.
I've got a little problem with data-binding between DataGridView and a PropertyGrid.
Here is the code from the object I am binding to and the DataGridView:
public class Effort
{
public BindingList<EffortCalculationRelation> CalculationRelations { get; set; }
public int ID { get; set; }
// more properties
public Effort()
{
CalculationRelations = new BindingList<EffortCalculationRelation>();
CalculationRelations.Clear();
for (int i=0;i<10;i++)
{
CalculationRelations.Add( new EffortCalculationRelation() { ID = i, Name = "Round:" + i.ToString(), calculation = "Some calc" });
}
}
public Effort(int id) : this()
{
this.ID = id;
// Load all other properties
}
public class EffortCalculationRelation
{
public int ID { get; set; }
public string Name { get; set; }
public string calculation { get; set; }
public int Save()
{
// save or insert and return id or 0 on fail
if (this.ID > 0)
{
return this.Update();
}
else
{
return this.Insert();
}
}
public string Delete()
{
// delete and return "" or errormsg on fail
return "";
}
private int Insert()
{
// insert and return id or 0 on fail
return ID;
}
private int Update()
{
// return affected rows or 0 on fail
return 1;
}
public string Representation
{
get { return String.Format("{0}: {1}", ID, Name); }
}
}
}
The datagridview connection is realy simple an only just a little style:
public test()
{
effort = new Effort(1209);
dgv.DataSource = effort.CalculationRelations;
dgv.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
dgv.AllowUserToAddRows = true;
//this.dgv.AllowUserToDeleteRows = false;
dgv.AllowUserToResizeRows = false;
dgv.ReadOnly = true;
dgv.SelectionChanged += (sender, args) =>
{
var selectedObjects =
(from System.Windows.Forms.DataGridViewRow r in dgv.SelectedRows
where r.DataBoundItem != null && r.DataBoundItem.GetType() == typeof(EffortCalculationRelation)
select r.DataBoundItem).ToArray();
// pg is a propertygrid
this.pg.SelectedObjects = selectedObjects;
};
}
So and my problem is, when I select the new row in the datagridview, that no properties are displayed in the propertygrid.
When I select a row that has an object in the list at the moment I load it, then I can edit the properties.
So could you please help?
The reason the new row does not show in the property grid is that its DataBoundItem is null so is removed by your LINQ statement where r.DataBoundItem != null. 1
I agree with you that this is very annoying behaviour, particularly since the object has in some sense been created.
I had thought there was a viable workaround of in certain circumstance binding the property grid to the new object in either the parent Effort object or in a BindingSource using some code like:
var selectedObjects =
(from System.Windows.Forms.DataGridViewRow r in dataGridView1.SelectedRows
where r.DataBoundItem != null && r.DataBoundItem.GetType() == typeof(Effort.EffortCalculationRelation)
select r.DataBoundItem).ToArray();
if (dataGridView1.CurrentRow.IsNewRow && dataGridView1.SelectedRows.Count == 1)
{
// I tried accessing the parent object like this:
//Effort.EffortCalculationRelation ecr = effort.CalculationRelations[effort.CalculationRelations.Count - 1];
//propertyGrid1.SelectedObject = ecr;
// Or accessing a binding source like:
propertyGrid1.SelectedObject = calculationRelations.Current;
}
else
{
propertyGrid1.SelectedObjects = selectedObjects;
}
I experimented with these variations a bit, as well as adding these items into the SelectedObjects array, thinking something would meet your requirements but what I eventually realised was shifting focus from the new row to the property grid before the DataGridView had committed the new row meant that the new row was lost and could no longer be edited.
So - what to do?
If I was in your spot I'd consider one of two things:
Allow direct editing in the grid of some form - maybe just to the new row.
Something like this in the selection changed event would work:
if (dataGridView1.CurrentRow.IsNewRow)
{
dataGridView1.CurrentRow.ReadOnly = false;
}
else
{
dataGridView1.CurrentRow.ReadOnly = true;
}
Keep the grid as is but don't allow new rows - instead handle new objects between a seperate row creation panel.
1 This works this way apparently by design - the DataBoundItem is not committed uptil you leave the grid. There is a little discussion including the DataGridView code in question here.
I'm having trouble getting my UI to update Two Listboxes' to update properly when my ViewModel changes.
First, the basic logic behind the page:
Movie is an object with a title, and a variety of MovieDetails. Some MovieDetail are different than others, as they are detailed which is a glorified way of saying they're more Important.
I use two ListBoxes to separate these MovieDetails into stacked ListBoxes, one for 'Detailed' and one for 'NotDetailed'
If a movie has no 'Detailed' attributes, the corresponding list is Hidden via a BooleanToVisibilityConverter (and vice-versa)
When I navigate to the page, I set the Movie the page corresponds to, and it should RaisePropertyChanged to alert the AllMoviesDetail ObservableCollection that it should re-get Movies.MovieDetailFetchedList.
From there, AllMoviesDetail would alert the two ObservableCollections (Detailed, NotDetailed) they should be re-get.
In fact, RaisePropertyChanged on NotDetailedMovieDetails or DetailedMovieDetails does not seem to do anything either. (And the corresponding HasNotDetailedMovieDetails, Has...)
What does work, however, is if I add more items into the list, the CollectionChanged event seems to fire and reactivate the list. I have also been able to do this by instantiating the ObservableCollections in code first var temp = DetailedMoviesDetail;
public class MoviesDetailViewModel : ViewModelBase
{
#region Property Names
public const string MoviePropertyString = "Movie";
public const string AllMoviesDetailPropertyString = "AllMoviesDetail";
public const string DetailedMoviesDetailPropertyString = "DetailedMoviesDetail";
public const string NotDetailedMoviesDetailPropertyString = "NotDetailedMoviesDetail";
public const string HasNotDetailedMoviesDetailPropertyString = "HasNotDetailedMoviesDetail";
public const string HasDetailedMoviesDetailPropertyString = "HasDetailedMoviesDetail";
public const string NotDetailedHeaderPropertyString = "NotDetailedHeader";
#endregion
public MoviesDetailViewModel()
{
if (IsInDesignMode)
{
Movie = DesignDataStore.MovieList[0];
Movie.Category = Category.DDA;
}
}
private Movie _Movie;
/// <summary>
/// The Movie for which to browse MoviesDetail. It is expected when setting this property, that MoviesDetail for it have been downloaded previously.
/// </summary>
/// <remarks>The 'Master' property for this ViewModel. All properties are Dependent on this and the underlying property MoviesDetailList</remarks>
/// <seealso cref="MovieDetailFetchedList"/>
public Movie Movie
{
get { return _Movie; }
set
{
if (_Movie != value)
{
if (_Movie != null)
_Movie.MovieDetailFetchedList.CollectionChanged -= MoviesDetailListChanged;
_Movie = value;
RaisePropertyChanged(MoviePropertyString);
RaisePropertyChanged(StatementPeriodAvailablePropertyString);
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
Movie.MovieDetailFetchedList.CollectionChanged += MoviesDetailListChanged;
RaisePropertyChanged(AllMoviesDetailPropertyString);
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(NotDetailedHeaderPropertyString);
}
}
}
private void MoviesDetailListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
if (((MovieDetail) item).IsDetailed())
DetailedMoviesDetail.Add(item as MovieDetail);
else
NotDetailedMoviesDetail.Add(item as MovieDetail);
}
}
else
{
RaisePropertyChanged(AllMoviesDetailPropertyString);
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
}
}
#endregion
private MovieDetailFetchedList _allMoviesDetail;
public MovieDetailFetchedList AllMoviesDetail
{
get
{
if (Movie == null)
return new MovieDetailFetchedList();
return _allMoviesDetail ?? (AllMoviesDetail = Movie.MovieDetailFetchedList);
}
set
{
if (_allMoviesDetail != value)
{
if (_allMoviesDetail != null)
_allMoviesDetail.CollectionChanged -= MoviesDetailListChanged;
_allMoviesDetail = value;
_allMoviesDetail.CollectionChanged += MoviesDetailListChanged;
RaisePropertyChanged(AllMoviesDetailPropertyString);
//force update
DetailedMoviesDetail = NotDetailedMoviesDetail = null;
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasDetailedMoviesDetailPropertyString);
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasNotDetailedMoviesDetailPropertyString);
}
}
}
public bool HasNotDetailedMoviesDetail { get { return NotDetailedMoviesDetail != null && NotDetailedMoviesDetail.Count > 0; } }
private ObservableCollection<MovieDetail> _notDetailedMoviesDetail;
public ObservableCollection<MovieDetail> NotDetailedMoviesDetail
{
get
{
if (Movie == null) return new ObservableCollection<MovieDetail>();
return AllMoviesDetail;
return _notDetailedMoviesDetail ?? //make sure RaisePropertyChanged happens by using property setter
(NotDetailedMoviesDetail = AllMoviesDetail.Where(mem => !mem.IsDetailed()).ToObservableCollection());
}
set
{
_notDetailedMoviesDetail = value;
RaisePropertyChanged(NotDetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasNotDetailedMoviesDetailPropertyString);
}
}
public bool HasDetailedMoviesDetail
{ get { return DetailedMoviesDetail != null && DetailedMoviesDetail.Count > 0; } }
private ObservableCollection<MovieDetail> _DetailedMoviesDetail;
public ObservableCollection<MovieDetail> DetailedMoviesDetail
{
get
{
if (Movie == null) return new ObservableCollection<MovieDetail>();
return AllMoviesDetail;
return _DetailedMoviesDetail ?? //make sure RaisePropertyChanged happens by using property setter
(DetailedMoviesDetail = AllMoviesDetail.Where(mem => mem.IsDetailed()).ToObservableCollection());
}
set
{
_DetailedMoviesDetail = value;
RaisePropertyChanged(DetailedMoviesDetailPropertyString);
RaisePropertyChanged(HasDetailedMoviesDetailPropertyString);
}
}
private string _DetailedHeader;
public string DetailedHeader
{
get { return _DetailedHeader ?? (_DetailedHeader = AppResources.in_available); }
set { _DetailedHeader = value; }
}
public string NotDetailedHeader
{
get { return (Movie != null && Movie.Category == Category.DRAMA) ? AppResources.Movie_MoviesDetail : AppResources.not_in_available; }
}
}
All of your property getters (except AllMoviesDetail) have two return statements. Since only the first will be executed, the values are not being assigned and the PropertyChanged events are not being twiggered.