Change colors with time gap in wpf - wpf

I have 4 stackpanels, and a textbox that user can enter time in and a button.
How can I ensure the 4 boxes colors change (to some random ones) with the time gap of given input on clicking start button.
So its like, if the input is 1 second, first box changes to yellow then after 1s second box changes its color to red and so on until 4th box.
Is there any efficient and faster way to do it ?

This is probably what you're looking for:
Xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Background="{Binding Brush1}" Grid.Row="0"/>
<StackPanel Background="{Binding Brush2}" Grid.Row="1"/>
<StackPanel Background="{Binding Brush3}" Grid.Row="2"/>
<StackPanel Background="{Binding Brush4}" Grid.Row="3"/>
<TextBox Grid.Row="4" Text="{Binding Number}"/>
<Button Grid.Row="5" Content="Start" Click="Button_Click"/>
</Grid>
Code behind (with INotifyPropertyChanged implemented):
public DispatcherTimer DispatcherTimer { get; set; }
public int Number { get; set; }
private int _counter;
Brush _b1;
public Brush Brush1
{
get
{
return _b1;
}
set
{
_b1 = value;
OnPropertyChanged("Brush1");
}
}
Brush _b2;
public Brush Brush2
{
get
{
return _b2;
}
set
{
_b2 = value;
OnPropertyChanged("Brush2");
}
}
Brush _b3;
public Brush Brush3
{
get
{
return _b3;
}
set
{
_b3 = value;
OnPropertyChanged("Brush3");
}
}
Brush _b4;
public Brush Brush4
{
get
{
return _b4;
}
set
{
_b4 = value;
OnPropertyChanged("Brush4");
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
DispatcherTimer = new System.Windows.Threading.DispatcherTimer();
DispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
Number = 1;
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
switch (_counter)
{
case 2:
Brush2 = PickRandomBrush();
_counter++;
break;
case 3:
Brush3 = PickRandomBrush();
_counter++;
break;
case 4:
Brush4 = PickRandomBrush();
DispatcherTimer.Stop();
break;
default:
break;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Brush1 = PickRandomBrush();
_counter = 2;
DispatcherTimer.Interval = new TimeSpan(0, 0, Number);
DispatcherTimer.Start();
}
private Brush PickRandomBrush()
{
Brush result = Brushes.Transparent;
Random rnd = new Random();
Type brushesType = typeof(Brushes);
PropertyInfo[] properties = brushesType.GetProperties();
int random = rnd.Next(properties.Length);
result = (Brush)properties[random].GetValue(null, null);
return result;
}

Related

Custom WPF MessageBox does not return MessageBoxResult

This is the xaml "SidiMessageBoxWindow.xaml" file:
<Window
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" mc:Ignorable="d">
<Border>
<Grid x:Name="mainGrid" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" Margin="0">
<TextBlock x:Name="TextBlock" TextWrapping="Wrap" Text="TextBlock" ScrollViewer.VerticalScrollBarVisibility="Auto" Height="Auto"/>
</ScrollViewer>
<Grid Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="Auto" Width="Auto" Margin="0,10,0,0">
<Button x:Name="btnCancel" Content="Cancel" Width="Auto" MinWidth="0" Height="30"
HorizontalAlignment="Right" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
Margin="0,0,45,0" Padding="4,0,4,0" BorderThickness="1" />
<Button x:Name="btnOk" Content="Ok" Width="Auto" MinWidth="40" Height=" 30"
HorizontalAlignment="Right" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
Margin="0" Padding="4,0,4,0" BorderThickness="1" />
</Grid>
</Grid>
</Border>
and here the "SidiMessageBox1" class
I can't use "messageBox.ShowDialog();" here because I have to use the class "NTWindow" which I don't have access to.
public class SidiMessageBox1 : SidiMessageBoxWindow1
{
public static MessageBoxResult Show(ChartControl chartControl, string text, MessageBoxButton buttons = MessageBoxButton.OK)
{
if (chartControl == null)
{
return MessageBoxResult.None;
}
var messageBox = CreateMessageBox(chartControl, text, buttons);
messageBox.Show();
return messageBox.MsgBoxResult;
}
private static SidiMessageBoxWindow1 CreateMessageBox(ChartControl chartControl, string text, MessageBoxButton buttons)
{
return new SidiMessageBoxWindow1(text, buttons)
{
Owner = chartControl.OwnerChart,
Foreground = Application.Current.TryFindResource("FontControlBrush") as SolidColorBrush
};
}
}
and here is the SidiMessageBoxWindow1 class
public class SidiMessageBoxWindow1 : NTWindow
{
private static readonly string xamlFilePath = Path.Combine(Globals.UserDataDir, #"bin\Custom\AddOns\Sidi\SidiMessageBoxWindow.xaml");
private string text;
private Button btnOk, btnCancel;
private TextBlock textBlock;
private MessageBoxButton buttons;
public SidiMessageBoxWindow1()
{
}
public SidiMessageBoxWindow1(string text, MessageBoxButton buttons)
{
this.text = text;
Caption = "SidiMessageBox";
Topmost = true;
MinHeight = 100;
MinWidth = 200;
ResizeMode = ResizeMode.NoResize;
SizeToContent = SizeToContent.WidthAndHeight;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
Content = LoadXaml(xamlFilePath);
Buttons = buttons;
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
btnOk.Click -= OkButton_Click;
Close();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
btnCancel.Click -= CancelButton_Click;
Close();
}
private DependencyObject LoadXaml(string xmlFilePath)
{
Window page;
FileStream fs = new FileStream(xmlFilePath, FileMode.Open);
page = (Window)XamlReader.Load(fs);
btnOk = LogicalTreeHelper.FindLogicalNode(page, "btnOk") as Button;
btnCancel = LogicalTreeHelper.FindLogicalNode(page, "btnCancel") as Button;
textBlock = LogicalTreeHelper.FindLogicalNode(page, "TextBlock") as TextBlock;
textBlock.Text = text;
return page.Content as DependencyObject;
}
public MessageBoxButton Buttons
{
get
{
return buttons;
}
set
{
buttons = value;
btnCancel.Visibility = Visibility.Collapsed;
btnOk.Visibility = Visibility.Collapsed;
switch (buttons)
{
case MessageBoxButton.OK:
btnOk.Visibility = Visibility.Visible;
btnOk.Click += OkButton_Click;
break;
case MessageBoxButton.OKCancel:
btnCancel.Visibility = Visibility.Visible;
btnOk.Visibility = Visibility.Visible;
btnOk.Click += OkButton_Click;
btnCancel.Click += CancelButton_Click;
break;
}
}
}
public MessageBoxResult MsgBoxResult { get; set; }
}
call:
var result = SidiMessageBox1.Show(ChartControl, "text");
the messageboxwindow looks like this:
everything works fine, as it should, except that I don't get a "MessageBoxResult" back. Unfortunately I don't know how to do that with this code.
I thank "BionicCode" for his explanation and hope for your understanding, because i am still quite a beginner ;-)
To use the Thread class is considered an obsolete programming model. Since the introduction of async and await with .NET Framework 4.5 the recommended programming model is the Microsoft Docs: Task asynchronous programming model.
As the member name Dispatcher.InvokeAsync suggests, this method is awaitable and supports asynchronous execution.
Your code actually does not execute the Window on a new thread. Because you use post related code to the Dispatcher, the Window is shown on the main thread.
Showing another Window will not block the other Window instances.
Additionally, your posted code is quite smelly. You should never block a constructor. But showing a modal dialog from a constructor will block construction. A constructor must initialize the members and return immediately.
Instead you must create and show the Window instance from your static Show method:
public static MessageBoxResult Show(ChartControl chartControl, string text, MessageBoxButton buttons)
{
if (chartControl == null)
{
return MessageBoxResult.None;
}
SidiMessageBoxWindow messageBox = CreateMessageBox(chartControl, text, buttons);
// If just an OK button, allow the user to just move away from the dialog
if (buttons == MessageBoxButton.OK)
{
messageBox.Show();
}
else
{
messageBox.ShowDialog();
}
return messageBox.MsgBoxResult;
}
private static SidiMessageBoxWindow CreateMessageBox(ChartControl chartControl, string text, MessageBoxButton buttons)
{
return new SidiMessageBoxWindow(xamlFilePath, logFilePath, text, buttons, chartControl)
{
Owner = chartControl.OwnerChart,
Foreground = Application.Current.TryFindResource("FontControlBrush") as SolidColorBrush
};
}
private SidiMessageBoxWindow(ChartControl chartControl, string text, MessageBoxButton buttons)
{
this.chartControl = chartControl;
this.text = text;
this.buttons = buttons;
}

Itemscontrol that arrange Items with Gridsplitter-Functionality

I need a layout that stacks Items horizontal or vertical. Each Item should be separated by a Splitter, so the User can change the Size (Like the Toolbox Container in VisualStudio)
The Items come from a Model, so I need a ItemsControl where I can set the ItemsSource.
My first idea was to build a CustomControl derived from Grid. Their I used the "OnVisualChildrenChanged" Method to react when a new Item is added. Then I wantet to add new Column-/Rowdefinitions (Depending wether it schould be horizontal or vertical). But here was the first Proplem. When the Grid is set to IsItemsHost="true" I get a Error that the DefinitionsCollection is not accessable...
Heres a CodeSnipped from the custom control, where I tried to add a row.
private void SetRows()
{
this.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto };
}
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
{
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
SetRows();
}
EDIT:
I think I found a solution right now.
First I created a CustomControl that derives from ItemsControl.
In his template I add a Grid without inserting a Itempresenter. Now I override OnItemsChange. When a Item is added to the Collection I create a FrameworkElement and set DataContext to the added Item, than I add two Column definition to the Grid and add my Item plus an Gridsplitter to the Grid. This works well, now I only need to get the ItemTemplate from my Itemscontrol to use it in the grid.
When I solved this last issue I will add a small example.
Heres my Solution so far. If someone has a better idea, you're welcome.
Heres the CustomControl Code behind:
public class ResizableItemControl : ItemsControl
{
public ObservableCollection<FrameworkElement> _gridItems = new ObservableCollection<FrameworkElement>();
private Grid _grid;
static ResizableItemControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ResizableItemControl), new FrameworkPropertyMetadata(typeof(ResizableItemControl)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (this.Template != null)
{
_grid = this.Template.FindName("PART_Grid", this) as Grid;
}
// Add all existing items to grid
foreach (var item in Items)
{
AddItemToGrid(item);
}
}
/// <summary>
/// Called when Items in ItemsCollection changing
/// </summary>
/// <param name="e"></param>
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
if (Items.Count > 0)
{
//Add Items in Grid when new Items where add
var myItem = this.Items[Items.Count - 1];
AddItemToGrid(myItem);
}
break;
}
}
/// <summary>
/// Adds Items to grid plus GridSplitter
/// </summary>
/// <param name="myItem"></param>
private void AddItemToGrid(object myItem)
{
var visualItem = this.ItemTemplate.LoadContent() as FrameworkElement;
if (visualItem != null)
{
visualItem.DataContext = myItem;
if (_grid != null)
{
if (_grid.ColumnDefinitions.Count != 0)
{
_grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
_grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
var gridSplitter = CreateSplitter();
Grid.SetColumn(gridSplitter, _grid.ColumnDefinitions.Count - 2);
Grid.SetColumn(visualItem, _grid.ColumnDefinitions.Count - 1);
_grid.Children.Add(gridSplitter);
_grid.Children.Add(visualItem);
//_grid.Children.Add(myTest);
}
else
{
_grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
Grid.SetColumn(visualItem, _grid.ColumnDefinitions.Count - 1);
_grid.Children.Add(visualItem);
}
}
}
}
private static GridSplitter CreateSplitter()
{
var gridSplitter = new GridSplitter() {ResizeDirection = GridResizeDirection.Columns};
gridSplitter.Width = 5;
gridSplitter.HorizontalAlignment = HorizontalAlignment.Stretch;
gridSplitter.Background = new SolidColorBrush(Colors.Black);
return gridSplitter;
}
}
The generic Xaml:
<Style TargetType="{x:Type controls:ResizableItemControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:ResizableItemControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Hidden">
<Grid x:Name="PART_Grid"></Grid>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And how to use it:
<controls:ResizableItemControl
ItemsSource="{Binding ElementName=this,Path=Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label
Content="{Binding Name}"
ToolTip="{Binding Description}"
Background="Black"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</controls:ResizableItemControl>
You could create a Stackpanel, and for each element, a Grid inside it, with the following structure:
<StackPanel Orientation="Vertical">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Button>Hallo</Button>
<GridSplitter Height="5" Background="Transparent" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0" ResizeDirection="Rows" ResizeBehavior="CurrentAndNext"/>
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Button>Hallo</Button>
<GridSplitter Height="5" Background="Transparent" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0" ResizeDirection="Rows" ResizeBehavior="CurrentAndNext"/>
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Button>Hallo</Button>
<GridSplitter Height="5" Background="Transparent" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0" ResizeDirection="Rows" ResizeBehavior="CurrentAndNext"/>
</Grid>
</StackPanel>
Note that you can only resize one column at a time, but i'm sure you can refine this a bit.
I cannot add comments to waits83's answer.
Instead of create grid splitter on OnApplyTemplate, use OnItemsSourceChanged may be better.
because with OnApplyTemplate, need to bind data context before initializeComponents() in view constructor.
Here is a panel I ended up with after a few failed attempts to implement similar scenario:
class SplitPanel : Grid
{
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
"ItemTemplate", typeof (DataTemplate), typeof (SplitPanel), new PropertyMetadata(default(DataTemplate), OnItemTemplateChanged));
public DataTemplate ItemTemplate
{
get { return (DataTemplate) GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
private static void OnItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
foreach (var child in ((SplitPanel)d).Children.OfType<ContentPresenter>())
{
child.ContentTemplate = (DataTemplate)e.NewValue;
}
}
public static readonly DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register(
"ItemContainerStyle", typeof(Style), typeof(SplitPanel), new PropertyMetadata(default(Style), OnContainerStyleChanged));
public Style ItemContainerStyle
{
get { return (Style)GetValue(ItemContainerStyleProperty); }
set { SetValue(ItemContainerStyleProperty, value); }
}
private static void OnContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
foreach (var child in ((SplitPanel)d).Children.OfType<ContentPresenter>())
{
child.Style = (Style) e.NewValue;
}
}
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
"ItemsSource", typeof (IEnumerable), typeof (SplitPanel), new PropertyMetadata(null ,OnItemsSourceChanged));
public IEnumerable ItemsSource
{
get { return (IEnumerable) GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var grid = (SplitPanel)d;
grid.Children.Clear();
grid.ColumnDefinitions.Clear();
var items = e.NewValue as IEnumerable;
if (items == null) return;
var children = items.Cast<object>().Select(grid.GenerateContainer).ToArray();
for (int i = 0; ; i++)
{
var child = children[i];
var column = new ColumnDefinition
{
MinWidth = GetMinColumnWidth(child),
Width = GetColumnWidth(child),
MaxWidth = GetMaxColumnWidth(child)
};
grid.ColumnDefinitions.Add(column);
grid.Children.Add(child);
SetColumn(child, i);
if (i == children.Length - 1) break;
var splitter = new GridSplitter
{
Width = 5,
ResizeBehavior = GridResizeBehavior.CurrentAndNext,
VerticalAlignment = VerticalAlignment.Stretch,
HorizontalAlignment = HorizontalAlignment.Right,
Background = Brushes.Transparent
};
SetColumn(splitter, i);
grid.Children.Add(splitter);
}
}
public static readonly DependencyProperty ColumnWidthProperty = DependencyProperty.RegisterAttached(
"ColumnWidth", typeof (GridLength), typeof (SplitPanel), new PropertyMetadata(new GridLength(1, GridUnitType.Star), OnColumnWidthChanged));
public static void SetColumnWidth(DependencyObject element, GridLength value)
{
element.SetValue(ColumnWidthProperty, value);
}
public static GridLength GetColumnWidth(DependencyObject element)
{
return (GridLength) element.GetValue(ColumnWidthProperty);
}
private static void OnColumnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateColumnDefinition(d, column => column.Width = (GridLength)e.NewValue);
}
public static readonly DependencyProperty MinColumnWidthProperty = DependencyProperty.RegisterAttached(
"MinColumnWidth", typeof (double), typeof (SplitPanel), new PropertyMetadata(100d, OnMinColumnWidthChanged));
public static void SetMinColumnWidth(DependencyObject element, double value)
{
element.SetValue(MinColumnWidthProperty, value);
}
public static double GetMinColumnWidth(DependencyObject element)
{
return (double) element.GetValue(MinColumnWidthProperty);
}
private static void OnMinColumnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateColumnDefinition(d, column => column.MinWidth = (double)e.NewValue);
}
public static readonly DependencyProperty MaxColumnWidthProperty = DependencyProperty.RegisterAttached(
"MaxColumnWidth", typeof (double), typeof (SplitPanel), new PropertyMetadata(double.MaxValue, OnMaxColumnWidthChanged));
public static void SetMaxColumnWidth(DependencyObject element, double value)
{
element.SetValue(MaxColumnWidthProperty, value);
}
public static double GetMaxColumnWidth(DependencyObject element)
{
return (double) element.GetValue(MaxColumnWidthProperty);
}
private static void OnMaxColumnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UpdateColumnDefinition(d, column => column.MaxWidth = (double)e.NewValue);
}
private static void UpdateColumnDefinition(DependencyObject child, Action<ColumnDefinition> updateAction)
{
var grid = VisualTreeHelper.GetParent(child) as SplitPanel;
if (grid == null) return;
var column = GetColumn((UIElement)child);
if (column >= grid.ColumnDefinitions.Count) return;
grid.Dispatcher.BeginInvoke(new Action(() => updateAction(grid.ColumnDefinitions[column])));
}
private ContentPresenter GenerateContainer(object item)
{
return new ContentPresenter {Content = item, ContentTemplate = ItemTemplate};
}
}
Usage:
<wpfApplication1:SplitPanel ItemsSource="{Binding Items}">
<wpfApplication1:SplitPanel.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="wpfApplication1:SplitPanel.ColumnWidth" Value="{Binding Width}"/>
<Setter Property="wpfApplication1:SplitPanel.MinColumnWidth" Value="10"/>
<Setter Property="wpfApplication1:SplitPanel.MaxColumnWidth" Value="100"/>
</Style>
</wpfApplication1:SplitPanel.ItemContainerStyle>
<wpfApplication1:SplitPanel.ItemTemplate>
<DataTemplate>
<TextBlock Text="123"/>
</DataTemplate>
</wpfApplication1:SplitPanel.ItemTemplate>
</wpfApplication1:SplitPanel>
It only auto-generates columns and it does not support INotifyCollectionChanged (I do not need those in my use case). It has built-in grid splitters though, and you can specify column sizes using attached properties. I hope it helps someone. :)

