Creating a Tri-State checkbox component for blazor - checkbox

<input #bind="Checked" type="checkbox" #onclick="eventArgs => { onclick(); }" indeterminate="#indeterminate" class="checkbox-input">
#code {
[Parameter]
public bool? selected { get; set; } = null;
public bool indeterminate { get; set; }
public bool Checked { get; set; }
public void onclick()
{
selected = selected == null ? true : selected == true ? new bool?() : false;
Checked = selected == null || selected == false;
indeterminate = selected == null;
}
}
This doesn't produce the desired result
The checkbox is always either checked or unchecked, never indeterminate.
Any ideas?

I implemented this simple component in .NET core 3.1+.
Here is a fiddle.
The css is from bootstrap, needed to display an empty box, a checked one and a box "full" to indicate the states 0,1,-1 (can change these values easily):
<style>
[class^="icon-"], [class*=" icon-"] { display: inline-block; width: 14px; height: 14px; margin-top: 1px; *margin-right: .3em; line-height: 14px; vertical-align: text-top; background-image: url(/img/glyphicons-halflings.png); background-position: 14px 14px; background-repeat: no-repeat; }
.bootstrap-checkbox { display: inline-block; position: relative; width: 13px; height: 13px; border: 1px solid #000; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
.bootstrap-checkbox i { position: absolute; left: -2px; top: -3px; }
.icon-stop { background-position: -312px -72px; }
.icon-check { background-position: -288px 0px; }
</style>
and this is the blazor component:
<div #ref=checkboxElement class="bootstrap-checkbox" #onclick="(e) => OnClick(e)"><i class="#ImgClass"></i></div>#Description
#code {
public ElementReference checkboxElement { get; set; }
[Parameter]
public string Description { get; set; }
[Parameter]
public bool? Checked { get; set; }
public string ImgClass { get; set; }
public int Value { get; set; }
protected override void OnInitialized()
{
Value = Checked switch { null => -1, true => 1, false => 0 };
ImgClass = Value switch { -1 => "icon-stop", 1 => "icon-check", _ => "" };
}
public void OnClick(MouseEventArgs e)
{
switch (ImgClass)
{
case "":
ImgClass = "icon-check";
Value = 1;
break;
case "icon-check":
ImgClass = "icon-stop";
Value = -1;
break;
case "icon-stop":
ImgClass = "";
Value = 0;
break;
}
}
}

Using JS interop
Create a simple script
<script>
var auxiliarDOM = auxiliarDOM || {};
auxiliarDOM.setValue = function (element, property,value) {
element[property] = value;
}
</script>
Then in blazor you can has a ElementRef
#inject IJSRuntime JSRuntime
<input #ref="checkRef" type="checkbox" />
private ElementReference checkRef;
//this make the check indeterminate
await JSRuntime.InvokeVoidAsync("auxiliarDOM.setValue", checkRef, "indeterminate", true);
//this make the check no indeterminate
await JSRuntime.InvokeVoidAsync("auxiliarDOM.setValue", checkRef, "indeterminate", false);

Tri-state checkbox component, based on Eliseo's answer:
Working example: Blazor fiddle
JS to set the indeterminate attribute:
<script type="text/javascript">
function setElementProperty(element, property, value) {
element[property] = value;
}
</script>
CheckBox.razor file:
<input #ref=elementRef id="#elementId" type="checkbox" checked="#isChecked" #onchange="OnChange"/>
<label for="#elementId">#ChildContent</label>
CheckBox.razor.cs file:
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;
public partial class CheckBox
{
[Inject]
IJSRuntime jsRuntime { get; set; } = null!;
[Parameter]
public RenderFragment? ChildContent { get; set; }
[Parameter]
public bool? Checked { get; set; }
[Parameter]
public EventCallback<bool?> CheckedChanged { get; set; }
private bool isChecked;
private ElementReference elementRef;
private string elementId = Guid.NewGuid().ToString();
private async Task OnChange(ChangeEventArgs e)
{
Checked = Checked switch
{
false => true,
true => null,
null => false,
};
isChecked = Checked != false;
bool indet = Checked == null;
await jsRuntime.InvokeVoidAsync("setElementProperty", elementRef, "indeterminate", indet);
await CheckedChanged.InvokeAsync(Checked);
}
}

