Check a large group of checkboxes - c#

I want to be able to say:
Get the first textblock, then the first checkbox, both with the number 1 in their name.
Then if the checkbox is checked, then the textblock can be populated.
See code:
for (int i = 1; i < 10; i++)
{
TextBlock a = (this.FindName(string.Format("tb_{0}", i)) as TextBlock);
CheckBox b = (this.FindName(string.Format("ck_{0}", i)) as CheckBox);
if (b.IsChecked.HasValue)
{
if (a != null) a.Text = data.ArrayOfSensors[i].ToString();
}
else
{
if (a != null) a.Text = data.ArrayOfSensors[0].ToString();
}
}
So when the checkbox is enabled, the textblock will be populated with the index from the array.
Many thanks!
EDIT: A slightly better explanation:
The textblocks are named: tb_1, tb_2 etc
The Checkboxes are named: cb_1, cb_2 etc
The array is:
[0] 0
[1] 100
[2] 150
The number is what they all have in common. So I can use a for loop with i as a common variable for each. I also have about 50 textboxes and Comboboxes and don't want to write each one out individually.
EDIT: My ComboBoxes and Textblocks are created on Xaml code like this:
<CheckBox x:Name="Cb_1" Width="15" Height="15" Margin="349,53,127,164" IsChecked="True" />
<TextBlock x:Name="tb_1" Text="80" Height="20" Width="20" Margin="266,35,205,177" />

Its hard to answer without seeing what your XAML looks like, however it sounds like you may be trying to use WPF like it is WinFirms.
To build an interface like this in WPF, you should start by creating a custom class to hold your data, and then use an ItemsControl to render your collection of data.
For example, your class might look something like this
public class SensorData() : INotifyPropertyChanged
{
// should implement INotifyPropertyChanged of course
public string Text { get; set; }
public bool IsChecked { get; set; }
}
And an ObservableCollection<SensorData> might be rendered using an <ItemsControl> with a ItemsPanelTemplate containing both a CheckBox and a TextBox
<ItemsControl ItemsSource="{Binding MyCollectionOfSensorData}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Checked="{Binding IsChecked}" />
<TextBlock Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This will loop through the collection of SensorData objects, and render a CheckBox and TextBox for each one. If you want to do any manipulation of the data from the code-behind, you only need to modify the properties of the SensorData objects.
For example, you could have a loop that goes
for (int i = 0; i < MyCollectionOfSensorData.Length; i++)
{
SensorData item = MyCollectionOfSensorData[i];
if (item.IsChecked)
item.Text = data.ArrayOfSensors[i].ToString();
else
item.Text = "0";
}
And there would be no interaction with the UI objects at all.

Related

Gridview element’s background depending on whether the binded object is an element of the list in application for UWP

