How to add checkboxes to a treeview with dynamic ItemsSource? - c#

So I have tried a whole bunch of examples from google, but I cannot seem to give my treeview checkboxes....The only thing I can think of is that it is because my tree's ItemsSource is always changing
An example I was trying is: TreeView with Checkboxes
most noteable, the HierarchicalDataTemplate:
<HierarchicalDataTemplate
x:Key="CheckBoxItemTemplate"
ItemsSource="{Binding Children, Mode=OneTime}"
>
<StackPanel Orientation="Horizontal">
<!-- These elements are bound to a FooViewModel object. -->
<CheckBox
Focusable="False"
IsChecked="{Binding IsChecked}"
VerticalAlignment="Center"
/>
<ContentPresenter
Content="{Binding Name, Mode=OneTime}"
Margin="2,0"
/>
</StackPanel>
</HierarchicalDataTemplate>
and I set my tree's ItemTemplate to:
ItemTemplate="{StaticResource CheckBoxItemTemplate}"
But I see no checkboxes. I think it is because in the example, the data is bound to Children...but in my example, I am always changing the itemsSource (moving from tree to tree, or editting it, and adding it back to the tree etc)...
Anyone know how to make it work?
Thanks!
*EDIT*
adding the treeview itemsSource I just go
tv_master.ItemsSource = t.TreeItems;
Where the t.TreeItems is a List which holds the top level nodes..
my treeview:
<my:SpecTreeView Margin="8,8,0,12"
x:Name="tv_local"
TreeViewItem.Selected="node_Selected" HorizontalAlignment="Left" Width="304"
x:FieldModifier="private" BorderBrush="Black">
The original class used by the person who wrote the checkbox code:
using System.Collections.Generic;
using System.ComponentModel;
namespace TreeViewWithCheckBoxes
{
public class FooViewModel : INotifyPropertyChanged
{
#region Data
bool? _isChecked = false;
FooViewModel _parent;
#endregion // Data
#region CreateFoos
public static List<FooViewModel> CreateFoos()
{
FooViewModel root = new FooViewModel("Weapons")
{
IsInitiallySelected = true,
Children =
{
new FooViewModel("Blades")
{
Children =
{
new FooViewModel("Dagger"),
new FooViewModel("Machete"),
new FooViewModel("Sword"),
}
},
new FooViewModel("Vehicles")
{
Children =
{
new FooViewModel("Apache Helicopter"),
new FooViewModel("Submarine"),
new FooViewModel("Tank"),
}
},
new FooViewModel("Guns")
{
Children =
{
new FooViewModel("AK 47"),
new FooViewModel("Beretta"),
new FooViewModel("Uzi"),
}
},
}
};
root.Initialize();
return new List<FooViewModel> { root };
}
FooViewModel(string name)
{
this.Name = name;
this.Children = new List<FooViewModel>();
}
void Initialize()
{
foreach (FooViewModel child in this.Children)
{
child._parent = this;
child.Initialize();
}
}
#endregion // CreateFoos
#region Properties
public List<FooViewModel> Children { get; private set; }
public bool IsInitiallySelected { get; private set; }
public string Name { get; private set; }
#region IsChecked
/// <summary>
/// Gets/sets the state of the associated UI toggle (ex. CheckBox).
/// The return value is calculated based on the check state of all
/// child FooViewModels. Setting this property to true or false
/// will set all children to the same check state, and setting it
/// to any value will cause the parent to verify its check state.
/// </summary>
public bool? IsChecked
{
get { return _isChecked; }
set { this.SetIsChecked(value, true, true); }
}
void SetIsChecked(bool? value, bool updateChildren, bool updateParent)
{
if (value == _isChecked)
return;
_isChecked = value;
if (updateChildren && _isChecked.HasValue)
this.Children.ForEach(c => c.SetIsChecked(_isChecked, true, false));
if (updateParent && _parent != null)
_parent.VerifyCheckState();
this.OnPropertyChanged("IsChecked");
}
void VerifyCheckState()
{
bool? state = null;
for (int i = 0; i < this.Children.Count; ++i)
{
bool? current = this.Children[i].IsChecked;
if (i == 0)
{
state = current;
}
else if (state != current)
{
state = null;
break;
}
}
this.SetIsChecked(state, false, true);
}
#endregion // IsChecked
#endregion // Properties
#region INotifyPropertyChanged Members
void OnPropertyChanged(string prop)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
My TNode Class
public class TNode : TreeViewItem{
public int Level { get; set; }
public Boolean IsCheckedStr { get; set; }
public string Section { get; set; }
public string Note { get; set; }
public Boolean Locked { get; set; }
public string ID { get; set; }
public int Hierarchy { get; set; }
public string Type { get; set; }
public Boolean HasChildren { get; set; }
public string TextBlock { get; set; }
public Boolean ShowDetails { get; set; }
public List<TNode> Dependencies { get; set; }
public TNode(string id) {
ID = id;
Dependencies = new List<TNode>();
}
I just want to get the checkboxes to appear for now :(
Let me know if there is anything else you would like to see

Edit: DataTemplates are for data, TreeViewItems or subclasses thereof are not data, the template will be ignored. You should see an error regarding this in the Output-window of Visual Studio (which is helpful for debugging databinding issues of any sort).
See nothing wrong with this, you might want to post the code behind for the classes, and the TreeView instance declaration.
A common error is the lack of notifying interfaces. Also: Did you bind the ItemsSource of the TreeView itself to a root-list of items?

Related

WPF databinding and refreshing its UI

I've posted the same question before but it wasn't clear (and contained too many self-induced errors in attempt to fix the code) so re-posting it with more details.
So I have "MainUiWindow.xaml" file which uses databinding like this:
<ItemsControl x:Name="gridSettingsMonster" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding SettingsMonster}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type core:Setting}">
<Grid x:Name="gridMonster">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Label}" IsEnabled="{Binding Enabled}" ToolTip="{Binding Description}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10 5 10 5" FontWeight="{Binding Fontweight}" ></TextBlock>
<ts:ToggleSwitch x:Name="toggleSwitchMonsterAll" IsEnabled="{Binding Enabled}" Grid.Row="0" Grid.Column="1" Command ="{Binding TriggerAction}" IsChecked="{Binding Value}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5 0 20 2" Foreground="White" UncheckedText="" CheckedText="" UncheckedBorderBrush="#FF333333" CheckedBorderBrush="#FF2D2D30"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
SettingsMonster binding:
SettingsMonster.Add(new Setting(ConfigHelper.Main.Values.Overlay.MonsterWidget.IsVisible, true, "Monster_1", "Monster Widget", "Show/Hide Monsters Widget", new Command(_ =>
{
ConfigHelper.Main.Values.Overlay.MonsterWidget.IsVisible = !ConfigHelper.Main.Values.Overlay.MonsterWidget.IsVisible;
ConfigHelper.Main.Save();
})));
SettingsMonster.Add(new Setting(ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowUnchangedMonsters, ConfigHelper.Main.Values.Overlay.MonsterWidget.IsVisible, "Monster_2", " Show unchanged monsters", "Automatically hide monsters if they are not damaged", new Command(_ =>
{
ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowUnchangedMonsters = !ConfigHelper.Main.Values.Overlay.MonsterWidget.ShowUnchangedMonsters;
ConfigHelper.Main.Save();
})));
And finally, the Setting class:
public class Setting
{
public bool Value { get; set; }
public bool Enabled { get; set; }
public string Name { get; }
public string Label { get; }
public string Description { get; }
public string Checkbox_visibility { get; }
public string Fontweight { get; }
public List<Setting>SubSettings { get; }
public Command TriggerAction { get; }
public Setting(bool value, bool enabled, string name, string label, string description, Command action = null)
{
Value = value;
Enabled = enabled;
Name = name;
Label = label;
Description = description;
SubSettings = new List<Setting>();
TriggerAction = action;
}
}
Problem:
When I run the build and use the "ToggleSwitch" (it's basically a open-source checkbox) to change the value of "ConfigHelper.Main.Values.Overlay.MonsterWidget.IsVisible", it unchecks the UI correctly.
I want this checkbox to control the other checkboxes (i.e. "Monster_2") as well, so that when the main one is turned off, set IsEnabled value for the child checkboxes/textblocks to FALSE.
I got to the stage where if I check off the main one, restart the build, then the child checkboxes/textblocks are all set as IsEnabled=False. However, I want the same to happen in real time (i.e. refresh the UI without having to restart).
Any help would be appreciated.
EDIT 1.
So I have attempted implementing the INotifyPropertyChanged in my Settings class which looks like the following:
public class Setting : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _value;
private bool _enabled;
public bool Value
{
get
{
return _value;
}
set
{
if (_value == value)
return;
_value = value;
OnPropertyChanged(nameof(Enabled));
}
}
public bool Enabled
{
get
{
return _enabled;
}
set
{
if (_enabled == value)
return;
_enabled = value;
OnPropertyChanged(nameof(Enabled));
}
}
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public string Name { get; }
public string Label { get; }
public string Description { get; }
public string Checkbox_visibility { get; }
public string Fontweight { get; }
public List<Setting>SubSettings { get; }
public Command TriggerAction { get; }
public Setting(bool value, bool enabled, string name, string label, string description, Command action = null)
{
Value = value;
Enabled = enabled;
Name = name;
Label = label;
Description = description;
SubSettings = new List<Setting>();
TriggerAction = action;
}
But my UI is still not refreshing yet... any help?
My viewmodel was referencing incorrect variable in the first place.
I have implemented INotifyPropertyChange in my Setting object as below, and also added a command to be run when the checkbox is triggered.
public class Setting : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
private bool _value;
private bool _enabled;
public bool Value
{
get
{
return _value;
}
set
{
if (_value == value)
return;
_value = value;
OnPropertyChanged(nameof(Value));
}
}
public bool Enabled
{
get
{
return _enabled;
}
set
{
if (_enabled == value)
return;
_enabled = value;
OnPropertyChanged(nameof(Enabled));
}
}
public string Name { get; }
public string Label { get; }
public string Description { get; }
public string Fontweight { get; }
public List<Setting>SubSettings { get; }
public Command TriggerAction { get; }
public Setting(bool _value, bool _enabled, string name, string label, string description, Command action = null)
{
Value = _value;
Enabled = _enabled;
Name = name;
Label = label;
Description = description;
SubSettings = new List<Setting>();
TriggerAction = action;
}
}

How to copy OberservableCollection List in listview from api query items to new listview

I'm having trouble copying data from one ObservableCollection to another. I have an api call GetItemsAsync from http that puts the response into a model called ShipList.cs. Inside of ShipList.cs there is ShipCatalog[] ships. I have created a second model called HangarList.cs with HangarCatalog[] hangars. I have a page that displays the master list of ships (ShipsList) I want the user to select the ship (ShipList.name is bound to this particular ListVIew. I tried to use .Where() to filter ShipList to only the match to the selected item and copy that data to HangarCatalog. I'm getting Cannot convert GallogForms.Api.ShipCatalog to GallogForms.Api.HangarCatalog using the following code.
ViewModel
private ShipCatalog _selectedShip;
public ShipCatalog SelectedShip
{
get {return _selectedShip; }
set
{if (_selectedShip != value)
_selectedShip = value;
id = _selectedShip.id;
CopyShipData();
private async void CopyShipData()
{
var _container = Items.Where(s =>
s.name.FirstOrDefault().ToString() == id.ToString()).ToList();
foreach (var item in _container.Where(s =>
s.name.FirstOrDefault().ToString() == id.ToString()).ToList())
// var items = await _gallogClient.GetItemsAsync<ShipList>();
// foreach (var item in items.ships.Where(s =>
// s.name.FirstOrDefault().ToString() == id.ToString()).ToList())
{
Hangars.Clear();
Hangars.Add(item);
}
}
I haven't found any answer yet, and I've read plenty, that can address my situation. myShipsList is bound to a new model I've created in the API that perfectly mirrors ShipCatalog[].
I've also keep running across answers that suggest ListViewItem.Item or in my case SuggestedShipView.Items. .Items is not an option for my ListViews in the view model.
AddShipPage.xaml
<StackLayout Orientation="Vertical">
<SearchBar x:Name="HangarListView" Text="Add To Your Fleet!"
TextChanged="HangarList_TextChanged"
BackgroundColor="Azure"
/>
<Grid>
<ListView x:Name="SuggestedShipView"
ItemsSource="{Binding Items}"
SelectedItem="{Binding selectedShip}"
BackgroundColor="Silver">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
.....................
ShipList.cs (API Query)
[ApiPath("ships")]
public class ShipList : ApiQueryable
{
public ShipCatalog[] ships { get; set; }
}
public class ShipCatalog : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public int id { get; set; }
public string name { get; set; }
public string uri { get; set; }
public int rsi_id { get; set; }
public string img { get; set; }
public string mfr { get; set; }
public string flyable { get; set; }
public string scu { get; set; }
public string value { get; set; }
public string bgcolor { get; set; }
public string color { get; set; }
public string role { get; set; }
public bool _isVisible { get; set; }
public bool IsVisible
{
get { return _isVisible; }
set
{
if (_isVisible != value)
{
_isVisible = value;
OnPropertyChanged();
}
}
}
}
}
HangarList mirrors ShipList perfectly with the exception it's named HangarList, public HangarCatalog[] hangars
And Finally, the query which populates ShipCatalog[]
AddShipViewModel
Items.Clear();
var items = await _gallogClient.GetItemsAsync<ShipList>();
foreach (var item in items.ships.ToList())
{
Items.Add(item);
}
No error messages per se, but I have not been able to structure a method to complete this task. If you would like to see the entire project to see more of what I have going on, http://github.com/dreamsforgotten/GallogMobile
when you tap or select an item in a ListView, the second parameter of the event handler will contain a reference to the item selected/tapped. You just need to cast it to the correct type. Then you can reference all of its properties as needed
private void SuggestedShipView_ItemTapped(object sender, ItemTappedEventArgs e)
{
// e.Item is the specific item selected
ShipCatalog ship = (ShipCatalog)e.Item;
// you can then use this ship object as the data source for your Hangar list/control,
// and/or add it to another List that is just the items the user has selected
}

Select item from combo box WPF from view model in C# WPF

I have the following view model:
public sealed class FileViewModel : AbstractPropNotifier
{
private string _path;
private CategoryViewModel _category;
public string Path
{
get
{
return _path;
}
set
{
_path = value;
OnPropertyChanged(nameof(Path));
OnPropertyChanged(nameof(Title));
}
}
public string Title => System.IO.Path.GetFileNameWithoutExtension(Path);
public CategoryViewModel Category
{
get
{
return _category;
}
set
{
_category = value;
OnPropertyChanged(nameof(Category));
}
}
}
and Category view model:
public sealed class CategoryViewModel : IEquatable<CategoryViewModel>
{
public string Title { get; set; }
public EMyEnum Value { get; set; }
public bool Equals(CategoryViewModel other)
{
return Title.Equals(other.Title) && Value == other.Value;
}
public static CategoryViewModel From(EMyEnum eCat)
{
return new CategoryViewModel
{
Title = eCat.DescriptionAttr(),
Value = eCat
};
}
}
I set data context to my view model like:
public sealed class MainViewModel
{
public MainViewModel()
{
Files = new ObservableCollection<FileViewModel>();
Categories = GetCategories();
}
public ObservableCollection<FileViewModel> Files { get; set; }
public CategoryViewModel[] Categories { get; set; }
private CategoryViewModel[] GetCategories()
{
var enums = Enum.GetValues(typeof(EMyEnum));
var list = new List<CategoryViewModel>();
foreach (var en in enums)
{
EMyEnum cat = (EMyEnum)en;
list.Add(CategoryViewModel.From(cat));
}
return list.ToArray();
}
}
and
_model = new MainViewModel();
DataContext = _model;
and XAML:
<Window.Resources>
<CollectionViewSource x:Key="Categories" Source="{Binding Categories}"/>
</Window.Resources>
and in DataGrid element
<DataGridComboBoxColumn SelectedItemBinding="{Binding Category}" ItemsSource="{Binding Source={StaticResource Categories}}" Header="Category" Width="2*" DisplayMemberPath="Title"/>
The dropdown is populated correctly but cannot select automatically from dropdown a specific Category, means the Category column from Datagrid is empty.
I expected to select automatically from dropdown with correspondent Category...
Where is my mistake ? I tried with SelectedItemBinding and SelectedValueBinding but same issue. Nothing selected from dropdown.
To be clear:
For a file, I set a category but nothing is selected:
But dropdown has items:
There are probably different instances of CategoryViewModels in your MainViewModel compared to the ones in the FileViewModels.
You should either override Equals and GetHashCode in your CategoryViewModel class or make sure that you set the Category property of each FileViewModel to a CategoryViewModel that's actually present in the CategoryViewModel[] array of the MainViewModel.

DataContext: Updating comboBox's ItemSource

I want to be able to update a ComboBox within my Gird. I'm assuming I need some sort of event system.
I've bound it as follows:
<ComboBox Name="ScreenLocations" Grid.Row="1" Margin="0,0,0,175" ItemsSource="{Binding Path=CurrentPlayer.CurrentLocation.CurrentDirections}" DisplayMemberPath="Name" SelectedValuePath="Name" SelectedValue="{Binding Path= Location}"/>
my xaml.cs is as follows:
public partial class MainWindow : Window
{
GameSession _gameSession;
public MainWindow()
{
InitializeComponent();
_gameSession = new GameSession();
DataContext = _gameSession;
}
}
I want to be able to change the CurrentDirections property and to have it updated in the UI.
The class and properties I have it bound to is:
public class Location
{
public int ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Quest[] AvailableQuests { get; set; }
public Monster[] LocationMonsters { get; set; }
public Location[] CurrentDirections { get; set; }
public Location(string name, string description, Quest[] availableQuests, int id)
{
Name = name;
Description = description;
AvailableQuests = availableQuests;
ID = id;
CurrentDirections = new Location[] { };
LocationMonsters = new Monster[] { };
AvailableQuests = new Quest[] { };
}
}
You just need to implement interface System.ComponentModel.INotifyPropertyChanged on class Location. This will oblige you to define a PropertyChanged event that interested parties (such as the bound ComboBox) can subscribe to in order to detect changes, and you can then reimplement CurrentDirections as follows, such that it notifies interested parties of the change via this event :
private Location[] currentDirections;
public Location[] CurrentDirections
{
get {return currentDirections;}
set {currentDirections = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("CurrentDirections"));}
}
For completeness you should consider implementing this interface on Player, and for the other properties of Location.