How to make a custom control WPF Resource Dictionary with MVVMLight RelayCommands

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

How can I "stick" a control on top edge of screen?

I have a custom control which shows some statistic data and need always be placed at the top edge of WP7 screen. but, when user inputs something on a textbox, the soft-keyboard popup. And the custom control is moved out of the screen. I want to make sure the custom control always visible, even when soft keyboard is popup. Does anyone know how to do this?
You must to use some "magic". By "magic" I mean RenderTransform.
Solution is simple - you need to move your custom control (down, when keyboard visible; up, when hidden). Check this valuable post - it's must help you.
Regards.
<phone:PhoneApplicationPage
x:Class="Test.Keyboard.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
>
<Grid x:Name="LayoutRoot" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="WINDOWS PHONE" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="developer's ?" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid Grid.Row="1" Margin="12,0,12,0"></Grid>
<TextBox Grid.Row="2" LostFocus="TextBoxLostFocus"/>
</Grid>
</phone:PhoneApplicationPage>
public partial class MainPage : PhoneApplicationPage
{
private const double LandscapeShift = -259d;
private const double LandscapeShiftWithBar = -328d;
private const double Epsilon = 0.00000001d;
private const double PortraitShift = -339d;
private const double PortraitShiftWithBar = -408d;
public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register("TranslateY", typeof(double), typeof(MainPage), new PropertyMetadata(0d, OnRenderXPropertyChanged));
public MainPage()
{
InitializeComponent();
Loaded += MainPageLoaded;
}
public double TranslateY
{
get { return (double)GetValue(TranslateYProperty); }
set { SetValue(TranslateYProperty, value); }
}
private static void OnRenderXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MainPage)d).UpdateTopMargin((double)e.NewValue);
}
private void MainPageLoaded(object sender, RoutedEventArgs e)
{
BindToKeyboardFocus();
}
private void BindToKeyboardFocus()
{
PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
if (frame != null)
{
var group = frame.RenderTransform as TransformGroup;
if (group != null)
{
var translate = group.Children[0] as TranslateTransform;
var translateYBinding = new Binding("Y");
translateYBinding.Source = translate;
SetBinding(TranslateYProperty, translateYBinding);
}
}
}
private void UpdateTopMargin(double translateY)
{
if (IsClose(translateY, LandscapeShift) || IsClose(translateY, PortraitShift)
||IsClose(translateY, LandscapeShiftWithBar) || IsClose(translateY, PortraitShiftWithBar)
)
{
LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
}
}
private bool IsClose(double a, double b)
{
return Math.Abs(a - b) < Epsilon;
}
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
LayoutRoot.Margin = new Thickness();
}
}
Good Luck....