Related

Blazor InputCheckbox binding to string backing field

I am trying to make a dynamic form system and I want to be able to bind an InputCheckbox to a database field that's a string rather than a bool...
<EditForm Model="#theEntryResults" OnValidSubmit="#SaveEntries">
<div class="row">
<div class="col-6">
#foreach (var entry in theEntryResults)
{
<div class="form-group m-2">
<label>
#entry.Field.FieldName:
#switch (entry.Field.FieldTypeID)
{
case 0:
<InputText #bind-Value="#entry.Value" class="form-control"></InputText>
break;
case 1:
<InputSelect #bind-Value="#entry.Value" class="form-select">
<option value=""></option>
#foreach (var option in entry.Field.Choices)
{
<option value="#option.Value">#option.Name</option>
}
</InputSelect>
break;
case 2:
<InputCheckbox #bind-Value="#MyValue" class="form-check-inline" style="width: 50px; height: 50px;"></InputCheckbox>
break;
}
</label>
</div>
}
</div>
</div>
<button class="btn btn-success" type="submit">Save</button>
</EditForm>
is what I am trying but entry.Value is a string and so this is giving me "Cannot convert string to bool"
Any ideas?
Thanks!
Bind it to a bool in your code section of the component and then translate in the getters and setters of that.
<InputCheckbox #bind-Value=#MyValue />
#code {
bool MyValue
{
get => Convert.ToBoolean(entry.Value);
set => entry.Value = value.ToString();
}
}
As you are using a for each loop, my recommendation would be to use a child-component for each entry (e.g. EntryViewComponent), so that each child-component is focused on working with an individual entry. In this way, the above suggestion would still apply.
#foreach (var entry in theEntryResults)
{
<EntryViewComponent Entry=#entry />
}
EntryViewComponent
<markup that was previously in the for-each loop>
#code {
[Parameter] public EntryClass Entry { get; set; }
// similar code to first suggestion above
}
If you wish to continue using mark-up inside the for each loop instead of a component, the following may work:
<InputCheckbox Value=#(Convert.ToBoolean(entry.Value))
ValueChanged=#((v) => entry.Value = v.ToString()) />
In this code, instead of auto-binding, you are using different code for the setting of the value of the checkbox and the handling of a value change from the checkbox.
An example to bind string to an InputCheckbox would be by using a component where the string can be converted to boolean and bind to InputCheckBox and vice versa.
Component:
#* MyInputCheckBox.razor *#
<InputCheckbox #bind-Value="isCheck"
class="form-check-inline"
style="width: 50px; height: 50px;"/>
#code {
[Parameter]
public string CheckValueStr { get; set; }
[Parameter]
public EventCallback<string> CheckValueStrChanged { get; set; }
private bool _isCheck;
public bool isCheck
{
get { return _isCheck; }
set {
_isCheck = value;
CheckValueStrChanged.InvokeAsync(value.ToString());}
}
protected override void OnInitialized()
{
isCheck = bool.Parse(CheckValueStr);
}
}
Page:
#page "/"
#using BlazorApp2.Components
<EditForm Model="sample">
<MyInputCheckBox #bind-CheckValueStr="#sample.CheckValue" />
</EditForm>
<br/>
#sample.CheckValue
#code {
private Sample sample = new Sample();
public class Sample
{
public string CheckValue = "false";
}
}
Output:

Add some way to specify indeterminate checkboxes in blazor