WPF Binding GridView to Element in collection

I'm creating a form that will allows user to add filters to data for processing.
I have setup:
public Class RuleGroup
{
public ObservableCollection<Rule> Rules {get; set;}
...
}
public Class Rule
{
public ObservableCollection<String> Fields {get; set;}
public ObservableCollection<Rule> Rules {get; set;}
...
}
public class Criteria
{
public int ItemId{ get; set;}
public string Field{ get; set;}
public OperationType Operation{ get; set;}
public string Value {get; set;}
public string Value2 {get; set;}
}
So a Rule has a List of Criteria that must be matched if the rule is to be applied. Each Criteria in a Rule must specify a value for every field selected. The Amount of fields may vary from One RuleGroup to the next.
I am trying to set up a form that is user friendly when creating multiple Rules. I was thinking of having a GridView on the form that is some how bound to this class layout.
Rule = Row
Criteria = Column
Currently I have function that generates a DataTable based on the Rules/Criteria as the user move from one RuleGroup to the next, but I think there my be an nicer solution to this
Any ideas or help would be much appreciated
Thanks
Right Think I have got it.
Needed to change my Classes around a bit to get the correct groups / hierarchy. I have then been able to bind the column using the items index in the collection.
This has given me the outcome I wanted, Though there is a minor issue where I would like to be able to access the index using the string Name rather then the position. I am currently having to make sure that the "Criterion" are in the correct order when accessing the values.
Here is a link to the Source code
Rule Group
public class RuleGroup
{
public String Description { get; set; }
public ObservableCollection<Rule> Rules { get; set; }
public RuleGroup()
{
Rules = new ObservableCollection<Rule>();
}
}
Rule
public class Rule
{
public Rule()
{
Criteria = new ObservableCollection<Criteria>();
}
public String Description { get; set; }
public ObservableCollection<Criteria> Criteria { get; set; }
readonly ObservableCollection<RuleField> _Fields = new ObservableCollection<RuleField>();
public IEnumerable<RuleField> Fields
{
get
{
return _Fields;
}
}
public void AddField(string name, string header)
{
if (_Fields.FirstOrDefault(i => i.Name == name) == null)
{
RuleField field = new RuleField(_Fields.Count)
{
Name = name,
Header = header
};
_Fields.Add(field);
AddFieldToCriteria(field);
}
}
void AddFieldToCriteria(RuleField field)
{
foreach (Criteria c in Criteria)
{
if (c.Values.FirstOrDefault(i => i.Field == field) == null)
c.Values.Add(new Criterion() { Field = field, Operation = 1 });
}
}
}
Criteria
public class Criteria
{
public Criteria()
{
Values = new ObservableCollection<Criterion>();
}
public ObservableCollection<Criterion> Values { get; set; }
public Criterion this[int index]
{
get
{
return Values.OrderBy(i=>i.Field.Position).ElementAt(index);
}
set
{
Criterion c = Values.OrderBy(i => i.Field.Position).ElementAt(index);
c= value;
}
}
}
Criterion
public class Criterion
{
public RuleField Field { get; set; }
public int Operation { get; set; }
public object Value { get; set; }
public object Value2 { get; set; }
}
RuleField
public class RuleField
{
public string Name { get; set; }
public string Header { get; set; }
int _Position = 0;
public int Position
{
get
{
return _Position;
}
}
public RuleField(int position)
{
_Position = position;
}
}
View Model
public delegate void UpdateColumnsEventHandler(object sender, UpdateColumnsEventArgs e);
public class UpdateColumnsEventArgs
{
public IEnumerable<RuleField> Columns { get; set; }
public UpdateColumnsEventArgs()
{
Columns = new List<RuleField>();
}
public UpdateColumnsEventArgs(IEnumerable<RuleField> columns)
{
Columns = columns;
}
}
public class MainWindowViewModel
{
public event UpdateColumnsEventHandler UpdateColumns;
public ObservableCollection<RuleGroup> RuleGroups { get; set; }
RuleGroup _SelectedRuleGroup = null;
public RuleGroup SelectedRuleGroup
{
get
{
return _SelectedRuleGroup;
}
set
{
if (_SelectedRuleGroup == value)
return;
_SelectedRuleGroup = value;
}
}
public Rule _SelectedRule = null;
public Rule SelectedRule
{
get
{
return _SelectedRule;
}
set
{
if (_SelectedRule == value)
return;
_SelectedRule = value;
if (UpdateColumns != null)
UpdateColumns(this, new UpdateColumnsEventArgs(_SelectedRule.Fields));
}
}
public MainWindowViewModel()
{
RuleGroups = new ObservableCollection<RuleGroup>();
RuleGroup rg = new RuleGroup();
rg.Description = "Rule Group A";
Rule r = new Rule();
r.Description = "Rule 1";
Random random = new Random();
int range = 10000;
for (int x = 0; x < 2000; x++)
{
Criteria c = new Criteria();
c.Values.Add(new Criterion()
{
Field = new RuleField(0)
{
Name = "A",
Header = "A Column"
},
Operation = 1,
Value = "X"
});
c.Values.Add(new Criterion()
{
Field = new RuleField(0)
{
Name = "B",
Header = "B Column"
},
Operation = 1,
Value = x % 10
});
r.Criteria.Add(c);
}
#region Fields
r.AddField("A", "A Column");
r.AddField("B", "B Column");
r.AddField("C", "C Column");
#endregion
rg.Rules.Add(r);
r = new Rule();
r.Description = "Rule 2";
for (int x = 0; x < 1750; x++)
{
r.Criteria.Add(new Criteria());
}
#region Fields
r.AddField("A", "A Column");
r.AddField("B", "B Column");
#endregion
rg.Rules.Add(r);
RuleGroups.Add(rg);
}
}
WPF Window
<Window x:Class="RuleMappingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:RuleMappingTest"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:MainWindowViewModel UpdateColumns="UpdateGridColumns"/>
</Window.DataContext>
<Grid Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<ListBox Grid.Row="0" ItemsSource="{Binding RuleGroups}" SelectedItem="{Binding SelectedRuleGroup}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Grid.Row="1" ItemsSource="{Binding SelectedRuleGroup.Rules}" SelectedItem="{Binding SelectedRule}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<DataGrid x:Name="CriteriaGrid" Grid.Row="2" ItemsSource="{Binding SelectedRule.Criteria}" AutoGenerateColumns="False" >
</DataGrid>
</Grid>
</Window>
WPF Code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void UpdateGridColumns(object sender, UpdateColumnsEventArgs e)
{
CriteriaGrid.Columns.Clear();
foreach (RuleField rf in e.Columns)
{
DataGridTextColumn c = new DataGridTextColumn();
c.Header = rf.Header;
Binding b = new Binding(String.Format("[{0}].Value", rf.Position));
CriteriaGrid.Columns.Add(c);
c.Binding = b;
}
}
}

Categories