How to show next n items using WPF ListBox or ScrollView?

I have list box with 10 items.
By default vertical scroll is enabled and i can see first 3 items.
Customer wants me to add 2 buttons "UP" and "down" and on a button click list box should show next 3 items.
For example i want to show by "down" click item 4,item 5, item 6.
How its possible to do with default WPF controls listbox and scrollview?
You can use ScrollViewer.ScrollToVerticalOffset method (msdn).
Example:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="50" />
<RowDefinition Height="20" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Button x:Name="btnUp" Content="UP" Click="btnUp_Click" />
<ScrollViewer x:Name="scroll" Grid.Row="1">
<ListBox x:Name="lbData">
<ListBoxItem>Item1</ListBoxItem>
<ListBoxItem>Item2</ListBoxItem>
<ListBoxItem>Item3</ListBoxItem>
<ListBoxItem>Item4</ListBoxItem>
<ListBoxItem>Item5</ListBoxItem>
<ListBoxItem>Item6</ListBoxItem>
<ListBoxItem>Item7</ListBoxItem>
<ListBoxItem>Item8</ListBoxItem>
<ListBoxItem>Item9</ListBoxItem>
<ListBoxItem>Item10</ListBoxItem>
</ListBox>
</ScrollViewer>
<Button x:Name="btnDown" Content="Down" Click="btnDown_Click" Grid.Row="2" />
<StackPanel Grid.Row="3" Orientation="Horizontal">
<TextBlock Text="Start with:" Margin="2" />
<ComboBox x:Name="cbIndex" Loaded="cbIndex_Loaded" Margin="2" />
<Button x:Name="btnGo" Content="GO" Click="btnGo_Click" Margin="2" />
</StackPanel>
</Grid>
Code-behind:
private void btnUp_Click(object sender, RoutedEventArgs e)
{
scroll.ScrollToVerticalOffset(scroll.VerticalOffset - 50);
}
private void btnDown_Click(object sender, RoutedEventArgs e)
{
scroll.ScrollToVerticalOffset(scroll.VerticalOffset + 50);
}
public double GetOffset(int itemIndex)
{
double result = 0;
for (int i = 0; i < itemIndex; i++)
{
result += (lbData.Items[i] as ListBoxItem).ActualHeight;
}
return result;
}
private void cbIndex_Loaded(object sender, RoutedEventArgs e)
{
cbIndex.ItemsSource = Enumerable.Range(1, lbData.Items.Count);
}
private void btnGo_Click(object sender, RoutedEventArgs e)
{
scroll.ScrollToVerticalOffset(GetOffset(cbIndex.SelectedIndex));
}
Solution for horizontal list:
/// <summary>
/// Show next n items starting from first visible.
/// </summary>
public void ShowNext()
{
if (this.scrollviewer == null)
{
return;
}
var rightLimit = this.scrollviewer.HorizontalOffset + this.scrollviewer.ViewportWidth;
double horizontalOffset = 0;
foreach (var item in this.Items)
{
var container = this.ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
if (container == null)
{
continue;
}
if (horizontalOffset + container.ActualWidth >= rightLimit)
{
// We found last item offset
break;
}
horizontalOffset += container.ActualWidth;
}
this.scrollviewer.ScrollToHorizontalOffset(horizontalOffset);
}
/// <summary>
/// Show previous n items starting last visible item.
/// </summary>
public void ShowPrevious()
{
if (this.scrollviewer == null)
{
return;
}
double horizontalOffset = 0;
foreach (var item in this.Items)
{
var container = this.ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;
if (container == null)
{
continue;
}
horizontalOffset += container.ActualWidth;
if (horizontalOffset >= this.scrollviewer.HorizontalOffset)
{
// We found last item offset
break;
}
}
horizontalOffset -= this.scrollviewer.ViewportWidth;
this.scrollviewer.ScrollToHorizontalOffset(horizontalOffset);
}
This code will show next\previous items from last visible in listbox.

Resources