WPF hierarchicaldatatemplate Filter - c#

I have in ViewModel
public string SearchPattern
{
get
{
return searchPattern;
}
set
{
searchPattern = value;
}
}
private bool UserFilter(object item)
{
return (item as Node).Name.Contains(SearchPattern);
}
public ICollectionView YourFilteredCollection
{
get
{
var source = CollectionViewSource.GetDefaultView(model.Items);
source.Filter = UserFilter;
return source;
}
}
YourFilteredCollection depends on Model property
public ObservableCollection<Node> Items { get; set; }
Than I decided to filter Node sub items YourFilteredCollectionNodes
public class Node
{
public string Name { get; set; }
public ObservableCollection<Node> Nodes { get; set; }
public ICollectionView YourFilteredCollectionNodes
{
get
{
var source = CollectionViewSource.GetDefaultView(Nodes);
if (source != null)
{
source.Filter = UserFilter;
}
return source;
}
}
private bool UserFilter(object item)
{
//return (item as Node).Name.Contains(SearchPattern);
return true;
}
}
But in this case how it is possible to pass SearchPattern from ViewModel in ObservableCollection item that is in Model??

Related

Update ListItem with MessageProtocol in MVVMCross

I have a list item which has more or less around 10 objects. I could able to detect which item is selected and also I sending this item properties into the DetailViewModel,I am using messageprotocol in mvvmcross.
I could able to observe changes in the MainViewModel when user enters new value in the edittext in DetailViewModel.
I wonder how I am going to put these values back into the selected item and update list.
MainViewModel
private readonly IMvxMessenger _messenger;
private readonly MvxSubscriptionToken _token;
private MainViewModel _selectedItem;
public MainViewModel SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
ShowViewModel<DetailViewModel>(
new DetailViewModel.Parameter
{
Age= _selectedItem.Age,
Category = _selectedItem.Category,
});
RaisePropertyChanged(() => SelectedItem);
}
}
public MainViewModel(IMvxMessenger messenger) {
_messenger = messenger;
_token = messenger.Subscribe<SelectedItemMessage>(OnMessageReceived);;
}
private void OnMessageReceived(SelectedItemMessage obj)
{
// I could observe the DetailView Changes in the MainViewModel
// I wonder how to put these value back to selectedItem
double? Age = obj.Age;
int? Category= obj.Category;
}
public virtual ICommand ItemSelected
{
get{ return new MvxCommand<TestViewModel>(item =>{ SelectedItem = item;});
}
}
private ObservableCollection<TestViewModel> _testViews;
private ObservableCollection<WellTestViewModel> _allTestItemViews;
public void Init(string Id)
{
List<Test> allTests = new List<Test>();
allTests = _TestService.GetAllTestById(Id);
foreach (var test in allTests)
{
_testViews.Add(TestViewModel.CreateViewModel(test, this));
}
_allTestItemViews = _testViews;
}
TestViewModel
public static TestViewModel CreateViewModel(Test entity, MainViewModel parent = null)
{
if (entity == null)
{
return null;
}
return new TestViewModel(parent)
{
Age = entity.Age,
Category= entity.Category,
};
}
public TestViewModel()
{
// parameterless constructor
}
readonly MainViewViewModel _mainViewModel ;
public TestViewModel(MainViewViewModel mainViewViewModel)
{
_mainViewModel = mainViewViewModel;
}
DetailViewModel
private readonly IMvxMessenger _messenger;
public class Parameter
{
public double? Age{ get; set; }
public int? Category { get; set; }
}
public void Init(Parameter param)
{
Age= param.Age;
Category= param.Category;
}
public DetailViewModel(IMvxMessenger messenger) {
_messenger = messenger;
}
public void UpdateMethod() {
var message = new SelectedItemMessage(this, age, category);
_messenger.Publish(message, typeof(SelectedItemMessage));
}
SelectedItemMessage
public SelectedItemMessage(object sender, double? age, int? category) : base(sender)
{
Age = age;
Category = category;
}
public double? Age { get; set; }
public int? Category{ get; set; }
}
Just use your _selectedItem and set the properties on it.
private void OnMessageReceived(SelectedItemMessage obj)
{
_selectedItem.Age = obj.Age;
_selectedItem.Category= obj.Category;
}
You need to update the collection inside the OnMessageReceived method:
var item = _allTestItemViews.FirstOrDefault(i => i.Id == id);
if (item != null)
{
item.Age = age;
item.Category = category;
}
You need to add Id to your model class so that you can uniquely identify the item you need to update.