Welcome.
It’s the first time, that I can’t find solution on this website and I have to ask own question. I have list (List1) of objects my class Cell. This objects are binded to a Gridview. GridviewElements has Grid, which background I want to change each time the binded object is being added to or removed from other list (List2).
Firstly, I was trying to achieve it by using WinRTMultiBinding
(https://github.com/Verbon/WinRTMultiBinding), but it seems that can only bind simple types, not Cell and list of it. Then I started to trying initialize IValueConverter object in VievModel, but couldn’t bind it to {Binding Converter}. After that I decided to declare and pass List2 to the converter as a field, but it didn’t changed through the time. My last try, was declaring static field in ViewModel class that contains current reference, but as the GridViewElement binds only Cell object which is not changing, the PropertyChanged event is not raised, so the colour stays the same.
I’m now thinking about declaring a new property in Cell class that represents brush, or new list of cell brushes to be bind as background, but I hope there is better solution. And there is my question: do You know any?
My XAML code:
<GridView Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Cells}">
<GridView.ItemTemplate>
<DataTemplate>
<Border Name="Border" BorderThickness="2" Width="30" Height="30" CornerRadius="2" Tag="{Binding}"
BorderBrush="{Binding Converter={StaticResource CellToBrush}}"
PointerPressed="OnCrosswordGridViewItemPointerPressed">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock Name="Character" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource ForegroundMain}" Text="{Binding Char}"/>
</Grid>
</Border>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
There is my VM:
It contains
Crossword object - model for that page which contains list of Cells
List1 (named Cells)
VM's deffinition of it (named the same as in model)
Deffinition of StartCell that represents first Cell that user
presses down
Deffinition of ObservableCollection of Cell SelectedCells - this is the List2
Crossword crossword;
public List<Cell> Cells
{
get { return crossword.Cells; }
}
Cell startCell;
public Cell StartCell
{
set
{
if(value != startCell)
{
startCell = value;
OnPropertyChanged("StartCell");
}
}
get { return startCell; }
}
public ObservableCollection<Cell> SelectedCells
{
get;set;
}
And methods in code behind:
void OnCellPointerPressed(object sender, PointerRoutedEventArgs args)
{
if (args.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
{
CreateCrosswordPageVM vm = (CreateCrosswordPageVM)DataContext;
vm.StartCell = (Cell)((Border)sender).Tag;
}
}
void OnCrosswordGridViewItemPointerMoved(object sender, PointerRoutedEventArgs args)
{
CreateCrosswordPageVM vm = (CreateCrosswordPageVM)DataContext;
Cell currentCell = (Cell)((Border)sender).Tag;
if (currentCell.Row == vm.StartCell.Row && currentCell.Column > vm.StartCell.Column)
vm.SelectedCells = new System.Collections.ObjectModel.ObservableCollection<Cell>(vm.Cells.FindAll(x=>x.Row == currentCell.Row && x.Column<= currentCell.Column && x.Column>= vm.StartCell.Column));
else if (currentCell.Column == vm.StartCell.Column && currentCell.Row > vm.StartCell.Row)
vm.SelectedCells = new System.Collections.ObjectModel.ObservableCollection<Cell>(vm.Cells.FindAll(x=>x.Column== currentCell.Column && x.Row <= currentCell.Row && x.Row >= vm.StartCell.Row));
}
First method passes the "pressed" Cell to ViewModel's StartCell, second checks which Cells lies between StartCell and current Cell (over which the pointer is) and passes them to SelectedCells.
And about the colours. I wanted to hardcode it in Converter and later when it works, pass them as Converter parameter or daclare is as resources in ResourceDictionary

Center aligning GridView items in last row

I want to implement a GridView which takes 3 items in a row, and if the number of items are 2 in last row, then the last row items should be aligned center instead of being left-aligned. Here are a couple of images to explain what I want to achieve.
Currently my implementation looks like
.
And this is what I want to achieve.
Any help would be appreciated.
There are many ways realizing the feature that you mentioned.
To summarize it, you need to inherit GridView and override MeasureOverride ArrangeOverride method to re-calculate each Rect of Panel's children. This way is complex. For more info you could refer to
XAML custom panels overview.
And you could also use PrepareContainerForItemOverride method to re-layout the item directly.
<local:VariableGrid
x:Name="MyGridView"
SelectionMode="Single"
IsSwipeEnabled="False">
<local:VariableGrid.ItemTemplate >
<DataTemplate>
<StackPanel BorderBrush="Red" BorderThickness="3" Height="200" Width="200" Margin="20">
</StackPanel>
</DataTemplate>
</local:VariableGrid.ItemTemplate>
<local:VariableGrid.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid
Orientation="Horizontal"
VerticalAlignment="Top"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.VerticalScrollMode="Disabled"
MaximumRowsOrColumns="4">
</VariableSizedWrapGrid>
</ItemsPanelTemplate>
</local:VariableGrid.ItemsPanel>
</local:VariableGrid>
VariableGrid.cs
public sealed class VariableGrid : GridView
{
public VariableGrid()
{
this.DefaultStyleKey = typeof(VariableGrid);
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var list = this.ItemsSource as List<string>;
var griditem = element as GridViewItem;
for (var t = ((list.Count - list.Count % 4)); t < list.Count; t++)
{
if (item as string == list[t])
{
if (griditem != null)
{
VariableSizedWrapGrid.SetColumnSpan(griditem, 2);
}
}
}
base.PrepareContainerForItemOverride(element, item);
}
}
However, this simple way can not fit all the scenario.

change textblock text that is inside Listbox in windowsphone 8

i want to change textblock text in page initialize event
here is my xaml
<ListBox Margin="3,60,1,10" BorderThickness="2" Grid.Row="1" Name="lstAnnouncement" Tap="lstAnnouncement_Tap" Width="476" d:LayoutOverrides="VerticalMargin">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Name="thispanel" Grid.Row="1" Orientation="Horizontal" Height="120" Width="478" >
<StackPanel.Background>
<ImageBrush ImageSource="Images/Text-ALU.png" Stretch="Fill" />
</StackPanel.Background>
<Grid HorizontalAlignment="Left" Width="30" Margin="0,0,0,2" Background="#FF0195D5" Height="118">
<TextBlock x:Name="txtDate" TextWrapping="Wrap">
</TextBlock>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
i want to change txtDate.Text using c# in code-behind but txtdate is not accessible in code behind so how to achieve it ?
The reason you're not able to access the txtDate object is because it's contained within the DataTemplate you're using for the ListBox. This isn't an error - the DataTemplate is being applied to every single item added to your ListBox.
Given that the ListBox creates, among other controls, a Grid containing a TextBlock with the name "txtDate", for every single item added to it, what would it mean to access the txtDate object? How would your program decide which of a (functionally) infinite number of txtDates associated with an identical number of ListBoxItems you meant when you referenced txtDate?
If you wanted to be able to easily change the content of txtDate, you'd want to bind the ItemsSource of your ListBox to a property in a ViewModel. The easiest way to do this would be to have that property be an IEnumerable containing a custom model type. This way, you could update the text property of that model and call NotifyPropertyChanged on the that property, and the UI would update to reflect the new data.
Here's an example:
public class YourViewModel
{
public List<YourModel> Models { get; set; }
}
public class YourModel : INotifyPropertyChanged
{
private string yourText;
public string YourText
{
get { return yourText; }
set
{
yourText = value;
NotifyPropertyChanged("YourText");
}
}
// add INotifyPropertyChanged implementation here
}
And then you'd want to bind the ItemsSource of the ListBox to YourViewModel's Models property, and the text of your TextBox to the YourModel's YourText property. Any time you change the YourModel.YourText property, it'll automatically update on the UI. I think it's probably subject to debate whether having your model implement INotifyPropertyChanged is proper MVVM, but I find it a lot easier in these cases than forcing the ViewModel to update every single model each time a change is made on one of them.
If you're not familiar with the MVVM pattern used with WPF, this might be a good start: MVVM example.
this function will help you... This will help u find the control inside of a listbox runtime..
public FrameworkElement SearchVisualTree(DependencyObject targetElement, string elementName)
{
FrameworkElement res = null;
var count = VisualTreeHelper.GetChildrenCount(targetElement);
if (count == 0)
return res;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(targetElement, i);
if ((child as FrameworkElement).Name == elementName)
{
res = child as FrameworkElement;
return res;
}
else
{
res = SearchVisualTree(child, elementName);
if (res != null)
return res;
}
}
return res;
}
Here first parameter is parent and the second parameter is the name of the element which in your case is "txtDate".. hope it works!!

