C# WPF ComboBox Auto switch number [closed] - c#

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
How can i manage auto switch number in ComboBox in short simple way?

You should not do this in that way. You should present the user swappable user controls which user can drag and drop, changing order with the mouse.
Your solution is not that good, but if you still want to do this, then in combobox selectitem event look through other comboboxes with that value and change it to the previous one.

You can add separate properties in your ViewModel and separate ComboBoxes in the view, then manipulate the values when a value changes in the ViewModel, but this is cumbersome, and involves a lot of work when you add a new ComboBox (value).
A better approach is to create a custom collection that handles the changes:
public class ValueHolder<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value; }
set
{
if (!EqualityComparer<T>.Default.Equals(value, _value))
{
T old = _value;
_value = value;
OnPropertyChanged("Value");
OnValueChanged(old, value);
}
}
}
public ValueHolder()
{
}
public ValueHolder(T value)
{
this._value = value;
}
public event EventHandler<ValueChangedEventArgs<T>> ValueChanged;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnValueChanged(T oldValue, T newValue)
{
var h = ValueChanged;
if (h != null)
h(this, new ValueChangedEventArgs<T>(oldValue, newValue));
}
protected virtual void OnPropertyChanged(string propName)
{
var h = PropertyChanged;
if (h != null)
h(this, new PropertyChangedEventArgs(propName));
}
}
public class ValueChangedEventArgs<T> : EventArgs
{
public T OldValue { get; set; }
public T NewValue { get; set; }
public ValueChangedEventArgs(T oldValue, T newValue)
{
this.OldValue = oldValue;
this.NewValue = newValue;
}
}
public class MyCollection<T> : Collection<ValueHolder<T>>
{
public void Add(T i)
{
this.Add(new ValueHolder<T>(i));
}
private void AddChangeHandler(ValueHolder<T> item)
{
item.ValueChanged += item_ValueChanged;
}
private void RemoveChangeHandler(ValueHolder<T> item)
{
item.ValueChanged -= item_ValueChanged;
}
protected override void InsertItem(int index, ValueHolder<T> item)
{
AddChangeHandler(item);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
RemoveChangeHandler(this[index]);
base.RemoveItem(index);
}
protected override void ClearItems()
{
foreach (var item in this)
{
RemoveChangeHandler(item);
}
base.ClearItems();
}
protected override void SetItem(int index, ValueHolder<T> item)
{
RemoveChangeHandler(this[index]);
AddChangeHandler(item);
base.SetItem(index, item);
}
private void item_ValueChanged(object sender, ValueChangedEventArgs<T> e)
{
ValueHolder<T> v = (ValueHolder<T>)sender;
for (int i = 0; i < this.Count; i++)
{
if (this[i] == v)
continue;
if (EqualityComparer<T>.Default.Equals(this[i].Value, e.NewValue))
{
this[i].Value = e.OldValue;
break;
}
}
}
}
Then define your ViewModel like this:
public class MyViewModel
{
private MyCollection<int> _values;
public MyViewModel()
{
_values = new MyCollection<int>() { 1, 2, 3, 4, 5 };
}
public MyCollection<int> Values
{
get { return _values; }
}
}
and in your xaml:
<ItemsControl ItemsSource="{Binding Path=Values}" Margin="10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding Path=Value}" Margin="5">
<ComboBox.ItemsSource>
<Int32Collection >1,2,3,4,5</Int32Collection>
</ComboBox.ItemsSource>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is a lot of code! But does the task nicely, and also is very maintainable.