WPF Menu with visibility permission

I've a WPF application that loads a menu from an XML file, each node as a tag that identifies the user function. Each user has visibility permission that match against the tag defined in the xml file. I wish some help on simplifing that code since I's quite complex and from my point of view poor performing. Consider that the main menu is composed of main items and inside each there're specific areas function. If a user is enabled to at element at list the main menu node is shown otherwise not.
public virtual System.Threading.Tasks.Task<MenuItemNode> RegisterMenu(IDictionary<string,Type> functions)
{
var assembly = Assembly.GetCallingAssembly(); //I should get the module that invoked the base class
string filename = GetFullFileName(assembly, MenuFilename);
return Task.Factory.StartNew<MenuItemNode>(() =>
{
string xmlFileName = string.Format(filename);
var doc = new XmlDocument();
using (Stream stream = assembly.GetManifestResourceStream(xmlFileName))
{
if (stream != null)
{
using (var reader = new StreamReader(stream))
{
doc.LoadXml(reader.ReadToEnd());
}
}
}
MenuItemNode menu = BuildMenu(doc.SelectSingleNode(#"/Node"), "/", functions);
return menu;
});
}
private string GetFullFileName(Assembly assembly,string filename)
{
var resourceFiles = assembly.GetManifestResourceNames();
return resourceFiles.First(x => x.EndsWith(filename));
}
private MenuItemNode BuildMenu(XmlNode parent, string path, IDictionary<string, Type> functions)
{
Argument.IsNotNull(() => parent);
if (functions == null || (functions.Count == 0)) return null;
MenuItemNode menuItem = null;
string subPath = "Node";
string name = string.Empty;
string tag = string.Empty;
int position = 0;
bool forceVisible = false;
string parameters = string.Empty;
string group = string.Empty;
bool showInDialog = false;
if (parent.Attributes != null)
{
if (parent.Attributes["name"] != null)
name = parent.Attributes["name"].Value;
if (parent.Attributes["tag"] != null)
tag = parent.Attributes["tag"].Value;
if (parent.Attributes["position"] != null)
position = System.Convert.ToInt32(parent.Attributes["position"].Value);
if (parent.Attributes["force_visible"] != null)
forceVisible = Convert.ToBoolean(parent.Attributes["force_visible"].Value);
if (parent.Attributes["parameters"] != null)
parameters = parent.Attributes["parameters"].Value;
if (parent.Attributes["group"] != null)
group = parent.Attributes["group"].Value;
if (parent.Attributes["showindialog"] != null)
showInDialog = Convert.ToBoolean(parent.Attributes["showindialog"].Value);
}
//parent item
if (string.IsNullOrEmpty(tag))
{
menuItem = CreateMenuItem(name, position);
menuItem.ForceVisible = forceVisible;
// menuItem.Group = group;
}
else//child item
{
if (functions.ContainsKey(tag))
{
menuItem = CreateMenuItem(name, tag, position);
menuItem.ForceVisible = forceVisible;
//menuItem.GroupName = group;
menuItem.ShowInDialog = showInDialog;
//menuItem.MenuParameter = GetMenuItemParameters(parameters);
#region Multiple-tag
if ((functions == null) || !functions.Any()) return null;
#endregion
}
else
{
//todo: add-logging
}
}
if (parent.HasChildNodes)
{
foreach (XmlNode child in parent.SelectNodes(subPath))
{
MenuItemNode childMenuItem = BuildMenu(child, subPath, functions);
if (childMenuItem == null) continue;
int childPosition = childMenuItem.SortIndex;
//This to prevent out-of-boundaries exception
if (childPosition > menuItem.Children.Count)
childPosition = menuItem.Children.Count;
menuItem.Children.Insert(childPosition, childMenuItem);
}
}
return menuItem;
}
private MenuItemNode CreateMenuItem(string text, int position)
{
var item = new MenuItemNode();
item.Text = text;
item.SortIndex = position;
return item;
}
private MenuItemNode CreateMenuItem(string text, string tag, int? position)
{
MenuItemNode item = CreateMenuItem(text, (!position.HasValue) ? 0 : position.Value);
item.FunctionTag = tag;
item.SortIndex = (!position.HasValue) ? 0 : position.Value;
return item;
}
And here's the MenuItemNode class
[ContentProperty("Children")]
public class MenuItemNode : INotifyPropertyChanged
{
private string text;
private ICommand command;
private Uri imageSource;
private int sortIndex;
private bool forceVisible;
private bool showInDialog;
private bool isChecked;
public bool IsChecked
{
get
{
return this.isChecked;
}
set
{
if (this.isChecked != value)
{
this.isChecked = value;
this.RaisePropertyChanged(() => this.IsChecked);
}
}
}
public bool IsSeparator { get; set; }
public MenuItemNode()
{
Children = new MenuItemNodeCollection();
SortIndex = 50;
SetCommand();
}
public MenuItemNode(String path)
: base()
{
Path = path;
}
public MenuItemNodeCollection Children { get; private set; }
public virtual ICommand Command
{
get
{
return command;
}
set
{
if (command != value)
{
command = value;
RaisePropertyChanged(() => this.Command);
}
}
}
public Uri ImageSource
{
get
{
return imageSource;
}
set
{
if (imageSource != value)
{
imageSource = value;
RaisePropertyChanged(() => this.ImageSource);
}
}
}
public string Text
{
get
{
return text;
}
set
{
if (text != value)
{
text = value;
RaisePropertyChanged(() => this.Text);
}
}
}
private MenuGroupDescription group;
public MenuGroupDescription Group
{
get { return group; }
set
{
if (group != value)
{
group = value;
RaisePropertyChanged(() => this.Group);
}
}
}
public int SortIndex
{
get
{
return sortIndex;
}
set
{
if (sortIndex != value)
{
sortIndex = value;
RaisePropertyChanged(() => this.SortIndex);
}
}
}
public string Path
{
get;
private set;
}
public bool ForceVisible
{
get
{
return this.forceVisible;
}
set
{
if (forceVisible != value)
{
this.forceVisible = value;
RaisePropertyChanged(() => ForceVisible);
}
}
}
public bool ShowInDialog
{
get
{
return this.showInDialog;
}
set
{
if (showInDialog = value)
{
this.showInDialog = value;
RaisePropertyChanged(() => ShowInDialog);
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyExpression.Name));
}
#endregion
protected virtual void SetCommand()
{
this.Command = FunctionMenuCommands.OpenFunctionCommand;
}
public string FunctionTag { get; set; }
}
In specific what I did is to process each child node then if visible I add it to the collection... do you see any possible better solution?
Thanks
Whoever wrote that code clearly didn't know how to write WPF. In WPF, there is a much simpler option... just use the MenuItem.Visibility property to hide (collapse) MenuItems that users don't have access to. Of course, you'd need some data bind-able security bool properties which you could then data bind to the MenuItem.Visibility property of each MenuItem via a BooleanToVisibilityConverter. Here's a simple example:
<MenuItem Header="Some option" Visibility="{Binding User.Security.HasSomeOptionPermission,
Converter={StaticResource BooleanToVisibilityConverter}}" ... />
If a particular user has the SomeOptionPermission, then the MenuItem will be displayed, otherwise it will be hidden.

ASP MVC 5 Creating Treeview with check boxes on Leafnode

This is my model structure from which I want to use to create a treeview, with checkboxes on leaf nodes:
public class CategoryEntity : BaseEntity
{
public CategoryEntity()
: base()
{
}
private Guid _categoryId;
public Guid CategoryId
{
get { return _categoryId; }
set { _categoryId = value; InvokePropertyChanged("CategoryId"); IsDirty = true; }
}
private string _categoryname;
public string CategoryName
{
get { return _categoryname; }
set { _categoryname = value; InvokePropertyChanged("CategoryName"); IsDirty = true; }
}
private string _categorydescription;
public string CategoryDescription
{
get { return _categorydescription; }
set { _categorydescription = value; InvokePropertyChanged("CategoryDescription"); IsDirty = true; }
}
private string _categorytype;
public string CategoryType
{
get { return _categorytype; }
set { _categorytype = value; InvokePropertyChanged("CategoryType"); IsDirty = true; }
}
private Guid? _parentcategoryId;
public Guid? ParentCategoryId
{
get { return _parentcategoryId; }
set { _parentcategoryId = value; InvokePropertyChanged("ParentCategoryId"); IsDirty = true; }
}
}
The problem is that I am new to MVC and I don't know which controls to use to display this values in a tree structure. Can anyone suggest a way of doing this?

WPF ViewModel Issue

I have a recursive viewmodel that uses for a treeview. The problem is everytime I delete a Group Item or Entry Item. The treeview cannot reflect the change immediately until I force it by treeview.Items.Refresh(). My guess is the ObservableCollection Items did get notified. Could you one please point me out. Thanks.
ViewModel
public class Group:ViewModelBase
{
private int _key;
public int Key
{
get { return _key; }
set { _key = value; OnPropertyChanged("Key"); }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyChanged("Name"); }
}
private bool _isexpanded;
public bool IsExpanded
{
get { return _isexpanded; }
set { _isexpanded = value; OnPropertyChanged("IsExpanded"); }
}
private int _order;
public int Order
{
get { return _order; }
set { _order = value; OnPropertyChanged("Order"); }
}
private int _grouporder;
public int GroupOrder
{
get { return _grouporder; }
set { _grouporder = value; OnPropertyChanged("GroupOrder"); }
}
private string _error;
public string Error
{
get { return _error; }
set { _error = value; OnPropertyChanged("Error"); }
}
private ObservableCollection<Group> _subgroups;
public ObservableCollection<Group> SubGroups
{
get { return _subgroups; }
set { _subgroups = value;
OnPropertyChanged("SubGroups");
OnPropertyChanged("Entries");
}
}
private ObservableCollection<Entry> _entries;
public ObservableCollection<Entry> Entries
{
get { return _entries; }
set { _entries = value;
OnPropertyChanged("SubGroups");
OnPropertyChanged("Entries"); }
}
public ObservableCollection<object> Items
{
get
{
ObservableCollection<object> childNodes = new ObservableCollection<object>();
foreach (var entry in this.Entries)
childNodes.Add(entry);
foreach (var group in this.SubGroups)
childNodes.Add(group);
return childNodes;
}
}
}
Binding:
public MainWindow()
{
InitializeComponent();
treeview.ItemsSource = Groups;
this.DataContext = this;
}
The issue is that you break the link with the original collections.
So I can imagine two solutions:
1) Register for changes on Entries and SubGroups and apply them back to Items:
private ObservableCollection<object> items;
public ObservableCollection<object> Items
{
get
{
if (items == null)
{
items = new ObservableCollection<object>();
foreach (var entry in this.Entries)
items.Add(entry);
foreach (var group in this.SubGroups)
items.Add(group);
this.Entries.CollectionChanged += (s, a) =>
{
if (/*add some stuff*/)
{
items.Add(/*some stuff*/)
}
else if (/*remove some stuff*/)
{
items.Remove(...)
}
};
this.SubGroups.CollectionChanged += ...
return items;
}
}
}
And you would reset items by setting it to null each time you set Entries or SubGroups so that it is regenerated next time, taking into account new Entries and SubGroups.
2) Try with a CompositeCollection:
new CompositeCollection
{
new CollectionContainer { Collection = this.Entries },
new CollectionContainer { Collection = this.SubGroups }
};
Not sure for this second solution but it would be quite elegant, worth a try...

