I have two text boxes: min and max for user to enter. If the max number is smaller than the min number, the number in the max text box will be automatically changed to the same number as the min number in the min text box.
What is the best way to implement it with wpf and C#? Code would be great.
Thanks!
Define two properties MinValue and MaxValue of type int in your ViewModel (if using MVVM) and bind to two text boxes.
C#
private int minValue;
private int maxValue;
public int MinValue
{
get { return minValue; }
set
{
minValue = value;
PropertyChanged(this, new PropertyChangedEventArgs("MinValue"));
if (minValue > maxValue)
{
MaxValue = minValue;
}
}
}
public int MaxValue
{
get { return maxValue; }
set
{
maxValue = value;
PropertyChanged(this, new PropertyChangedEventArgs("MaxValue"));
if(maxValue < minValue)
{
MinValue = maxValue;
}
}
}
Xaml:
<TextBox Text="{Binding MinValue, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding MaxValue, UpdateSourceTrigger=PropertyChanged}"/>
Thanks
Just putting the way I achieve in my WPF code for MIN numeric Value is 0 and MAX numeric value is 99.
hope this may help
<!-- WPF Code Sample.xaml -->
<TextBox
Text="1"
Width="20"
PreviewTextInput="PreviewTextInputHandler"
IsEnabled="True"/>
https://social.msdn.microsoft.com/Forums/vstudio/en-US/990c635a-c14e-4614-b7e6-65471b0e0e26/how-to-set-minvalue-and-max-value-for-a-testbox-in-wpf?forum=wpf
// C# Code Sample.xaml.cs
private void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
{
// MIN Value is 0 and MAX value is 99
var textBox = sender as TextBox;
bool bFlag = false;
if (!string.IsNullOrWhiteSpace(e.Text) && !string.IsNullOrWhiteSpace(textBox.Text))
{
string str = textBox.Text + e.Text;
bFlag = str.Length <= 2 ? false : true;
}
e.Handled = (Regex.IsMatch(e.Text, "[^0-9]+") || bFlag);
}
Related
I want to Style a TextBox with decimal places like this:
How can I do that ?
You can extend the TextBox like this.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
public class DecimalTextBox : TextBox
{
public static readonly DependencyProperty FloatColorProperty = DependencyProperty.Register("FloatColor", typeof(Color), typeof(DecimalTextBox), new FrameworkPropertyMetadata(Colors.Red));
public Color FloatColor
{
get { return (Color)GetValue(FloatColorProperty); }
set { SetValue(FloatColorProperty, value); }
}
protected TextBlock _textBlock;
protected FrameworkElement _textBoxView;
public DecimalTextBox()
{
_textBlock = new TextBlock() { Margin = new Thickness(1, 0, 0, 0) };
Loaded += ExTextBox_Loaded;
}
private void ExTextBox_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= ExTextBox_Loaded;
// hide the original drawing visuals, by setting opacity on their parent
var visual = this.GetChildOfType<DrawingVisual>();
_textBoxView = (FrameworkElement)visual.Parent;
_textBoxView.Opacity = 0;
// add textblock to do the text drawing for us
var grid = this.GetChildOfType<Grid>();
if (grid.Children.Count >= 2)
grid.Children.Insert(1, _textBlock);
else
grid.Children.Add(_textBlock);
}
protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnLostKeyboardFocus(e);
_textBoxView.Opacity = 0;
_textBlock.Visibility = Visibility.Visible;
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
_textBoxView.Opacity = 1;
_textBlock.Visibility = Visibility.Collapsed;
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
// making sure text on TextBlock is updated as per TextBox
var dotPos = Text.IndexOf('.');
var textPart1 = dotPos == -1 ? Text : Text.Substring(0, dotPos + 1);
var textPart2 = (dotPos == -1 || dotPos >= (Text.Length-1)) ? null : Text.Substring(dotPos + 1);
_textBlock.Inlines.Clear();
_textBlock.Inlines.Add(new Run {
Text = textPart1,
FontFamily = FontFamily,
FontSize = FontSize,
Foreground = Foreground });
if (textPart2 != null)
_textBlock.Inlines.Add(new Run {
Text = textPart2,
FontFamily = FontFamily,
TextDecorations = System.Windows.TextDecorations.Underline,
BaselineAlignment = BaselineAlignment.TextTop,
FontSize = FontSize * 5/6,
Foreground = new SolidColorBrush(FloatColor) });
}
}
public static class HelperExtensions
{
public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
}
XAML code usage
<local:DecimalTextBox FloatColor="Maroon" />
And your output should look like this:
Update 05/17
Explanation: As you can see from the image, the DecimalTextBox displays the text in formatted mode only when its not focused.
I had initially developed the control to support formatting during edit (which can still be done by commenting the methods OnLostKeyboardFocus, and OnGotKeyboardFocus) - but because of the font-size difference the cursor positioning was getting slightly skewed, which in turn would translate to bad user experience.
Therefore, implemented the swap logic during GotFocus and LostFocus to fix that.
You can't do that with a TextBox, because TextBox only accepts color changes to the entire text. You should try with RichTextBox, that allows loop throug TextRange's. Look at this sample of syntax highlighting with a RichTextBox.
I actually understood how it works and made it:
private void richTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
richTextBox.TextChanged -= this.richTextBox_TextChanged;
if (richTextBox.Document == null)
return;
TextRange documentRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
documentRange.ClearAllProperties();
int dotIndex = documentRange.Text.IndexOf(".");
if(dotIndex == -1)
{
richTextBox.TextChanged += this.richTextBox_TextChanged;
return;
}
TextPointer dotStart = GetPoint(richTextBox.Document.ContentStart, dotIndex);
TextPointer dotEnd = dotStart.GetPositionAtOffset(1, LogicalDirection.Forward);
TextRange initRange = new TextRange(richTextBox.Document.ContentStart, dotStart);
TextRange endRange = new TextRange(dotEnd, richTextBox.Document.ContentEnd);
endRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
richTextBox.TextChanged += this.richTextBox_TextChanged;
}
Suscribe the textbox TextChanged event to this method. You can now set the styles you want to every part of the text like this:
To change the last part (after the dot char) endRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
To change the first part (before the dot char) is the same but for the initRange variable. If you want to change the 'dot' style, then create a new TextRange with dotStart and dotEnd TextPointers and apply styles to it. You can do other things like change font style, size, etc.
This code result looks like this:
All this is just for style. For checking that is a number is up to you.
I would define a custom control with this main properties:
FloatNumber: the original number, that should be a DependencyProperty to be Bind from the control.
NumberOfDecimalDigits: a number to choose how many decimal digits to represent, that should be a DependencyProperty to be Bind from the control.
FirstPart: a string that will contain the first part of the decimal number
Decimals: a string that will contain the decimal digits of FloatNumber
Of course this is just a scratch, those properties could be implemented better to extract FloatNumber parts.
public partial class DecimalDisplayControl : UserControl, INotifyPropertyChanged
{
public DecimalDisplayControl()
{
InitializeComponent();
(Content as FrameworkElement).DataContext = this;
}
public static readonly DependencyProperty NumberOfDecimalDigitsProperty =
DependencyProperty.Register(
"NumberOfDecimalDigits", typeof(string),
typeof(DecimalDisplayControl), new PropertyMetadata(default(string), OnFloatNumberChanged));
public static readonly DependencyProperty FloatNumberProperty =
DependencyProperty.Register(
"FloatNumber", typeof(string),
typeof(DecimalDisplayControl), new PropertyMetadata(default(string), OnFloatNumberChanged));
private static void OnFloatNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as DecimalDisplayControl).OnFloatNumberChanged();
}
protected void OnFloatNumberChanged()
{
int numberOfDecimalDigits = Convert.ToInt32(NumberOfDecimalDigits);
float fullNumber = Convert.ToSingle(FloatNumber);
float firstPart = (float)Math.Truncate(fullNumber);
float fullDecimalPart = fullNumber - firstPart;
int desideredDecimalPart = (int)(fullDecimalPart * Math.Pow(10, numberOfDecimalDigits));
FirstPart = $"{firstPart}.";
Decimals = desideredDecimalPart.ToString();
}
public string FloatNumber
{
get => (string)GetValue(FloatNumberProperty);
set { SetValue(FloatNumberProperty, value); }
}
public string NumberOfDecimalDigits
{
get => (string)GetValue(NumberOfDecimalDigitsProperty);
set { SetValue(NumberOfDecimalDigitsProperty, value); }
}
private string _firstPart;
public string FirstPart
{
get => _firstPart;
set
{
if (_firstPart == value)
return;
_firstPart = value;
OnPropertyChanged();
}
}
private string _decimals;
public string Decimals
{
get => _decimals;
set
{
if (_decimals == value)
return;
_decimals = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Its XAML:
<UserControl
x:Class="WpfApp1.CustomControls.DecimalDisplayControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
FontSize="20"
Foreground="Black"
Text="{Binding FirstPart}" />
<TextBlock
FontSize="10"
Foreground="Red"
Text="{Binding Decimals}"
TextDecorations="Underline" />
</StackPanel>
</UserControl>
Then you can use it in your page and bind a property to make it change dynamically:
<Grid>
<StackPanel VerticalAlignment="Center" Orientation="Vertical">
<customControls:DecimalDisplayControl
HorizontalAlignment="Center"
VerticalAlignment="Center"
NumberOfDecimalDigits="2"
FloatNumber="{Binding MyNumber}" />
<TextBox
Width="200"
VerticalAlignment="Center"
Text="{Binding MyNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Grid>
The final result:
Is there any way that i can show my text in column wise like:
1 5
2 6
3 7
4 8
Like this:
<TextBox x:Name="mytextbox" TextWrapping="Wrap" AcceptsReturn="True" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Auto" />
This is my TextBox. I am getting text from a service which is string and set in this text box well that is not an issue. Issue is how can i display multiple text in column wise as I mention above?
<TextBox x:Name="Mytextbox" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Auto"
Text="1 5
2 6
3 7
4 8">
</TextBox>
Also you can specify text in code like in the example:
Mytextbox.Text = "1\t3" + Environment.NewLine + "2\t4";
#omeriqbal: to explain my comment. create a collection from your string
this.MyText = new List<string>{"1","2","3","4",...};
instead of the textbox you could use an itemscontrol
<ItemsControl itemsSource="{Binding MyText}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Local:UniformGrid2 Orientation="Vertical" Rows="6" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
if you want a fix rowsize you can create you own uniformgrid
public class UniformGrid2 : UniformGrid
{
private int _columns;
private int _rows;
#region Orientation
/// <summary>
/// Orientation Dependency Property
/// </summary>
public static readonly DependencyProperty OrientationProperty =
StackPanel.OrientationProperty.AddOwner(typeof(UniformGrid2),
new FrameworkPropertyMetadata((Orientation)Orientation.Horizontal,
FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Gets or sets the Orientation property.
/// </summary>
public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
#endregion
protected override Size ArrangeOverride(Size arrangeSize)
{
if (Orientation == Orientation.Horizontal)
return base.ArrangeOverride(arrangeSize);
else
return ArrangeOverrideVertical(arrangeSize);
}
protected override Size MeasureOverride(Size constraint)
{
if (Orientation == Orientation.Horizontal)
return base.MeasureOverride(constraint);
else
return MeasureOverrideVertical(constraint);
}
private Size ArrangeOverrideVertical(Size arrangeSize)
{
Rect finalRect = new Rect(0.0, 0.0, arrangeSize.Width / ((double)_columns), arrangeSize.Height / ((double)_rows));
double height = finalRect.Height;
double totalHeight = arrangeSize.Height - 1.0;
foreach (UIElement element in base.InternalChildren)
{
element.Arrange(finalRect);
if (element.Visibility != Visibility.Collapsed)
{
finalRect.Y += height;
if (finalRect.Y >= totalHeight)
{
finalRect.X += finalRect.Width;
finalRect.Y = 0.0;
}
}
}
return arrangeSize;
}
private Size MeasureOverrideVertical(Size constraint)
{
UpdateComputedValuesVertical();
Size availableSize = new Size(constraint.Width / ((double)_columns), constraint.Height / ((double)_rows));
double width = 0.0;
double height = 0.0;
int i = 0;
int count = base.InternalChildren.Count;
while (i < count)
{
UIElement element = base.InternalChildren[i];
element.Measure(availableSize);
Size desiredSize = element.DesiredSize;
if (width < desiredSize.Width)
{
width = desiredSize.Width;
}
if (height < desiredSize.Height)
{
height = desiredSize.Height;
}
i++;
}
return new Size(width * _columns, height * _rows);
}
private void UpdateComputedValuesVertical()
{
_columns = Columns;
_rows = Rows;
// Ignore FirstColumn property
FirstColumn = 0;
if (_rows == 0 || _columns == 0)
{
int visibleChildren = 0;
int i = 0;
int count = base.InternalChildren.Count;
while (i < count)
{
UIElement element = base.InternalChildren[i];
if (element.Visibility != Visibility.Collapsed)
{
visibleChildren++;
}
i++;
}
if (visibleChildren == 0)
{
visibleChildren = 1;
}
if (_columns == 0)
{
if (_rows > 0)
{
_columns = (visibleChildren + (_rows - 1)) / _rows;
}
else
{
_columns = (int)Math.Sqrt((double)visibleChildren);
if ((_columns * _columns) < visibleChildren)
{
_columns++;
}
_rows = _columns;
}
}
else if (_rows == 0)
{
_rows = (visibleChildren + (_columns - 1)) / _columns;
}
}
}
}
There are AcceptsTab boolean property in Textbox allow you to have tab in string and when you want to type in a Textbox and press the tab key the Textbox focus don't lost and in the text the tab space appear and after saving it to database or variable and assign it to the Textbox you have your tabs.
<TextBox TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" VerticalScrollBarVisibility="Auto" Height="70"/>
I have a problem in slider value data binding in MVVM. When value gets changed my expected value isn’t achieved. How can I solve my problem?
I have a listbox, a slider and a textblock. listbox is bound to ListImage, slider value and textblock text is bound to CurrentImage. One button with command navigate the lisbox item. CurrentImage is a property in the viewmodel. When I change slider’s setter, new value of setter put to current value of slider’s setter and the arrangement of listbox gets corrupted. For example when value of my slider’s setter set to 50 and I change value of slider to 10 again. My slider value navigate from 10 to 50 and not more. It must be navigate whole of the listbox but it can’t. There is my code:
XAML:
<TextBlock Text="{Binding CurrentImage.Index}"/>
<Slider Height="23" HorizontalAlignment="Left" Margin="12,305,0,0" Name="slider1" VerticalAlignment="Top" Width="479" Maximum="{Binding ListImage.Count, Mode=OneTime}"
Value="{Binding CurrentImage.Index, Mode=TwoWay}"
SmallChange="1" />
<Button Content="{Binding DisplayPlay}" Command="{Binding PlayCommand}" Height="23" HorizontalAlignment="Left" Margin="507,305,0,0" Name="button1" VerticalAlignment="Top" Width="75" />
<ListBox Height="129" HorizontalAlignment="Left" Margin="12,334,0,0" ItemsSource="{Binding ListImage}" SelectedItem="{Binding CurrentImage,Mode=TwoWay}"
VerticalAlignment="Top" Width="472">
viewmodel:
public class MainViewModel : ViewModelBase
{
public ICommand PlayCommand { get; set; }
private DispatcherTimer _Timer;
public ImageDTO Image { get; set;}
DataAccess AC = new DataAccess();
public byte[] Bytes { get; set; }
public MainViewModel()
{
ListImage = AC.OpenImages();
CurrentImage = ListImage[0];
Bytes = CurrentImage.Bytes;
this.PlayCommand = new DelegateCommand(Play, CanPlay);
DisplayPlay = "Play";
_Timer = new DispatcherTimer();
_Timer.Interval = new TimeSpan(0, 0, 0, 0, 2000 / 30);
_Timer.Tick += new EventHandler(timer_Tick);
}
private string _DisplayPlay;
public string DisplayPlay
{
get { return _DisplayPlay; }
set
{
if (_DisplayPlay != value)
{
_DisplayPlay = value;
OnPropertyChanged("DisplayPlay");
}
}
}
private List<ImageDTO> _ListImage;
public List<ImageDTO> ListImage
{
get { return _ListImage; }
set
{
if (_ListImage != value)
_ListImage = value;
OnPropertyChanged("ListImage");
}
}
private ImageDTO _CurrentImage;
public ImageDTO CurrentImage
{
get { return _CurrentImage; }
set
{
if (_CurrentImage != value)
{
_CurrentImage = value;
OnPropertyChanged("CurrentImage");
}
}
}
public bool CanPlay(object parameter)
{
return true;
}
public void Play(object parameter)
{
if (DisplayPlay == "Play")
{
DisplayPlay = "Pause";
_Timer.Start();
}
else
{
_Timer.Stop();
DisplayPlay = "Play";
}
}
private void timer_Tick(object sender, EventArgs e)
{
int position = ListImage.FindIndex(x => x.Index == CurrentImage.Index);
position++;
if (position == ListImage.Count)
{
position = 0;
}
else
{
CurrentImage = ListImage[position];
}
}
Maybe this is what you want:
<StackPanel>
<ListBox x:Name="ImageListBox" IsSynchronizedWithCurrentItem="True">
<ListBoxItem>Image1</ListBoxItem>
<ListBoxItem>Image2</ListBoxItem>
<ListBoxItem>Image3</ListBoxItem>
<ListBoxItem>Image4</ListBoxItem>
</ListBox>
<Slider Value="{Binding ElementName=ImageListBox, Path=SelectedIndex}"
Maximum="{Binding ElementName=ImageListBox, Path=Items.Count}"/>
</StackPanel>
You probably want to handle the max value nicer than in this sample
In your code the value of slider is bound to CurrentImage index, so when you change the value of slider then the index of the current image will be changed. Assumed that the current image index is 5 then your slider’s value will be 5 then if you move the slider pointer to a position like 10 then the Current image index will be set to 10 it means that your current image will be modified, so it means that it would not navigate to the 10th element of list, but it modifies the index of the image (with index of 5) and set its index to 10, in other words, you would not have a image with index of 5 anymore and 2 of your images are going to have the same index (10).
As a solution, you can add another property like “Index” into your viewmodel, and bind the slider value to that one, so at get method return the index of the selected item in list, and at the set method change the selected item in the list and call OnPropertyChanged and pass “Index” as the parameter.
I have an implementation of highlight text in datagrid when the user input a text in searchbox and click on search. The problem is when the user clicks the scrollbar in datagrid, the hightlight is gone. Below is my custom class for hightlighting:
public class SearchableTextBlock
{
public static DependencyProperty SearchPhraseProperty =
DependencyProperty.RegisterAttached(
"SearchPhrase",
typeof(string),
typeof(SearchableTextBlock), new PropertyMetadata("", SearchPhraseChanged));
public static string GetSearchPhrase(UIElement element)
{
return (string)element.GetValue(SearchPhraseProperty);
}
public static void SetSearchPhrase(UIElement element, string value)
{
element.SetValue(SearchPhraseProperty, value);
}
public static void SearchPhraseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null)
return;
if ((d as TextBlock) != null)
{
TextBlock tbx = d as TextBlock;
String text = tbx.Text;
tbx.Inlines.Clear();
string txtStore = "";
//Loops throught the entire text
for (int i = 0; i < text.Length; i++)
{
txtStore += text[i];
//If search phrase is found
if (txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper()) > -1)
{
//Creates the formatting for regular text
Run runRegular = new Run();
runRegular.Text = txtStore.Substring(0, txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper()));
//Creates the formatting for the found text
//Foreground is hardcoded to red.
Run runHighlight = new Run();
runHighlight.Text = txtStore.Substring(txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper()), txtStore.Length - (txtStore.ToUpper().IndexOf((e.NewValue as string).ToUpper())));
runHighlight.Foreground = new SolidColorBrush(Colors.Red);
runHighlight.FontWeight = FontWeights.Bold;
//Inserts the formatted text to the textblock
txtStore = "";
tbx.Inlines.Add(runRegular);
tbx.Inlines.Add(runHighlight);
}
}
Run runRemaining = new Run();
runRemaining.Text = txtStore;
tbx.Inlines.Add(runRemaining);
}
}
}
Here's my XAML:
<sdk:DataGridTemplateColumn x:Name="Database" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Database}"
sTextBlock:SearchableTextBlock.SearchPhrase="{Binding SDatabase, Mode=TwoWay}"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
Thanks!
You could try disable the DataGrid's virtualization. Try Xusan's solution in this post.
Hope this helps.
Miguel
I am using a MVVM Wizard with several pages. When I set a value in the combobox and go to the next page and switch back I want to reset the value I set before.
But all whats happening is that the combobox is empty at top and the index is -1 ?
What do I wrong?
<ComboBox ItemsSource="{Binding Path=LessonNumbers}" SelectedIndex="{Binding SelectedLessonNumber}" />
private ReadOnlyCollection<int> _lessonNumbers;
public ReadOnlyCollection<int> LessonNumbers
{
get
{
if (_lessonNumbers == null)
this.CreateLessonNumbers();
return _lessonNumbers;
}
}
private void CreateLessonNumbers()
{
var list = new List<int>();
for (int i = 1; i < 24; i++)
{
list.Add(i);
}
_lessonNumbers = new ReadOnlyCollection<int>(list);
}
private int _selectedLessonNumber;
public int SelectedLessonNumber
{
get { return _selectedLessonNumber; }
set
{
if (_selectedLessonNumber == value)
return;
_selectedLessonNumber = value;
this.OnPropertyChanged("SelectedLessonNumber");
}
}
UPDATE:
<ComboBox
SelectedIndex="0"
SelectedItem="{Binding SelectedWeeklyRotationNumber}"
ItemsSource="{Binding Path=WeeklyRotationNumbers}"
Height="23"
HorizontalAlignment="Left"
Margin="336,212,0,0"
VerticalAlignment="Top"
Width="121"
MaxDropDownHeight="100"
IsReadOnly="True"
IsTextSearchEnabled="False"
/>
private ReadOnlyCollection _weeklyRotationNumbers;
public ReadOnlyCollection WeeklyRotationNumbers
{
get
{
if (_weeklyRotationNumbers == null)
this.CreateWeeklyRotationNumbers();
return _weeklyRotationNumbers;
}
}
private void CreateWeeklyRotationNumbers()
{
var list = new List<string>();
list.Add("No rotation");
for (int i = 1; i < 16; i++)
list.Add(i.ToString());
_weeklyRotationNumbers = new ReadOnlyCollection<string>(list);
}
private string _selectedWeeklyRotationNumber;
public string SelectedWeeklyRotationNumber
{
get { return _selectedWeeklyRotationNumber; }
set
{
if (_selectedWeeklyRotationNumber == value)
return;
_selectedWeeklyRotationNumber = value;
this.RaisePropertyChanged("SelectedWeeklyRotationNumber");
Messenger.Default.Send<string>(value);
}
}
Again, what do I wrong or what is wrong with the string property?
Change XAML SelectedIndex to SelectedItem:
<ComboBox ItemsSource="{Binding Path=LessonNumbers}"
SelectedItem="{Binding SelectedLessonNumber}" />
UPDATE:
Somewhere you must set the DataContext of your Window to reference the collection from your XAML.
In my case I typically do that in the constructor of my view.
// this my class containing WeeklyRotationNumbers
private MainViewModel _mvm;
public MainView()
{
InitializeComponent();
_mvm = new MainViewModel();
DataContext = _mvm;
}
I added string to the read only collections:
private ReadOnlyCollection<string> _weeklyRotationNumbers;
public ReadOnlyCollection<string> WeeklyRotationNumbers
I also implemented the interface INotifyPropertyChanged which I think you did, but you are likely using
a different base class to handle the PropertyChanged event.
Everthing else I cut and paste from your code.