Add some way to specify indeterminate checkboxes in blazor.
I have tried below is not worked
<input type="checkbox" indeterminate="#checkValue" onclick="#checkedClick" />
Any one specify indeterminate checkboxes in blazor.
I seems this is not planned for a while. (see https://github.com/dotnet/aspnetcore/issues/10378)
The minimal solution I have found is this ...
Component code
#inject IJSRuntime jsRuntime
<input #ref=inputElement type="checkbox" checked="#Checked" #onchange="OnChange" />
#code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (Indeterminate.HasValue)
{
await jsRuntime.SetElementProperty(inputElement, "indeterminate", Indeterminate.Value);
}
await base.OnAfterRenderAsync(firstRender);
}
private ElementReference inputElement;
[Parameter]
public bool? Indeterminate { get; set; }
[Parameter]
public bool Checked { get; set; }
[Parameter]
public EventCallback<bool> CheckedChanged { get; set; }
private async Task OnChange(ChangeEventArgs e)
{
Checked = (bool)e.Value;
await CheckedChanged.InvokeAsync(Checked);
}
}
Interop C# code
public static async Task SetElementProperty(this IJSRuntime jsRuntime, ElementReference element, string property, object value)
{
await jsRuntime.InvokeVoidAsync("window.jsinterop.setPropByElement", element, property, value);
}
Interop Javascript code
window.jsinterop = {
setPropByElement: function (element, property, value) {
element[property] = value;
}
}

Telerik RadPropertyGrid Content of CollectionEditorPicker