Finding the root nodes of all the of a tree from a nodes in any generic list

This is a entity and i want to list all the children node for a given node in a generic function
public static List<T> BuildTree<T>(List<T> list, T selectNode string keyPropName, string parentPropName, string levelPropName, int level = 0)
{
List<T> entity = new List<T>();
foreach (T item in list)
{
}
return entity;
}
example of the entity structure
protected long _coakey;
protected long _parentkey;
protected string _coacode;
protected string _coacodeclient;
protected string _coaname;
protected int _coalevel;
[DataMember]
public long coakey
{
get { return _coakey; }
set { _coakey = value; this.OnChnaged(); }
}
[DataMember]
public long parentkey
{
get { return _parentkey; }
set { _parentkey = value; this.OnChnaged(); }
}
[DataMember]
public string coacode
{
get { return _coacode; }
set { _coacode = value; this.OnChnaged(); }
}
[DataMember]
public string coacodeclient
{
get { return _coacodeclient; }
set { _coacodeclient = value; this.OnChnaged(); }
}
[DataMember]
public string coaname
{
get { return _coaname; }
set { _coaname = value; this.OnChnaged(); }
}
[DataMember]
public int coalevel
{
get { return _coalevel; }
set { _coalevel = value; this.OnChnaged(); }
}
Your BuildTree<T> method cannot determine the structure of the tree unless it knows something about its structure. At a very minimum, I would suggest making a base class or interface that defines a tree node, and then change the BuildTree method to work specifically with those types of objects. Then, it will be able to figure out the tree structure. Each of you entity classes would have to implement that tree node interface or inherit from the tree node base class. For instance:
public abstract class TreeNodeBase
{
public long parentkey
{
get { return _parentkey; }
set { _parentkey = value; this.OnChanged(); }
}
protected long _parentkey;
}
public class MyEntityTreeNode : TreeNodeBase
{
public long coakey
{
get { return _coakey; }
set { _coakey = value; this.OnChanged(); }
}
protected long _coakey;
// etc...
}
// Note the generic type constraint at the end of the next line
public static List<T> BuildTree<T>(List<T> list, T selectNode, string keyPropName, string parentPropName, string levelPropName, int level) where T : TreeNodeBase
{
List<T> entity = new List<T>();
foreach (TreeNodeBase node in list)
{
long parentKey = node.parentkey;
// etc...
}
return entity;
}
Node class:
public class Node<TKey, TValue> where TKey : IEquatable<TKey>
{
public TKey Key { get; set; }
public TKey ParentKey { get; set; }
public TValue Data { get; set; }
public readonly List<Node<TKey, TValue>> Children = new List<Node<TKey, TValue>>();
}
TreeBuilder:
public static Node<TKey, TValue> BuildTree<TKey, TValue>(IEnumerable<Node<TKey, TValue>> list,
Node<TKey, TValue> selectNode)
where TKey : IEquatable<TKey>
{
if (ReferenceEquals(selectNode, null))
{
return null;
}
var selectNodeKey = selectNode.Key;
foreach (var childNode in list.Where(x => x.ParentKey.Equals(selectNodeKey)))
{
selectNode.Children.Add(BuildTree(list, childNode));
}
return selectNode;
}
Usage:
List<MyClass> list = ...
var nodes = list.Select(x => new Node<long, MyClass>
{
Key = x.MyKey,
ParentKey = x.MyParentKey,
Data = x
}).ToList();
var startNode = nodes.FirstOrDefault(x => x.Data.Stuff == "Pick me!");
var tree = BuildTree(nodes, startNode);
MyClass example:
public class MyClass
{
public long MyKey;
public long MyParentKey;
public string Name;
public string Text;
public string Stuff;
}
I have solved it my self hope it help you
public static List<T> BuildTree<T>(List<T> list, T selectedNode, string keyPropName, string parentPropName, int endLevel = 0, int level = 0)
{
List<T> entity = new List<T>();
Type type = typeof(T);
PropertyInfo keyProp = type.GetProperty(keyPropName);
string _selectedNodekey = keyProp.GetValue(selectedNode, null).ToString();
PropertyInfo parentProp = type.GetProperty(parentPropName);
foreach (T item in list)
{
string _key = keyProp.GetValue(item, null).ToString();
string _parent = parentProp.GetValue(item, null).ToString();
if (_selectedNodekey == _parent)
{
T obj = (T)Activator.CreateInstance(typeof(T));
obj = item;
entity.Add(obj);
if (level == endLevel && level!=0) break;
entity.AddRange(BuildTree<T>(list, obj, keyPropName, parentPropName, level + 1));
}
}
return entity;
}

Categories

Resources