Just switch values in your data model. As a result wpf controls will be updated when properties of the data model are changed.
XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<model:DataModel x:Key="MyModel" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl Grid.Column="0" Grid.Row="0" DataContext="{StaticResource MyModel}"
ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding Items}">
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
Code:
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
namespace WpfApplication2
{
public class DataModel
{
#region Construction and Initialization
public DataModel()
{
var elements = new[] {1, 2, 3, 4, 5};
Items = new List<ItemsModel>
{
new ItemsModel(elements, 1),
new ItemsModel(elements, 2),
new ItemsModel(elements, 3),
new ItemsModel(elements, 4),
new ItemsModel(elements, 5)
};
foreach (var itemsModel in Items)
{
itemsModel.PropertyChanged += SelectedItemChanged;
}
}
#endregion
public List<ItemsModel> Items { get; private set; }
private void SelectedItemChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedItem")
{
var model = sender as ItemsModel;
Debug.Assert(model != null, "model != null");
int pos = Items.IndexOf(model) + 1;
Items[model.SelectedItem - 1].SelectedItem = pos;
}
}
}
public class ItemsModel: INotifyPropertyChanged
{
#region Construction and Initialization
public ItemsModel(IEnumerable<int> items, int selectedItem)
{
Items = items;
_selectedItem = selectedItem;
}
#endregion
public int SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
RaisePropertyChanged("SelectedItem");
}
}
}
private int _selectedItem;
public IEnumerable<int> Items { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

Related

Revit API WPF C#: Check All button for Check Boxes in Listbox

I'm pretty new to programming with WPF and C# and I have a question regarding the possibility to automatically check all the CheckBoxes in a Listbox. I'm developing a plugin for Autodesk Revit and, after having listed all the names of the rooms in a list box, I want to check them all using the button "Check All"
I've read the thread at this page but still, I'm not able to make it work. May someone help me with my code?
Here is what I've done:
XAML:
<ListBox x:Name='roomlist'
SelectionMode='Multiple'>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked='{Binding IsChecked}'
Content="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.InputBindings>
<KeyBinding Command="ApplicationCommands.SelectAll"
Modifiers="Ctrl"
Key="A" />
</ListBox.InputBindings>
<ListBox.CommandBindings>
<CommandBinding Command="ApplicationCommands.SelectAll" />
</ListBox.CommandBindings>
</ListBox>
C#
public partial class RoomsDistance_Form : Window
{
UIDocument _uidoc;
Document _doc;
public RoomsDistance_Form(Document doc, UIDocument uidoc)
{
InitializeComponent();
FilteredElementCollector collector = new FilteredElementCollector(doc)
.WhereElementIsNotElementType()
.OfCategory(BuiltInCategory.OST_Rooms);
List<String> myRooms = new List<String>();
foreach (var c in collector)
{
myRooms.Add(c.Name);
}
myRooms.Sort();
roomlist.ItemsSource = myRooms;
}
private void checkAllBtn_Click(object sender, RoutedEventArgs e)
{
foreach (CheckBox item in roomlist.Items.OfType<CheckBox>())
{
item.IsChecked = true;
}
}
public class Authority : INotifyPropertyChanged
{
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Thank you very much for your help!
In the thread you are linking to, they are setting the "IsChecked" on the data object (Authority), not the CheckBox control itself.
foreach (var a in authorityList)
{
a.IsChecked = true;
}
You have a binding to IsChecked that will update the Checkbox control when NotifyPropertyChanged() is called.
After having lost my mind in the effort i solved my problem by avoiding the Listbox.. I simply added single CheckBoxes in the StackPanel.
XAML:
<ScrollViewer Margin='10,45,10,100'
BorderThickness='1'>
<StackPanel x:Name='stack'
Grid.Column='0'></StackPanel>
</ScrollViewer>
C#:
foreach (var x in myRooms)
{
CheckBox chk = new CheckBox();
chk.Content = x;
stack.Children.Add(chk);
}
Not what i was looking for but now it works and that's the point.
Thank you for your help!
I usually use CheckBoxList in the following way:
In xaml:
<ListBox ItemsSource="{Binding ListBoxItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> //+some dimensional properties
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In xaml.cs:
public partial class MyWindow : Window
{
public ViewModel ViewModel {get; set; }
public MyWindow(ViewModel viewModel)
{
//keep all the mess in ViewModel, this way your xaml.cs will not end up with 1k lines
ViewModel = viewModel;
DataContext = ViewModel;
InitializeComponent();
}
void BtnClick_SelectAll(object sender, RoutedEventArgs e)
{
ViewModel.CheckAll();
}
}
ViewModel preparation:
public class ViewModel
{
public List<ListBoxItem> ListBoxItems { get; set; }
//InitializeViewModel()...
//UpdateViewModel()...
//other things....
public void CheckAll()
{
foreach (var item in ListBoxItems)
{
item.IsSelected = true;
}
}
public class ListBoxItem : INotifyPropertyChanged
{
public string Name { get; set; }
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
OnPropertyChanged(nameof(IsSelected));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Get SelectedItem or SelectedItems in a ListBox that is updated to bind to ViewModel using MVVM

I'm creating a WPF Network Scanning application using .NET Framework 4.7.2 with Caliburn Micro and a strict MVVM pattern. I have been going through all the similar questions to this one but yet to find a solution. I don't use code-behind and so I am trying to do everything MVVM style.
My ListBox is initially empty and items are added to it until my scan is complete. After this I try to select 1 OR multiple items in the ListBox even though visually the items can be multiply selected, the problem I am finding is that I am unable to bind SelectedItem in my ListBox View with the SelectedItem property. I.e. SelectedItem property in my ViewModel will not update and remains at null.
I want my SelectedItems collection to increment as more items are selected.
I have tried the following:
Binding the IsSelected property of ListBoxItem to DataContext of Itemssource
Get ListBox SelectedItems
These have not worked so far.
Example Model:
public class ExampleModel
{
protected int _id;
protected string _name;
public ExampleModel()
{
}
public ExampleModel(int _id, string _name)
{
this.Id = _id;
this.Name = _name;
}
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
return this.Name == Name && this.Id == Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
Example ViewModel:
public class ExampleViewModel : Screen
{
private IEventAggregator _events;
public ExampleViewModel(IEventAggregator events)
{
// Initialize collection
BindableCollection<ExampleModel> SelectedItems = new BindableCollection<ExampleModel>();
_events = events;
}
private BindableCollection<ExampleModel> _selectedItems;
public BindableCollection<ExampleModel> SelectedItems
{
get { return _selectedItems; }
set
{
// SelectedItems remains NULL
_selectedItems = value;
NotifyOfPropertyChange(() => Items);
}
}
private ExampleModel _selectedItem;
public ExampleModel SelectedItem
{
get { return _selectedItem; }
set
{
// CODE NOT UPDATING SELECTED ITEM VALUE!
_selectedItem = value;
NotifyOfPropertyChange(() => SelectedItem);
NotifyOfPropertyChange(() => SelectedItems);
}
}
// Initialize list
private HashSet<ExampleModel> _exampleList = new HashSet<ExampleModel>();
public HashSet<ExampleModel> ExampleList
{
get { return _exampleList; }
set { _exampleList = value; }
}
private async Task AddItem(ExampleModel item)
{
// A task to asyncrhonously add unique items to list
await Task.Run(() =>
_exampleList.Add(item));
Items = new BindableCollection<ExampleModel>(_exampleList);
NotifyOfPropertyChange(() => Items);
}
private BindableCollection<ExampleModel> _items;
public BindableCollection<ExampleModel> Items
{
get { return _items; }
set
{
_items = value;
NotifyOfPropertyChange(() => Items);
}
}
// Begin adding items to list
public async void Add()
{
for (int i = 0; i<10; i++)
{
// do something
var item = new ExampleModel
{
Id = i + 1,
Name = i.ToString()
};
await AddItem(item);
}
}
// Button to start process
public void Start()
{
Add();
}
}
Example View:
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Item"
HorizontalContentAlignment="Stretch"
ScrollViewer.IsDeferredScrollingEnabled="True"
Margin="8 0 0 0"
Grid.Column="1"
ItemsSource="{Binding Path= Items}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
SelectionMode="Multiple"
b:SelectedItemsBehavior.SelectedItems="{Binding SelectedItems, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- Id -->
<TextBlock
Text="{Binding Id}"
Grid.Row="0"
Grid.Column="0"
/>
<!-- Name -->
<TextBlock
Text="{Binding Name}"
Grid.Row="0"
Grid.Column="1"
Margin="10"
/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
Selected Items Behavior class:
public class SelectedItemsBehavior
{
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.RegisterAttached("SelectedItems",
typeof(INotifyCollectionChanged), typeof(SelectedItemsBehavior),
new PropertyMetadata(default(IList), OnSelectedItemsChanged));
public static void SetSelectedItems(DependencyObject d, INotifyCollectionChanged value)
{
d.SetValue(SelectedItemsProperty, value);
}
public static IList GetSelectedItems(DependencyObject element)
{
return (IList)element.GetValue(SelectedItemsProperty);
}
private static void OnSelectedItemsChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
IList selectedItems = null;
void CollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs args)
{
if (args.OldItems != null)
foreach (var item in args.OldItems)
if (selectedItems.Contains(item))
selectedItems.Remove(item);
if (args.NewItems != null)
foreach (var item in args.NewItems)
if (!selectedItems.Contains(item))
selectedItems.Add(item);
};
if (d is MultiSelector multiSelector)
{
selectedItems = multiSelector.SelectedItems;
multiSelector.SelectionChanged += OnSelectionChanged;
}
if (d is ListBox listBox)
{
selectedItems = listBox.SelectedItems;
listBox.SelectionMode = SelectionMode.Multiple;
listBox.SelectionChanged += OnSelectionChanged;
}
if (selectedItems == null) return;
if (e.OldValue is INotifyCollectionChanged)
(e.OldValue as INotifyCollectionChanged).CollectionChanged
-= CollectionChangedEventHandler;
if (e.NewValue is INotifyCollectionChanged)
(e.NewValue as INotifyCollectionChanged).CollectionChanged
+= CollectionChangedEventHandler;
}
private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var s = sender as DependencyObject;
if (!GetIsBusy(s))
{
SetIsBusy(s, true);
var list = GetSelectedItems((DependencyObject)sender);
foreach (var item in e.RemovedItems)
if (list.Contains(item)) list.Remove(item);
foreach (var item in e.AddedItems)
if (!list.Contains(item)) list.Add(item);
SetIsBusy(s, false);
}
}
private static readonly DependencyProperty IsBusyProperty =
DependencyProperty.RegisterAttached("IsBusy", typeof(bool),
typeof(SelectedItemsBehavior), new PropertyMetadata(default(bool)));
private static void SetIsBusy(DependencyObject element, bool value)
{
element.SetValue(IsBusyProperty, value);
}
private static bool GetIsBusy(DependencyObject element)
{
return (bool)element.GetValue(IsBusyProperty);
}
}
I expect SelectedItems collection to populate, but the output remains null.
I expect when any item is selected the value of SelectedItem is updated but get null.

WPF DataGrid Column Total MVVM Patern

I have one column in my DataGrid that is a Price field.
In a TextBlock at the bottom of my form.
How to show the total value in the TextBlock based on the values of the Price column?
XAML-code:
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding Path=SaleryDetailsCollection, Mode=TwoWay}" AutoGenerateColumns="False" VerticalAlignment="Top" Width="640" Height="192" >
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Type, Mode=TwoWay, NotifyOnTargetUpdated=True, ValidatesOnDataErrors=True}" Width="*" />
<DataGridTextColumn Header="Amount" Binding="{Binding Price, Mode=TwoWay, NotifyOnTargetUpdated=True, ValidatesOnDataErrors=True}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock HorizontalAlignment="Left" Margin="415,358,0,0" TextWrapping="Wrap" Text="{Binding SalaryTotal}" VerticalAlignment="Top"/>
</Grid>
ViewModel:
public ObservableCollection<SaleryDetailsModel> SaleryDetailsCollection
{
get { return _SaleryDetailsCollection; }
set
{
SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount);
_SaleryDetailsCollection = value;
NotifyPropertyChanged("SaleryDetailsCollection");
}
}
public Double SalaryTotal
{
get { return _SalaryTotal; }
set
{
_SalaryTotal = value;
NotifyPropertyChanged("SalaryTotal");
}
}
Class SaleryDetailsMode
class SaleryDetailsModel:ViewModel
{
private Double _Amount;
private String _Type;
public Double Amount
{
get { return _Amount; }
set
{
_Amount = value;
NotifyPropertyChanged("Amount");
}
}
public String Type { get { return _Type; } set { _Type = value; NotifyPropertyChanged("Type"); } }
}
Class ViewModel
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Add this code inside the Constructor
SaleryDetailsCollection = new ObservableCollection<SaleryDetailsModel>();
SaleryDetailsCollection.CollectionChanged += MyItemsSource_CollectionChanged;
In ViewModel
void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
foreach (SaleryDetailsModel item in e.NewItems)
item.PropertyChanged += MyType_PropertyChanged;
if (e.OldItems != null)
foreach (SaleryDetailsModel item in e.OldItems)
item.PropertyChanged -= MyType_PropertyChanged;
}
void MyType_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Amount")
DoWork();
}
private void DoWork()
{
SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount);
}
XAML
<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding Path=SaleryDetailsCollection, Mode=TwoWay}" AutoGenerateColumns="False" VerticalAlignment="Top" Width="640" Height="192" >
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="*" />
<DataGridTextColumn Header="Amount" Binding="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="*" />
</DataGrid.Columns>
</DataGrid>
<TextBlock HorizontalAlignment="Left" Margin="415,358,0,0" TextWrapping="Wrap" Text="{Binding SalaryTotal}" VerticalAlignment="Top"/>
The calculation must be done after the field assignment:
public ObservableCollection<SaleryDetailsModel> SaleryDetailsCollection
{
get { return _SaleryDetailsCollection; }
set
{
_SaleryDetailsCollection = value;
SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount); // This line must be after the field assignment.
NotifyPropertyChanged("SaleryDetailsCollection");
}
}
You need to use a collection which will get notification when its property getting changed. Refer the link https://social.msdn.microsoft.com/Forums/silverlight/en-US/12915e07-be95-4fc5-b8f0-b0a49b10bc57/observablecollection-item-changed. It has NotifyableCollection. I have used it for the below code.
<Grid>
<StackPanel>
<DataGrid x:Name="dgr" HorizontalAlignment="Left" ItemsSource="{Binding Path=Salaries, Mode=TwoWay}"
AutoGenerateColumns="True" VerticalAlignment="Top" Width="640" Height="192" >
</DataGrid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Text="{Binding TotalSalary}">
</TextBlock>
</StackPanel>
</Grid>
class ViewModel : INotifyPropertyChanged
{
private NotifiableCollection<Salary> salaries;
double _totalSal;
public double TotalSalary
{
get { return _totalSal = Salaries.Sum(x => x.Amount); }
set { _totalSal = value; }
}
public NotifiableCollection<Salary> Salaries
{
get { return salaries; }
set
{
salaries = value;
if (salaries != null)
{
salaries.ItemChanged += salaries_ItemChanged;
}
}
}
void salaries_ItemChanged(object sender, NotifyCollectionChangeEventArgs e)
{
OnPropertyChanged("TotalSalary");
}
public ViewModel()
{
Salaries = new NotifiableCollection<Salary>();
for (int i = 0; i < 10; i++)
{
Salary s = new Salary() { Type="Type"+i,Amount=new Random().Next(20000,30000)};
Salaries.Add(s);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
class Salary : INotifyPropertyChanged
{
private string type;
public string Type
{
get { return type; }
set { type = value; OnPropertyChanged("Type"); }
}
private double amount;
public double Amount
{
get { return amount; }
set { amount = value; OnPropertyChanged("Amount"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class NotifyCollectionChangeEventArgs : PropertyChangedEventArgs
{
public int Index { get; set; }
public NotifyCollectionChangeEventArgs(int index, string propertyName) : base(propertyName) { Index = index; }
}
public class NotifiableCollection<T> : ObservableCollection<T> where T : class, INotifyPropertyChanged
{
public event EventHandler<NotifyCollectionChangeEventArgs> ItemChanged;
protected override void ClearItems()
{
foreach (var item in this.Items)
item.PropertyChanged -= ItemPropertyChanged;
base.ClearItems();
}
protected override void SetItem(int index, T item)
{
this.Items[index].PropertyChanged -= ItemPropertyChanged;
base.SetItem(index, item);
this.Items[index].PropertyChanged += ItemPropertyChanged;
}
protected override void RemoveItem(int index)
{
this.Items[index].PropertyChanged -= ItemPropertyChanged;
base.RemoveItem(index);
}
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
item.PropertyChanged += ItemPropertyChanged;
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
T changedItem = sender as T;
OnItemChanged(this.IndexOf(changedItem), e.PropertyName);
}
private void OnItemChanged(int index, string propertyName)
{
if (ItemChanged != null)
this.ItemChanged(this, new NotifyCollectionChangeEventArgs(index, propertyName));
}
}

WPF selectable table fields

I am brand new to WPF and am trying to implement some sort of table (or I don't know how to implement it if not a table), that has its fields selectable (like in the this example - click the Open App icon and then File->New Project and if you click a table field you will see it coloring blue or going back white) and after they have been selected, to send some signals through the USB port with each columns fields.
Now my question is: How could I implement this table (or whatever)?
And another question would be: How could I browse the array (or whatever I would use to memorize states of the fields)?
Thank you in advance for everybody.
Simple example :D
Set a breakpoint for the Check status button clicked event so you can check which buttons are ticked or not.
Code:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var clickableGrid = new ClickableGrid(3, 3);
DataContext = clickableGrid;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var clickableGrid = (ClickableGrid) DataContext;
ObservableCollection<MyItem> observableCollection = clickableGrid.MyItems;
}
}
public class ClickableGrid : INotifyPropertyChanged
{
private int _columns;
private ObservableCollection<MyItem> _myItems;
private int _rows;
public ClickableGrid(int columns, int rows)
{
Columns = columns;
Rows = rows;
UpdateArray();
}
public ObservableCollection<MyItem> MyItems
{
get { return _myItems; }
set
{
_myItems = value;
OnPropertyChanged();
}
}
public int Columns
{
get { return _columns; }
set
{
_columns = value;
OnPropertyChanged();
}
}
public int Rows
{
get { return _rows; }
set
{
_rows = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void UpdateArray()
{
int columns = Columns;
int rows = Rows;
if (columns <= 0) columns = 1;
if (rows <= 0) rows = 1;
var observableCollection = new ObservableCollection<MyItem>();
for (int i = 0; i < columns*rows; i++)
{
observableCollection.Add(new MyItem());
}
MyItems = observableCollection;
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MyItem : INotifyPropertyChanged
{
private bool _isTicked;
public bool IsTicked
{
get { return _isTicked; }
set
{
_isTicked = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return string.Format("IsTicked: {0}", _isTicked);
}
}
}
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
Title="MainWindow"
Width="525"
Height="350"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl ItemsSource="{Binding MyItems}" d:DataContext="{d:DesignInstance wpfApplication1:ClickableGrid}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Columns}"
IsItemsHost="True"
Rows="{Binding Rows}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="wpfApplication1:MyItem">
<ToggleButton x:Name="toggleButton" IsChecked="{Binding Path=IsTicked}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Grid.Row="1"
Click="ButtonBase_OnClick"
Content="Check status" />
</Grid>
</Window>

How do I update a listview when my variable changes?

I have a conditional style using a StyleSelector, so that it changes the color of the playing song to green when the program loads. However, when the songIndex static variable is changed, I don't know how to make it update. I tried using the INotifyPropertyChanged interface, but am not sure how to use it properly or what I am supposed to bind to it. Here is my code....
public class HighlightStyleSelector : StyleSelector, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected override Style SelectStyleCore(object item, DependencyObject container)
{
//List<myMediaInterface> mediaList = new List<myMediaInterface>();
if (item == MainPage.mediaList[MainPage.songIndex])
{
Style style = new Style(typeof(ListViewItem));
style.Setters.Add(new Setter(ListViewItem.BackgroundProperty, new SolidColorBrush(Colors.LightGreen)));
return style;
}
else
{
var style = Application.Current.Resources["ListViewItemStyle1"] as Style;
return null;
}
}
public int songIndex
{
get { return MainPage.songIndex; }
set
{
songIndex = MainPage.songIndex;
OnPropertyChanged(songIndex.ToString());
}
}
protected void OnPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Xaml:
<ListView x:Name="songlistView" SelectionMode="Extended" DoubleTapped="songlistView_DoubleTapped" HorizontalContentAlignment="Stretch" BorderThickness="1" BorderBrush="#FF616161" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollMode="Enabled" ManipulationMode="None" UseLayoutRounding="False" VerticalContentAlignment="Stretch" Margin="2,150,0,558" Tapped="songlistView_Tapped" FontSize="14" ItemContainerStyleSelector="{StaticResource HighlightStyleSelector}" ItemsSource="{Binding MainPage.mediaList}">
Here is the code for the custom listview
namespace HelloWorld
{
public class MyListView : Control
{
public int highlightedItem;
public MyListView()
{
this.DefaultStyleKey = typeof(MyListView);
}
}
}
If I use get; and set; for hightlighted item doesn't work either. Still says the member highlightedItem is not recognized or is not accessible
Edited 5/25
this is now in MainPage.xaml.cs
public int songIndex
{
get
{
return songIndex;
}
set
{
songIndex = value;
OnPropertyChanged("songIndex");
}
}
^^ not sure if this should go with my field declarations?
public void OnPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Here is my code from MainPage.xaml
<ListView x:Name="songlistView" SelectedIndex="{Binding songIndex}" SelectionMode="Extended" DoubleTapped="songlistView_DoubleTapped" HorizontalContentAlignment="Stretch" BorderThickness="1" BorderBrush="#FF616161" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollMode="Enabled" ManipulationMode="None" UseLayoutRounding="False" VerticalContentAlignment="Stretch" Margin="2,150,0,558" Tapped="songlistView_Tapped" FontSize="14" ItemsSource="{Binding MainPage.mediaList}"><!--ItemContainerStyleSelector="{StaticResource HighlightStyleSelector}"-->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
Here is my code 5/26
I'm trying to create a dependencyproperty called highlightedIndex that is identical to selectedIndex, except that it is separate.
public class MyListView : ListView
{
public int highlightedIndex
{
get { return (int)GetValue(HighlightedProperty); }
set
{
SetValue(HighlightedProperty, value);
}
}
public static readonly DependencyProperty HighlightedProperty = DependencyProperty.Register("HighlightedProperty", typeof(int), typeof(MyListView), new PropertyMetadata(0));
}
namespace HelloWorld
{
public class HighlightStyleSelector : StyleSelector
{
protected override Style SelectStyleCore(object item, DependencyObject container)
{
if (item == MainPage.mediaList[MainPage.songIndex])
{
var style = Application.Current.Resources["ListViewItemHighlighted"] as Style;
Setter setter = new Setter(ListViewItem.BackgroundProperty, new SolidColorBrush(Colors.LightGreen));
//Style style = new Style(typeof(ListViewItem));
style.Setters.Add(setter);
return style;
}
else
{
var style = Application.Current.Resources["ListViewItemStyle1"] as Style;
return style;
}
}
}
}
I'm a bit confused because of static properties on MainPage you seem to be assigning songIndex to and binding mediaList to. It would be helpful to see that code as well.
Still, you need to fix your property (assuming OnPropertyChanged is implemented correctly):
public int songIndex
{
get { return MainPage.songIndex; }
set
{
// set the assigned value to property backing field
MainPage.songIndex = value;
// you need to notify with the name of the property as the argument
OnPropertyChanged("songIndex");
}
}
Then you can bind to this property like any other with the only difference that the control will be notified when its value changes:
<ListView SelectedIndex="{Binding songIndex}" />
public static readonly DependencyProperty HighlightedProperty = DependencyProperty.Register("highlightedIndex", typeof(int), typeof(MyListView), new PropertyMetadata(null, propertyChanged));
private static void propertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
int newValue = (int)e.NewValue;
ListView lv = (ListView)d;
foreach (ListViewItem lvi in lv.Items)
{
if (lv.Items.IndexOf(lvi) == newValue)
{
lvi.Background = new SolidColorBrush(Colors.LightGreen);
}
else
{
lvi.Background = new SolidColorBrush();
}
}
}
Didn't need the styleselector or any binding

Categories