<StackPanel Height="650" Width="650" Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl Name="Display_Test" Margin="10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="Black" Width="600" Height="600"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" Margin="15" Height="500" Width="500"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
// c# code start ====================================================================
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
this.InitializeComponent();
Canvas canvasSample = new Canvas();
canvasSample.Width = 100;
canvasSample.Height = 100;
canvasSample.Background = new SolidColorBrush(Colors.LightBlue);
CanvasList.Add(canvasSample);
Canvas canvasSample2 = new Canvas();
canvasSample2.Width = 100;
canvasSample2.Height = 100;
canvasSample2.Background = new SolidColorBrush(Colors.LightGreen);
CanvasList.Add(canvasSample2);
Rectangle rectangleSample = new Rectangle();
rectangleSample.Width = 30;
rectangleSample.Height = 30;
RectangleList.Add(rectangleSample);
Rectangle rectangleSample2 = new Rectangle();
rectangleSample2.Width = 30;
rectangleSample2.Height = 30;
RectangleList.Add(rectangleSample2);
Display_Test.ItemsSource = CanvasList;
this.MouseDoubleClick += new MouseButtonEventHandler(MainWindow_MouseDoubleClick);
}
void MainWindow_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
for (int nCanvasNum = 0; nCanvasNum < CanvasList.Count; nCanvasNum++)
{
Binding conBinding = new Binding()
{
Source = RectangleList
};
CanvasList[nCanvasNum].DataContext = RectangleList;
CanvasList[nCanvasNum].SetBinding(ItemsControl.ItemsSourceProperty, conBinding);
}
}
ObservableCollection<Canvas> _canvasList = new ObservableCollection<Canvas>();
public ObservableCollection<Canvas> CanvasList
{
get { return _canvasList; }
set
{
_canvasList = value;
OnPropertyChanged(new PropertyChangedEventArgs("CanvasList"));
}
}
ObservableCollection<Rectangle> _rectangleList = new ObservableCollection<Rectangle>();
public ObservableCollection<Rectangle> RectangleList
{
get { return _rectangleList; }
set
{
_rectangleList = value;
OnPropertyChanged(new PropertyChangedEventArgs("RegtangleList"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
#endregion
}
// c# code end ====================================================================
when i clicked mousebutton double I want to create RectangleList in CanvasList...
But I'm afraid I can't show that...I think that is problem because of setbinding...
I will wait for your answer....
CanvasList[nCanvasNum].SetBinding(ItemsControl.ItemsSourceProperty, conBinding); won't work bevause Canvas is not derived from ItemsControl and does not have ItemSource property. It has children property but it is not dependency property so you can't bind to it but you can add childrens manually. You can try to use ItemsControl instead of Canvas and set Canvas as a panel for ItemsControl the same way you did it to Show canvases
Related
I am writing a programme with C#, .NET 4.6 and WPF. I would like to have a set of CustomControls arranged in a two-dimensional grid (size dynamically specified at runtime) and be able to access each CustomControl.
I did some research, found different pieces of information about the ItemsControl, and created a solution which to some extend does what I want.
Here are the relevant parts of the code, they compile and run.
XAML for CustomControl
<UserControl x:Class="TestApp.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestApp"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Rectangle Fill="{Binding MyFill1, RelativeSource={RelativeSource FindAncestor, AncestorType=local:MyUserControl}}">
</Rectangle>
<Viewbox>
<TextBlock Text="{Binding MyText1, RelativeSource={RelativeSource FindAncestor, AncestorType=local:MyUserControl}}" >
</TextBlock>
</Viewbox>
</Grid>
</UserControl>
code-behind for CustomControl
namespace TestApp
{
public partial class MyUserControl : UserControl
{
public static readonly DependencyProperty MyText1Property =
DependencyProperty.Register("MyText1",
typeof(String), typeof(MyUserControl),
new PropertyMetadata(""));
public String MyText1
{
get { return (String)GetValue(MyText1Property); }
set { SetValue(MyText1Property, value); }
}
public static readonly DependencyProperty MyFill1Property =
DependencyProperty.Register("MyFill1",
typeof(SolidColorBrush),
typeof(MyUserControl),
new PropertyMetadata(new SolidColorBrush(Colors.Green)));
public SolidColorBrush MyFill1
{
get { return (SolidColorBrush)GetValue(MyFill1Property); }
set { SetValue(MyFill1Property, value); }
}
public MyUserControl()
{
InitializeComponent();
}
}
}
XAML for hosting MainWindow
<Window x:Class="TestApp.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:local="clr-namespace:TestApp"
mc:Ignorable="d"
Name="MyMainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ItemsControl Name="MyItemsControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding ElementName=MyMainWindow, Path=UniformGridColumns, Mode=OneWay}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:MyUserControl MyText1="{Binding Text1}" MyFill1="{Binding Fill1}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
code-behind for hosting main window
namespace TestApp
{
public partial class MainWindow : Window
{
public int UniformGridColumns //number of columns of the grid
{
get { return (int)GetValue(UniformGridColumnsProperty); }
set { SetValue(UniformGridColumnsProperty, value); }
}
public static readonly DependencyProperty UniformGridColumnsProperty =
DependencyProperty.Register("UniformGridColumns", typeof(int), typeof(MainWindow),
new FrameworkPropertyMetadata((int)0));
public MainWindow()
{
InitializeComponent();
//this.DataContext = this;
Setup(13, 5); //13 columns, 5 rows
}
public void Setup(int columns, int rows) //setup the grid
{
UniformGridColumns = columns;
SingleControl[] singleControls = new SingleControl[rows*columns];
for (int i = 0; i < rows*columns; i++)
singleControls[i] = new SingleControl()
{
Text1 = (i/ columns + 1) + ", " + (i % columns + 1),
Fill1 = new SolidColorBrush((i % 2 != 0) ? Colors.Yellow : Colors.Red)
}; //example, display position in grid and fill with two different colours
MyItemsControl.ItemsSource = singleControls.ToList<SingleControl>();
}
public MyUserControl GetSingleControl(int column, int row) //access a single control
{
//some code involving VisualTreeHelper
return null;
}
private class SingleControl //helper class for setting up the grid
{
public String Text1 { get; set; }
public Brush Fill1 { get; set; }
}
}
}
The method MainWindow.Setup(int, int) fills the ItemControl with the desired number of MyCustomControls, I can label and fill them with any colour I want.
Question 1:
How can I implement GetSingleControl(int, int) that returns the MyCustomControl on the specified position? I started with a solution involving VisualTreeHelper which seems to be clumsy and unflexible.
Question 2:
How can I set Name of all MyCustomControls, e.g. something like "MyCustomControl_01_05" for the item in row 1 and column 5.
Question 3:
If questions 1 and 2 cannot be answered on the basis of my solution, what would be a more suitable approach?
Thank you!
To give an example of what both elgonzo and Andy said, you should change things to be more MVVM friendly. Once you do more research you will understand why you dont want to bother with the DependencyProperties, binding to the code behind, and manually coding all the additions of the usercontrols.
This could be made pretty or more streamlined, but i coded it to give a full example of how this could be done with MVVM. I tried to make it simple and basic, while demonstrating how to refactor your idea.
New MainWindow.xaml
<Window x:Class="TestApp.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:local="clr-namespace:TestApp"
d:DataContext="{d:DesignInstance {x:Type local:MainWindowViewModel}}"
mc:Ignorable="d"
Name="MyMainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<ItemsControl Name="MyItemsControl" ItemsSource="{Binding MyList}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding GridRow}" />
<Setter Property="Grid.Column" Value="{Binding GridColumn}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding ColumnCount}" Rows="{Binding RowCount}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Rectangle Fill="{Binding Fill1}"/>
<TextBlock Text="{Binding Text1}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
New MainWindow.xaml.cs (Notice there is no extra code)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
Add a file MainWindowViewModel.cs:
-note the MyElement could be abstracted to a viewmodel for a UserControl if you desire.
public class MyElement : INotifyPropertyChanged
{
public MyElement()
{
//some default data for design testing
Text1 = "Test";
Fill1 = new SolidColorBrush(Colors.Red);
GridColumn = 13;
GridRow = 5;
}
private string _text1;
public string Text1
{
get { return _text1; }
set{
if (value != _text1) { _text1 = value; RaisePropertyChanged(); }
}
}
private Brush _fill1;
public Brush Fill1
{
get { return _fill1; }
set
{
if (value != _fill1) { _fill1 = value; RaisePropertyChanged(); }
}
}
private int _gridRow;
public int GridRow
{
get { return _gridRow; }
set
{
if (value != _gridRow) { _gridRow = value; RaisePropertyChanged(); }
}
}
private int _gridColumn;
public int GridColumn
{
get { return _gridColumn; }
set
{
if (value != _gridColumn) { _gridColumn = value; RaisePropertyChanged(); }
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel() : this(13, 5) { }
public MainWindowViewModel(int columns, int rows)
{
ColumnCount = columns;
RowCount = rows;
MyList = new ObservableCollection<MyElement>();
//your original setup code
for (int i = 0; i < columns; i++)
{
for (int j = 0; j < rows; j++)
{
var vm = new MyElement
{
Text1 = (i / columns + 1) + ", " + (i % columns + 1),
Fill1 = new SolidColorBrush((i % 2 != 0) ? Colors.Yellow : Colors.Red),
GridColumn = i,
GridRow = j
};
MyList.Add(vm);
}
}
}
private int _rowCount;
public int RowCount
{
get { return _rowCount; }
set
{
if (value != _rowCount) { _rowCount = value; RaisePropertyChanged(); }
}
}
private int _columnCount;
public int ColumnCount
{
get { return _columnCount; }
set
{
if (value != _columnCount) { _columnCount = value; RaisePropertyChanged(); }
}
}
public ObservableCollection<MyElement> MyList { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I did a more full solution where it uses INotifyPropertyChanged. I wont explain the reason for using it (in the event you are unaware), as there are much better explanations you can quickly search for.
I also made it so all the dynamic information uses Binding to make things easier to change. Now the Grid size, and item positioning are bound to your data. So it should adjust automatically as you change your "MyElement"
This should give you a good starting point for refactoring your code, and help you utilize what WPF was designed to do, as there are many mechanisms built in so you dont have to hard code UI layer manipulation (as you were in the code behind)
This also answers your Questions:
Q1 : You can now just access to the List of MyElements and change them accordingly. The UI layer should update automatically when you change anything.
Q2 : You shouldnt need to do this now, as each MyElement will keep a property for it's Grid Position. Thus you can just access that.
I have a WPF ListView containing multiple ItemsControl that have WrapPanels.
The items wrap as expected as long as there is no scrollbar visible. When there is a scrollbar visible, when the window becomes less wide, I can see the WrapPanel claiming vertical space for the items that need to move to the column to the left, but the items do not move. After scrolling using the scrollbar, the items do jump to the correct column.
Has anyone encountered this and does someone know a solution?
A movie clip would be more clear but in the pictures below I try to explain the steps and what happens. The code for the project is posted below the pictures.
No scrollbar, wrapping works fine:
No scrollbar, even narrower window, wrapping still works fine:
A scrollbar is visible, wrapping is still ok:
A scrollbar is visible, screen is narrower, the green wrappanel shows that vertical space is claimed for the items that should move to the leftmost column, but the items do not move:
After using the scrollbar, the items jump to the correct column:
MainWindow.xaml
<Window x:Class="Wrapping.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="800" Width="600">
<Window.Resources>
<DataTemplate x:Key="DetailReadOnlyTemplate">
<Grid Width="75" Height="15" Margin="2" Background="Green"/>
</DataTemplate>
<DataTemplate x:Key="MainObjectReadOnlyTemplate">
<StackPanel>
<Grid VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Number}"/>
<TextBlock Text="Some text" Grid.Column="1" HorizontalAlignment="Right"/>
</Grid>
<ItemsControl ItemsSource="{Binding DetailObjects}"
ItemTemplate="{StaticResource DetailReadOnlyTemplate}"
Background="LightGreen">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</DataTemplate>
</Window.Resources>
<ListView ItemsSource="{Binding MainObjects}"
SelectedItem="{Binding SelectedMainObject}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemTemplate="{StaticResource MainObjectReadOnlyTemplate}"
HorizontalContentAlignment="Stretch"
Background="Bisque"/>
</Window>
MainWindow.xaml.cs
public partial class MainWindow : INotifyPropertyChanged
{
private static readonly Random Random = new Random();
public MainWindow()
{
DataContext = this;
InitializeComponent();
MainObjects = new ObservableCollection<MainObject>();
for (var i = 0; i < 10; i++)
{
MainObjects.Add(CreateMainObject(i));
}
}
private ObservableCollection<MainObject> _mainObjects;
public ObservableCollection<MainObject> MainObjects
{
get => _mainObjects;
set
{
_mainObjects = value;
OnPropertyChanged();
}
}
private MainObject _selectedMainObject;
public MainObject SelectedMainObject
{
get => _selectedMainObject;
set
{
_selectedMainObject = value;
OnPropertyChanged();
}
}
private MainObject CreateMainObject(int n)
{
return new MainObject
{
DisplayText = "Main object " + n,
Number = n,
DetailObjects = GenerateDetailObjects()
};
}
private ObservableCollection<DetailObject> GenerateDetailObjects()
{
var detailObjects = new ObservableCollection<DetailObject>();
for (var i = 0; i < Random.Next(2, 4); i++)
{
detailObjects.Add(new DetailObject
{
DisplayText = "Detail " + i,
Value = GenerateRandomString(Random.Next(3, 8))
});
}
return detailObjects;
}
public static string GenerateRandomString(int length)
{
const string chars = "abcdefghijklmnopqrstuvwxyz0123456789";
return new string(Enumerable.Repeat(chars, length).Select(s => s[Random.Next(s.Length)]).ToArray());
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The dummy objects:
public class MainObject : INotifyPropertyChanged
{
private int _number;
public int Number
{
get => _number;
set
{
_number = value;
OnPropertyChanged();
}
}
private string _displayText;
public string DisplayText
{
get => _displayText;
set
{
_displayText = value;
OnPropertyChanged();
}
}
private ObservableCollection<DetailObject> _detailObjects;
public ObservableCollection<DetailObject> DetailObjects
{
get => _detailObjects;
set
{
_detailObjects = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class DetailObject : INotifyPropertyChanged
{
private string _displayText;
public string DisplayText
{
get => _displayText;
set
{
_displayText = value;
OnPropertyChanged();
}
}
private string _value;
public string Value
{
get => _value;
set
{
_value = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
It turns out that ListView is not very good at scrolling. After disabling the scrollbars on the outer ListView and wrapping it in a ScrollViewer, the inner WrapPanels and the contained items behave as expected. Took me a day to figure this out.
i´m a newbie in WPF and have a Problem with data-binding. I hope you can help me:
Here is my XAML- Code:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl Name="MainTabControl" ItemsSource="{Binding}" Margin="2,0,-2,0">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Header}" Tag="{Binding Rid}" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<DataGrid ItemsSource="{Binding Dg}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
So i have a TabControl with a binding to a ObservableCollection of Tabs. Each Tab has a TextBlock as Header and a DataGrid.
Binding:
public MainWindow()
{
InitializeComponent();
DataGrid dg = new DataGrid();
DataGridTemplateColumn xx = new DataGridTemplateColumn()
{
Header = new TextBlock() { Text = "Edit", Tag = "Edit" }
};
xx.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
dg.Columns.Add(xx);
OCTabs.Add(new OCTab() { Header = "test1", Rid = 1 , Dg = dg});
OCTabs.Add(new OCTab() { Header = "test2", Rid = 2 , Dg = dg});
OCTabs.Add(new OCTab() { Header = "test3", Rid = 3, Dg = dg });
MainTabControl.DataContext = OCTabs;
}
and here the Tab- Class:
public class OCTab : INotifyPropertyChanged
{
private string _header;
private int _rid;
private DataGrid dg;
public DataGrid Dg { get { return dg; } set { dg = value; NotifyPropertyChanged("Dg"); } }
public string Header { get { return _header; } set { _header = value; NotifyPropertyChanged("Header"); } }
public int Rid { get { return _rid; } set { _rid = value; NotifyPropertyChanged("Rid"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Now my problem:
everything works fine, except for the DataGrids from each Tab. The DataGrid is empty (no Columns,...)
The Binding doesn´t work and i don´t know why...
EDIT:
so is it possible, that each Tabitem has it´s own datagrid?
Can i / How can I attach commands to a custom control i made and put it into a Resource Dictionary in WPF? I would like to not define this control in multiple places and also not have the code in code-behind file of the XAML for it. Here is the first rendition of my control, its basically a re-orderable listbox of checkboxes. Unchecked items cannot be at the top of the list.
<ListBox Name="listBoxZone" Grid.Row="3" HorizontalContentAlignment="Stretch" Height="200"
ItemsSource="{Binding TheList}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0.5" BorderBrush="DarkGray">
<Grid Height="30">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Click="Reorder_Click" Grid.RowSpan="2" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" Width="Auto"/>
<Button Click="UpDownClick" Name="Up" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" Margin="1" ToolTip="Up" BorderBrush="{x:Null}" Background="{x:Null}">
<Image Source="/Resources/Icons/sort_up.png"/>
</Button>
<Button Name="Down" Click="UpDownClick" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" Margin="1" ToolTip="Down" BorderBrush="{x:Null}" Background="{x:Null}">
<Image Source="/Resources/Icons/sort_down.png"/>
</Button>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And what's currently just in code-behind :
public TaskRolesView()
{
InitializeComponent();
//remove later when i figure this out!
CreateCheckBoxList();
this.DataContext = this;
}
private System.Collections.ObjectModel.ObservableCollection<StoredProc> _theList;
public System.Collections.ObjectModel.ObservableCollection<StoredProc> TheList
{
get { return _theList; }
set
{
if (value != _theList)
{
_theList = value;
FirePropertyChanged("TheList");
}
}
}
public void CreateCheckBoxList()
{
TheList = new System.Collections.ObjectModel.ObservableCollection<StoredProc>();
StoredProc mea = new StoredProc();
mea.Name = "MEA";
mea.IsChecked = true;
StoredProc valic = new StoredProc();
valic.Name = "VALIC";
valic.IsChecked = true;
StoredProc axa = new StoredProc();
axa.Name = "AXA";
axa.IsChecked = true;
StoredProc fidelity = new StoredProc();
fidelity.Name = "Fidelity";
fidelity.IsChecked = true;
StoredProc first = new StoredProc();
first.Name = "Step 1";
first.IsChecked = true;
StoredProc second = new StoredProc();
second.Name = "Step 2";
second.IsChecked = false;
StoredProc last = new StoredProc();
last.Name = "Last";
last.IsChecked = false;
StoredProc another = new StoredProc();
another.Name = "another";
another.IsChecked = false;
StoredProc onemore = new StoredProc();
onemore.Name = "onemore";
onemore.IsChecked = false;
TheList.Add(mea);
TheList.Add(valic);
TheList.Add(axa);
TheList.Add(fidelity);
TheList.Add(first);
TheList.Add(second);
TheList.Add(last);
TheList.Add(another);
TheList.Add(onemore);
}
public class StoredProc
{
public string Name { get; set; }
public bool IsChecked { get; set; }
}
private void UpDownClick(object sender, RoutedEventArgs e)
{
Button button = sender as Button;
StoredProc sp = button.DataContext as StoredProc;
int oldLocation = TheList.IndexOf(sp);
if (oldLocation > 0 && button.Name == "Up")
{
if (oldLocation > 0)
{
if (sp.IsChecked || (TheList[oldLocation - 1].IsChecked == sp.IsChecked))
{
TheList.RemoveAt(oldLocation);
TheList.Insert(oldLocation - 1, sp);
}
}
}
if (oldLocation < TheList.Count - 1 && button.Name == "Down")
{
if (oldLocation + 1 <= TheList.Count)
{
if (sp.IsChecked == false || (TheList[oldLocation + 1].IsChecked == sp.IsChecked))
{
TheList.RemoveAt(oldLocation);
TheList.Insert(oldLocation + 1, sp);
}
}
}
}
private void Reorder_Click(object sender, RoutedEventArgs e)
{
CheckBox checkBox = sender as CheckBox;
IEnumerable<StoredProc> sort;
sort = TheList.OrderByDescending(item => item.IsChecked);
System.Collections.ObjectModel.ObservableCollection<StoredProc> temp = new System.Collections.ObjectModel.ObservableCollection<StoredProc>();
foreach (var item in sort)
{
temp.Add(item);
}
TheList.Clear();
TheList = temp;
}
#region FirePropertyChanged
/// <summary>
/// Property Changed handler
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Needed to update view model
/// </summary>
/// <param name="propertyName"></param>
protected void FirePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
I'm trying to better understand Silverlights binding mechanism and so have created a simple program that will change the borderthickness of a listbox on the press of a button. However it doesn't work and I can't figure out what I am doing wrong. Any ideas?
XAML:
<Grid x:Name="LayoutRoot" Background="White">
<ListBox Height="100" HorizontalAlignment="Left" Margin="134,102,0,0" Name="listBox1" VerticalAlignment="Top" Width="120" BorderThickness="{Binding TheThickness, Mode=TwoWay}" />
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="276,36,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
Code:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication4
{
public partial class MainPage : UserControl
{
private TestClass testInst = new TestClass();
public MainPage()
{
InitializeComponent();
listBox1.DataContext = testInst;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
testInst.TheThickness = 10;
}
}
public class TestClass
{
private int theThickness = 5;
public int TheThickness
{
get { return theThickness; }
set
{
theThickness = value;
NotifyPropertyChanged("TheThickness");
}
}
public event PropertyChangedEventHandler PropertyChanged;
// NotifyPropertyChanged will raise the PropertyChanged event, passing the source property that is being updated.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
A border thickness is of Type Thickness which has multiple values for Top, Bottom, Left and Right. The XAML parser knows how to handle something like BorderThickness="5" correctly but in code you need to use the Thickness type. For example:-
public Thickness SelectedThickness
{
get { return (Thickness)GetValue(SelectedThicknessProperty); }
set { SetValue(SelectedThicknessProperty, value); }
}
public static readonly DependencyProperty SelectedThicknessProperty =
DependencyProperty.Register("SelectedThickness", typeof(Thickness), typeof(MyRectangle),
new PropertyMetadata(new Thickness() { Top = 1, Bottom = 1, Left = 1, Right = 1 }));
}
In this case the default Thickness of 1.
Edit Code more like yours:-
private Thickness theThickness = new Thickness() {Left = 5, Right = 5, Top = 5, Bottom = 5};
public Thickness TheThickness
{
get { return theThickness; }
set
{
theThickness = value;
NotifyPropertyChanged("TheThickness");
}
}