Force selection by index of listbox or take apart same values

I use textbox and button to add items to listbox:
if (tbName.Text != "")
{
listBox.Items.Add(tbName.Text);
//Let user add another new items
tbName.Text = "";
}
And try to select items doing something (as I edit it).
But the trouble is the user can add same value of item, and while I try to select one of the item, it will result in failure. It will auto-select two items by same name, and the operation will be improper.
Can I use some method to force the listbox select items by index( since the index shouldn't be same)? Or how can I take apart the same value of items by programming(it won't select same item but just select what I click, is it means I should intercept the event of MouseDown or SelectChanged by select items refer to the position of mouse click, like height of the line is 18px, so if the position I click is between 18~36px, then the index of select item should be 1, and 0 is 0~18px)?
My listBox is:
<ListBox Height="248" HorizontalAlignment="Left" Margin="141,223,0,0" Name="listBox" VerticalAlignment="Top" Width="378" />
I think that if you set the SelectionMode="Single" property of the Listbox may help you.
use SelectedItem or SelectedInbdex
I use ObservableCollection finally. Although the question I still haven't been solved.
XAML :
<ListBox Height="248" HorizontalAlignment="Left" Margin="141,223,0,0" Name="listBox" VerticalAlignment="Top" Width="378">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Location, Mode=TwoWay}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And code:
ObservableCollection<locateItem> locatList = new ObservableCollection<locateItem>();
public class locateItem
{
public string Location { get; set; }
public string Id { get; set; }
public string Img { get; set; }
}
Then
listBox.ItemsSource = locatList;
Thanks Sheridan