as the topic suggests I wan't to modify the Content of the CollectionEditorPicker. This control is used to open the floating Window for the List of nested Properties.
Unfortunally the RadPropertyGrid don't show any Information about the collection in the Field.
How can I set some value in there? For example a placeholder like "Click here to open the collection" or "xx Items" or "Item 1, Item 2, Item 3..." so see some preview or Information about the field.
I've tried it with a template Selector, but if I'm doing so, the opened Popup is not resizable anymore. Also it looses some Information which are in the default CollectionEditorPicker.
Can you help me?
Below a minimal working Example.
The XAML:
<Window x:Class="TelerikPropertyGridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:model="clr-namespace:TelerikPropertyGridTest.Model"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<model:TemplateSelector x:Key="RadPropertyListTemplateSelector">
<!-- Not Working -->
<model:TemplateSelector.CollectionsDataTemplate>
<DataTemplate>
<telerik:RadDropDownButton Content="Test">
<telerik:RadDropDownButton.DropDownContent>
<telerik:CollectionEditor telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Source"
></telerik:CollectionEditor>
</telerik:RadDropDownButton.DropDownContent>
</telerik:RadDropDownButton>
</DataTemplate>
</model:TemplateSelector.CollectionsDataTemplate>
<model:TemplateSelector.FloatNumberTemplate>
<DataTemplate>
<telerik:RadNumericUpDown telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Value" />
</DataTemplate>
</model:TemplateSelector.FloatNumberTemplate>
<model:TemplateSelector.IntNumberTemplate>
<DataTemplate>
<telerik:RadNumericUpDown telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Value"
NumberDecimalDigits="0" />
</DataTemplate>
</model:TemplateSelector.IntNumberTemplate>
</model:TemplateSelector>
</Grid.Resources>
<telerik:RadPropertyGrid Item="{Binding ObjectToBind}"
AutoGeneratingPropertyDefinition="RadPropertyGrid_OnAutoGeneratingPropertyDefinition"
EditorTemplateSelector="{StaticResource RadPropertyListTemplateSelector}">
</telerik:RadPropertyGrid>
</Grid>
</Window>
The ViewModel (generates a Random Object for testing)
public class MainWindowViewModel : BindableBase
{
private readonly Random _random = new Random();
private IExampleInterface _objectToBind;
public MainWindowViewModel()
{
this.ObjectToBind = new ExampleImplementation
{
SomeBooleanValue = this._random.Next() % 2 == 1,
SomeDateValue = this.RandomDay(),
SomeIntValue = this._random.Next(),
SomeString = Guid.NewGuid().ToString(),
SubClasses = new List<IExampleInterface>
{
new ExampleImplementation
{
SomeBooleanValue = this._random.Next() % 2 == 1,
SomeDateValue = this.RandomDay(),
SomeIntValue = this._random.Next(),
SomeString = Guid.NewGuid().ToString(),
SubClasses = new List<IExampleInterface>
{
new ExampleImplementation
{
SomeBooleanValue =
this._random.Next() % 2 == 1,
SomeDateValue = this.RandomDay(),
SomeIntValue = this._random.Next(),
SomeString = Guid.NewGuid().ToString()
}
}
}
}
};
}
public IExampleInterface ObjectToBind
{
get { return this._objectToBind; }
set
{
if (this._objectToBind != value)
{
this._objectToBind = value;
this.OnPropertyChanged("ObjectToBind");
}
}
}
private DateTime RandomDay()
{
var start = new DateTime(1995, 1, 1);
var range = (DateTime.Today - start).Days;
return start.AddDays(this._random.Next(range));
}
}
The IExampleInterface (should be later on a real Interface):
public interface IExampleInterface
{
string SomeString { get; set; }
int SomeIntValue { get; set; }
double SomeDouble { get; set; }
IList<IExampleInterface> SubClasses { get; set; }
IList<IExampleInterface> SubClasses2 { get; set; }
bool SomeBooleanValue { get; set; }
DateTime SomeDateValue { get; set; }
SomeEnum SomeEnumValue { get; set; }
}
The ExampleImplementation (should have later on a Real Implementation with additional Properties).
public class ExampleImplementation : BindableBase, IExampleInterface
{
private bool _someBooleanValue;
private DateTime _someDateValue;
private double _someDouble;
private SomeEnum _someEnumValue;
private int _someIntValue;
private string _someString;
private ObservableCollection<IExampleInterface> _subClasses;
private ObservableCollection<IExampleInterface> _subClasses2;
public bool SomeBooleanValue
{
get { return this._someBooleanValue; }
set
{
if (this._someBooleanValue != value)
{
this._someBooleanValue = value;
this.OnPropertyChanged("SomeBooleanValue");
}
}
}
public DateTime SomeDateValue
{
get { return this._someDateValue; }
set
{
if (this._someDateValue != value)
{
this._someDateValue = value;
this.OnPropertyChanged("SomeDateValue");
}
}
}
public double SomeDouble
{
get { return this._someDouble; }
set
{
if (Math.Abs(this._someDouble - value) > 0.01)
{
this._someDouble = value;
this.OnPropertyChanged("SomeDouble");
}
}
}
public SomeEnum SomeEnumValue
{
get { return this._someEnumValue; }
set
{
if (this._someEnumValue != value)
{
this._someEnumValue = value;
this.OnPropertyChanged("SomeEnumValue");
}
}
}
public int SomeIntValue
{
get { return this._someIntValue; }
set
{
if (this._someIntValue != value)
{
this._someIntValue = value;
this.OnPropertyChanged("SomeIntValue");
}
}
}
[Display(Name = #"TestString", GroupName = #"TestGroup", Description = #"TestDescription")]
public string SomeString
{
get { return this._someString; }
set
{
if (this._someString != value)
{
this._someString = value;
this.OnPropertyChanged("SomeString");
}
}
}
[Display(Name = #"Some Subclasses")]
public IList<IExampleInterface> SubClasses
{
get { return this._subClasses; }
set
{
if (!Equals(this._subClasses, value))
{
this._subClasses = new ObservableCollection<IExampleInterface>(value);
this.OnPropertyChanged("SubClasses");
}
}
}
public IList<IExampleInterface> SubClasses2
{
get { return this._subClasses2; }
set
{
if (!Equals(this._subClasses2, value))
{
this._subClasses2 = new ObservableCollection<IExampleInterface>(value);
this.OnPropertyChanged("SubClasses2");
}
}
}
}
And finally the TemplateSelector
public class TemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var def = item as PropertyDefinition;
if (def == null || def.SourceProperty == null)
{
return base.SelectTemplate(item, container);
}
if (typeof (IEnumerable).IsAssignableFrom(def.SourceProperty.PropertyType) && typeof(string) != def.SourceProperty.PropertyType)
{
return this.CollectionsDataTemplate;
}
if (typeof (double).IsAssignableFrom(def.SourceProperty.PropertyType))
{
return this.FloatNumberTemplate;
}
if (typeof (int).IsAssignableFrom(def.SourceProperty.PropertyType))
{
return this.IntNumberTemplate;
}
return base.SelectTemplate(item, container);
}
public DataTemplate CollectionsDataTemplate { get; set; }
public DataTemplate FloatNumberTemplate { get; set; }
public DataTemplate IntNumberTemplate { get; set; }
}
This is what I expect
The optimal solution would be to get detailed Information in the TextBlock, like Item 1, item 2 etc.
Thank you.
// Edit:
I've figured out the NullReferenceException and got a Demo to work, so that I can modify the text. But the popup is different to the default. Have you an idea to fix it?
I've updated the text and the example.
After wasting a few hours now I figured out a solution to realize this.
I've added a custom behavior to the Collection template. This behavior sets the Header of the CollectionEditor as soon as it's loaded or updated.
Below you can see my modifications:
The Template:
<model:TemplateSelector.CollectionsDataTemplate>
<DataTemplate>
<telerik:RadDropDownButton Content="Click to edit the collection">
<telerik:RadDropDownButton.DropDownContent>
<telerik:CollectionEditor telerik:AutoBindBehavior.UpdateBindingOnElementLoaded="Source"
ResizeGripperVisibility="Visible">
<i:Interaction.Behaviors>
<model:CollectionEditorBehavior />
</i:Interaction.Behaviors>
</telerik:CollectionEditor>
</telerik:RadDropDownButton.DropDownContent>
</telerik:RadDropDownButton>
</DataTemplate>
</model:TemplateSelector.CollectionsDataTemplate>
The behavior:
internal class CollectionEditorBehavior : Behavior<CollectionEditor>
{
protected override void OnAttached()
{
this.AssociatedObject.SourceUpdated += (sender, args) => this.PrepareHeader();
this.AssociatedObject.DataContextChanged += (sender, args) => this.PrepareHeader();
this.AssociatedObject.Loaded += (sender, args) => this.PrepareHeader();
}
private void PrepareHeader()
{
if (this.AssociatedObject == null)
{
// Error Case
return;
}
if (this.AssociatedObject.CollectionView == null ||
this.AssociatedObject.CollectionView.SourceCollection == null)
{
// Source not set
this.AssociatedObject.Header = "Collection";
return;
}
// Get the property from the DataContext to retrieve HeaderInformation
var propInfo = this.AssociatedObject.DataContext
.GetType()
.GetProperties()
.FirstOrDefault(
propertyInfo =>
Equals(propertyInfo.GetValue(this.AssociatedObject.DataContext),
this.AssociatedObject.CollectionView.SourceCollection));
if (propInfo == null)
{
// We didn't got the property Information, using default value
this.AssociatedObject.Header = "Collection";
return;
}
// Getting the DisplayName Attribute
var attr = Attribute.GetCustomAttribute(propInfo,
typeof (DisplayNameAttribute)) as DisplayNameAttribute;
if (attr != null)
{
// We have a DisplayName attribute
this.AssociatedObject.Header = attr.DisplayName;
return;
}
// Alternative: Get the Display Attribute
var attr2 = Attribute.GetCustomAttribute(propInfo,
typeof (DisplayAttribute)) as DisplayAttribute;
if (attr2 != null)
{
// We have the Display Attribute
this.AssociatedObject.Header = attr2.Name;
return;
}
// We have no DisplayAttribute and no DisplayName attribute, set it to the PropertyName
this.AssociatedObject.Header = propInfo.Name;
}
}

cascading dropdown in angular with key relation between them

I have country and state dropdowns.Country and state has relation on countryid.
I am getting an error while fetching data for these two cascading dropdowns.
Below is the image of error on controller returning JsonResult for countries.
Angular function:
var getdata = fac.GetCountry = function () {
return $http.get('/Data/GetCountries')
};
getdata.then(function (d) {
$scope.CountryList = d.data;
}, function (error) {
alert('Error!');
});
Controller:
public JsonResult GetCountries()
{
List<Country> allCountry = new List<Country>();
using (SunilEntities dc = new SunilEntities())
{
allCountry = dc.Countries.OrderBy(a => a.CountryName).ToList();
}
return new JsonResult { Data = allCountry, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
//return Json(allCountry, JsonRequestBehavior.AllowGet);
}
View:
<div ng-controller="dropdowns">
Country : <select ng-model="CountryID" ng-options="I.CountryID as I.CountryName for I in CountryList" ng-change="GetState()">
<option value="">Select Country</option>
</select>
State : <select ng-model="StateID" ng-options="I.StateID as I.StateName for I in StateList">
<option value="">{{StateTextToShow}}</option>
</select>
<input type="button" value="Get Selected Values" ng-click="ShowResult()"/>
<div style="padding:10px; font-weight:bold; border:1px solid #f3f3f3">
{{Result}}
</div>
</div>
Models:
public partial class Country
{
public Country()
{
this.States = new HashSet<State>();
}
public int CountryID { get; set; }
public string CountryName { get; set; }
public virtual ICollection<State> States { get; set; }
}
public partial class State
{
public int StateID { get; set; }
public string StateName { get; set; }
public Nullable<int> CountryID { get; set; }
public virtual Country Country { get; set; }
public virtual State State1 { get; set; }
public virtual State State2 { get; set; }
}
public DbSet<Country> Countries { get; set; }
public DbSet<State> States { get; set; }
I got the soltution.
BY changing actions (controller) a bit i got the the results.
Controller:-
public JsonResult GetCountries()
{
using (SunilEntities dc = new SunilEntities())
{
var ret = dc.Countries.Select(x => new { x.CountryID, x.CountryName }).ToList();
return Json(ret, JsonRequestBehavior.AllowGet);
}
}
// Fetch State by Country ID
public JsonResult GetStates(int countryID)
{
using (SunilEntities dc = new SunilEntities())
{
var ret = dc.States.Where(x => x.CountryID == countryID).Select(x => new { x.StateID, x.StateName }).ToList();
return Json(ret, JsonRequestBehavior.AllowGet);
}
}
I have country and state dropdowns.Country and state has relation on coutryid.
I am getting an error while fetching data for these two cascading dropdowns.
Below is the image of error on controller returning JsonResult for countries.
Angular funtion:-
var getdata= fac.GetCountry = function () {
return $http.get('/Data/GetCountries')
};
getdata.then(function (d) {
$scope.CountryList = d.data;
}, function (error) {
alert('Error!');
});
View:-
<div ng-controller="dropdowns">
Country : <select ng-model="CountryID" ng-options="I.CountryID as I.CountryName for I in CountryList" ng-change="GetState()">
<option value="">Select Country</option>
</select>
State : <select ng-model="StateID" ng-options="I.StateID as I.StateName for I in StateList">
<option value="">{{StateTextToShow}}</option>
</select>
<input type="button" value="Get Selected Values" ng-click="ShowResult()"/>
<div style="padding:10px; font-weight:bold; border:1px solid #f3f3f3">
{{Result}}
</div>
</div>
Models:-
public partial class Country
{
public Country()
{
this.States = new HashSet<State>();
}
public int CountryID { get; set; }
public string CountryName { get; set; }
public virtual ICollection<State> States { get; set; }
}
public partial class State
{
public int StateID { get; set; }
public string StateName { get; set; }
public Nullable<int> CountryID { get; set; }
public virtual Country Country { get; set; }
public virtual State State1 { get; set; }
public virtual State State2 { get; set; }
}
public DbSet<Country> Countries { get; set; }
public DbSet<State> States { get; set; }

DataGrid: How do I programmatically select DataGrid ComboBox items, WITHOUT manipulating the GUI?

I asked this before and have a solution that works:
See Answer by srithar here
Being new to XAML/WPF, that one was my instinctively preferred solution. However, experts keep on telling us: "DO NOT manipulate the GUI! Handle the model instead."
This is the relevant XAML code:
<DataGridTemplateColumn Header=" Top Plate Thickness ">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding Gauge, Mode=TwoWay}"
DisplayMemberPath="Thickness"
SelectedItem="{Binding TopPlateThickness, UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ComboBoxLeft_SelectionChanged">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsEnabled" Value="{Binding Enabled}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
It currently supports the ability to disable menu items. This is the Code Behind:
static List<string> caliber = new List<string> { "0.3750", "0.5000", "0.6250", "0.7500", "1.0000" };
string left = "";
string right = "";
PlateThicknesses(ref left, ref right, rnd);
Selectable top = new Selectable(left);
Selectable bot = new Selectable(right);
GridsModel gm = new GridsModel()
{
OuterDiameter = outerDiameter,
InnerDiameter = innerDiameter,
TopPlateThickness = top,
BottomPlateThickness = bot
};
static void PlateThicknesses(ref string leftComboBoxIndex, ref string rightComboBoxIndex)
{
int a = rnd.Next(7);
int b = rnd.Next(7);
if (a > b)
{
leftComboBoxIndex = caliber[a];
rightComboBoxIndex = caliber[b];
}
else
{
leftComboBoxIndex = caliber[b];
rightComboBoxIndex = caliber[b];
}
}
Model:
public class GridsModel : PropertyChangedBase
{
public string Item { get; set; }
public string Description { get; set; }
private int _Quantity;
public int Quantity
{
get
{
return _Quantity;
}
set
{
if (_Quantity != value)
{
_Quantity = value;
RaisePropertyChanged("Quantity");
}
}
}
private int _QtyOfFound;
public int QtyOfFound
{
get
{
return _QtyOfFound;
}
set
{
if (_QtyOfFound != value)
{
_QtyOfFound = value;
RaisePropertyChanged("QtyOfFound");
}
}
}
public double MaxBoltLoad { get; set; }
public int NumberOfBolts { get; set; }
public double Separation { get; set; }
private double _Length;
public double Length
{
get
{
return _Length;
}
set
{
if (_Length != value)
{
_Length = value;
RaisePropertyChanged("Length");
}
}
}
public double Gamma { get; set; }
public double Beta { get; set; }
public double OuterDiameter { get; set; }
public double InnerDiameter { get; set; }
public List<Selectable> Gauge { get; set; } // Gauche is "Left" in French
private Selectable _TopPlateThickness;
public Selectable TopPlateThickness
{
get
{
return _TopPlateThickness;
}
set
{
if (_TopPlateThickness != value)
{
_TopPlateThickness = value;
RaisePropertyChanged("TopPlateThickness");
}
}
}
public List<Selectable> Caliber { get; set; } // The Right Stuff
private Selectable _BottomPlateThickness;
public Selectable BottomPlateThickness
{
get
{
return _BottomPlateThickness;
}
set
{
if (_BottomPlateThickness != value)
{
_BottomPlateThickness = value;
RaisePropertyChanged("BottomPlateThickness");
}
}
}
public double BoltCircleDiameter { get; set; }
private double _TemplateSetWeight;
public double TemplateSetWeight
{
get
{
return _TemplateSetWeight;
}
set
{
if (_TemplateSetWeight != value)
{
_TemplateSetWeight = value;
RaisePropertyChanged("TemplateSetWeight");
}
}
}
public double AnchorBoltSetWeight { get; set; }
private double _WholeAnchorCageWeight;
public double WholeAnchorCageWeight
{
get
{
return _WholeAnchorCageWeight;
}
set
{
if (_WholeAnchorCageWeight != value)
{
_WholeAnchorCageWeight = value;
RaisePropertyChanged("WholeAnchorCageWeight");
}
}
}
public GridsModel()
{
Gauge = new List<Selectable> { new Selectable("0.3750"),
new Selectable("0.4375"),
new Selectable("0.5000"),
new Selectable("0.6250"),
new Selectable("0.7500"),
new Selectable("0.8650"),
new Selectable("1.0000") };
Caliber = new List<Selectable> { new Selectable("0.3750"),
new Selectable("0.4370"),
new Selectable("0.5000"),
new Selectable("0.6250"),
new Selectable("0.7500"),
new Selectable("0.8650"),
new Selectable("1.0000") };
}
}
Selectable Class:
public class Selectable : PropertyChangedBase
{
private string _Thickness;
public string Thickness
{
get
{
return _Thickness;
}
set
{
if (_Thickness != value)
{
_Thickness = value;
RaisePropertyChanged("Thickness");
}
}
}
private bool _Enabled;
public bool Enabled
{
get
{
return _Enabled;
}
set
{
if (_Enabled != value)
{
_Enabled = value;
RaisePropertyChanged("Enabled");
}
}
}
public Selectable(string thickness)
{
Thickness = thickness;
Enabled = true;
}
}
Using debugging code I can see that the desired properties are actually being assigned the desired values, but the visual UI fails to display them.
TIA

Resources