Select item programmatically in WPF ListView

I'm unable to figure out how to select an item programmatically in a ListView.
I'm attempting to use the listview's ItemContainerGenerator, but it just doesn't seem to work. For example, obj is null after the following operation:
//VariableList is derived from BindingList
m_VariableList = getVariableList();
lstVariable_Selected.ItemsSource = m_VariableList;
var obj =
lstVariable_Selected.ItemContainerGenerator.ContainerFromItem(m_VariableList[0]);
I've tried (based on suggestions seen here and other places) to use the ItemContainerGenerator's StatusChanged event, but to no avail. The event never fires. For example:
m_VariableList = getVariableList();
lstVariable_Selected.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
lstVariable_Selected.ItemsSource = m_VariableList;
...
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
//This code never gets called
var obj = lstVariable_Selected.ItemContainerGenerator.ContainerFromItem(m_VariableList[0]);
}
The crux of this whole thing is that I simply want to pre-select a few of the items in my ListView.
In the interest of not leaving anything out, the ListView uses some templating and Drag/Drop functionality, so I'm including the XAML here. Essentially, this template makes each item a textbox with some text - and when any item is selected, the checkbox is checked. And each item also gets a little glyph underneath it to insert new items (and this all works fine):
<DataTemplate x:Key="ItemDataTemplate_Variable">
<StackPanel>
<CheckBox x:Name="checkbox"
Content="{Binding Path=ListBoxDisplayName}"
IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
<Image ToolTip="Insert Custom Variable" Source="..\..\Resources\Arrow_Right.gif"
HorizontalAlignment="Left"
MouseLeftButtonDown="OnInsertCustomVariable"
Cursor="Hand" Margin="1, 0, 0, 2" Uid="{Binding Path=CmiOrder}" />
</StackPanel>
</DataTemplate>
...
<ListView Name="lstVariable_All" MinWidth="300" Margin="5"
SelectionMode="Multiple"
ItemTemplate="{StaticResource ItemDataTemplate_Variable}"
SelectionChanged="lstVariable_All_SelectionChanged"
wpfui:DragDropHelper.IsDropTarget="True"
wpfui:DragDropHelper.IsDragSource="True"
wpfui:DragDropHelper.DragDropTemplate="{StaticResource ItemDataTemplate_Variable}"
wpfui:DragDropHelper.ItemDropped="OnItemDropped"/>
So what am I missing? How do I programmatically select one or more of the items in the ListView?
Bind the IsSelected property of the ListViewItem to a property on your model. Then, you need only work with your model rather than worrying about the intricacies of the UI, which includes potential hazards around container virtualization.
For example:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsGroovy}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Now, just work with your model's IsGroovy property to select/deselect items in the ListView.
Where 'this' is the ListView instance. This will not only change the selection, but also set the focus on the newly selected item.
private void MoveSelection(int level)
{
var newIndex = this.SelectedIndex + level;
if (newIndex >= 0 && newIndex < this.Items.Count)
{
this.SelectedItem = this.Items[newIndex];
this.UpdateLayout();
((ListViewItem)this.ItemContainerGenerator.ContainerFromIndex(newIndex)).Focus();
}
}
Here would be my best guess, which would be a much simpler method for selection. Since I'm not sure what you're selecting on, here's a generic example:
var indices = new List<int>();
for(int i = 0; i < lstVariable_All.Items.Count; i++)
{
// If this item meets our selection criteria
if( lstVariable_All.Items[i].Text.Contains("foo") )
indices.Add(i);
}
// Reset the selection and add the new items.
lstVariable_All.SelectedIndices.Clear();
foreach(int index in indices)
{
lstVariable_All.SelectedIndices.Add(index);
}
What I'm used to seeing is a settable SelectedItem, but I see you can't set or add to this, but hopefully this method works as a replacement.
In case you are not working with Bindings, this could also be a solution, just find the items in the source and add them to the SelectedItems property of your listview:
lstRoomLights.ItemsSource = RoomLights;
var selectedItems = RoomLights.Where(rl => rl.Name.Contains("foo")).ToList();
selectedItems.ForEach(i => lstRoomLights.SelectedItems.Add(i));

Categories

Resources