I have a TextBox. And I want to check if it's empty.
Which way is better
if(TextBox.Text.Length == 0)
or
if(TextBox.Text == '')
?
You should use String.IsNullOrEmpty() to make sure it is neither empty nor null (somehow):
if (string.IsNullOrEmpty(textBox1.Text))
{
// Do something...
}
More examples here.
For practical purposes you might also consider using String.IsNullOrWhitespace() since a TextBox expecting whitespace as input probably negates any purpose, except in case of, say, letting the user pick a custom separator for stuff.
I think
string.IsNullOrEmpty(TextBox.Text)
or
string.IsNullOrWhiteSpace(TextBox.Text)
are your best options.
If one is in XAML, one can check whether there is text in a TextBox by using IsEmpty off of Text property.
Turns out that it bubbles down to CollectionView.IsEmpty (not on the string property) to provide the answer. This example of a textbox watermark, where two textboxes are displayed (on the editing one and one with the watermark text). Where the style on the second Textbox (watermark one) will bind to the Text on the main textbox and turn on/off accordingly.
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=tEnterTextTextBox, Path=IsKeyboardFocusWithin}" Value="False" />
<Condition Binding="{Binding ElementName=tEnterTextTextBox, Path=Text.IsEmpty}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Visible" />
</MultiDataTrigger>
<DataTrigger Binding="{Binding ElementName=tEnterTextTextBox, Path=IsKeyboardFocusWithin}" Value="True">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tEnterTextTextBox, Path=Text.IsEmpty}" Value="False">
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
CollectionView.IsEmpty explanation
Help Text WaterMark to Disappear when user Types in (answer) (this is the full example which I used from the partial answer given above).
You can put that code in the ButtonClick event or any event:
//Array for all or some of the TextBox on the Form
TextBox[] textBox = { txtFName, txtLName, txtBalance };
//foreach loop for check TextBox is empty
foreach (TextBox txt in textBox)
{
if (string.IsNullOrWhiteSpace(txt.Text))
{
MessageBox.Show("The TextBox is empty!");
break;
}
}
return;
Another way:
if(textBox1.TextLength == 0)
{
MessageBox.Show("The texbox is empty!");
}
Here is a simple way
If(txtTextBox1.Text ==“”)
{
MessageBox.Show("The TextBox is empty!");
}
Farhan answer is the best and I would like to add that if you need to fullfil both conditions adding the OR operator works, like this:
if (string.IsNullOrEmpty(text.Text) || string.IsNullOrWhiteSpace(text.Text))
{
//Code
}
Note that there is a difference between using string and String
In my opinion the easiest way to check if a textbox is empty + if there are only letters:
public bool isEmpty()
{
bool checkString = txtBox.Text.Any(char.IsDigit);
if (txtBox.Text == string.Empty)
{
return false;
}
if (checkString == false)
{
return false;
}
return true;
}
Related
Can you guy tell me a great way of coloring the last row in a datagrid in WPF, I have to color the first and last rows, I found a way to do the first one by doing the code below, but I need a way to do the last row.
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Mode=PreviousData}}"
Value="{x:Null}">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
This is a tough one.
You may use the alternation index with a multi-binding on the ItemsSource and the AlternationCount, a IMultiValueConverter, and finally fail because the alternation index may not start from 0. (also, you loose the benefit of an AlternationCount of 2).
You may use code behind and hack the DataGrid to display the hard coded color you want. But that is not MVVM.
You may put a special boolean on your view model to mark those items as special. But this feels to be the wrong place.
...
My approach is to inherit the DataGrid object in a class that will keep up-to-date a ‘IsAnExtremity’ attached property (a pretty touchy pattern) on it's DataGridRow:
public class DataGridEx : DataGrid
{
private static readonly DependencyPropertyKey IsAnExtremityPropertyKey =
DependencyProperty.RegisterAttachedReadOnly(
"IsAnExtremity",
typeof(bool),
typeof(DataGridEx),
new FrameworkPropertyMetadata(defaultValue: false,
flags: FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty IsAnExtremityProperty = IsAnExtremityPropertyKey.DependencyProperty;
public static bool GetIsAnExtremity(DataGridRow dataGridRow)
{
return (bool)dataGridRow.GetValue(IsAnExtremityProperty);
}
private static void SetIsAnExtremity(DataGridRow dataGridRow, bool value)
{
dataGridRow.SetValue(IsAnExtremityPropertyKey, value);
}
private IReadOnlyList<DataGridRow> _extremities = Array.Empty<DataGridRow>();
protected override void OnLoadingRow(DataGridRowEventArgs e)
{
base.OnLoadingRow(e);
UpdateExtremities();
}
protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
UpdateExtremities();
}
private void UpdateExtremities()
{
// Current extremities
var extremities = new[]
{
ItemContainerGenerator.ContainerFromIndex(0),
ItemContainerGenerator.ContainerFromIndex(Items.Count - 1)
}.OfType<DataGridRow>()
.Distinct()
.ToArray();
// Remove the flag from old extremities (if any).
foreach (var oldExtremityContainer in _extremities.Except(extremities))
{
SetIsAnExtremity(oldExtremityContainer, false);
}
// Ensure the flag for new extremities.
foreach (var extremityContainer in extremities)
{
SetIsAnExtremity(extremityContainer, true);
}
_extremities = extremities;
}
}
Then you can use this attached property almost like any other properties in the xaml:
<controls:DataGridEx ItemsSource="{Binding Path=Items}">
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="LightBlue" />
<Style.Triggers>
<Trigger Property="controls:DataGridEx.IsAnExtremity" Value="True">
<Setter Property="Background" Value="Blue" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</controls:DataGridEx>
A working implementation is available here.
I've been set to maintain a wpf application where there is a listbox for logging purposes.
The items displayed using listbox are of type TextMessage, i.e. the listbox is bound to these text messages via
ObservableCollection<TextMessage> Messages;
listBox.DataContext = Messages;
Messages are then added with something like
Messages.Add(new TextMessage("Test", TypeOfMessage.Headline));
This is the definition of the class TextMessage
public enum TypeOfMessage
{
Normal,
Headline,
Focus,
Important,
Fail,
Success
}
public class TextMessage
{
public TextMessage(string content, TypeOfMessage typeOfMessage)
{
Content = content;
TypeOfMessage = typeOfMessage;
CreationTime = DateTime.Now;
}
public string Content { get; }
public TypeOfMessage TypeOfMessage { get; }
public DateTime CreationTime { get; }
}
The xaml definition for the listbox is something like this:
<ListBox x:Name="listBox" HorizontalAlignment="Left" Height="196" Margin="101,77,0,0" VerticalAlignment="Top" Width="256" ItemsSource="{Binding}" SelectionMode="Multiple">
<ListBox.InputBindings>
<KeyBinding
Key="C"
Modifiers="Control"
Command="Copy"
/>
</ListBox.InputBindings>
<ListBox.CommandBindings>
<CommandBinding
Command="Copy"
Executed="DoPerformCopy"
/>
</ListBox.CommandBindings>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="TextToShow" Text="{Binding Content}"></TextBlock>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding TypeOfMessage}" Value="Normal">
<Setter TargetName="TextToShow" Property="Foreground" Value="Black"/>
</DataTrigger>
<DataTrigger Binding="{Binding TypeOfMessage}" Value="Focus">
<Setter TargetName="TextToShow" Property="Foreground" Value="Black"/>
<Setter TargetName="TextToShow" Property="FontWeight" Value="Bold"/>
</DataTrigger>
<DataTrigger Binding="{Binding TypeOfMessage}" Value="Headline">
<Setter TargetName="TextToShow" Property="Foreground" Value="RoyalBlue"/>
<Setter TargetName="TextToShow" Property="FontWeight" Value="Bold"/>
</DataTrigger>
<DataTrigger Binding="{Binding TypeOfMessage}" Value="Important">
<Setter TargetName="TextToShow" Property="Foreground" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding TypeOfMessage}" Value="Fail">
<Setter TargetName="TextToShow" Property="Foreground" Value="Red"/>
<Setter TargetName="TextToShow" Property="FontWeight" Value="Bold"/>
</DataTrigger>
<DataTrigger Binding="{Binding TypeOfMessage}" Value="Success">
<Setter TargetName="TextToShow" Property="Foreground" Value="Green"/>
<Setter TargetName="TextToShow" Property="FontWeight" Value="Bold"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This works nicely (i.e messages are displayed in the listbox in different font weight and color depending on their type), but now for the question :
Is there any way using BindingExpression or any other means to get the font formatting and coloring from code behind from the xaml definitions ?
The reason is that I want to just have the formatting in one place (just in the xaml as it is right now) but still be able to reuse it when I want to copy the contents (using code behind) including font formatting to the clipboard.
Example:
private void DoPerformCopy()
{
RichTextBox rtb = new RichTextBox();
foreach (TextMessage message in (listBox as ListBox)?.SelectedItems.Cast<TextMessage>().ToList())
{
TextPointer startPos = rtb.CaretPosition;
rtb.AppendText(message.Content);
rtb.Selection.Select(startPos, rtb.CaretPosition.DocumentEnd);
//
// Here it would be very nice to instead having multiple switch statements to get the formatting for the
// TypeOfMessage from the xaml file.
SolidColorBrush scb = new SolidColorBrush(message.TypeOfMessage == TypeOfMessage.Fail ? Colors.Red);
//
rtb.Selection.ApplyPropertyValue(RichTextBox.ForegroundProperty, scb);
}
// Now copy the whole thing to the Clipboard
rtb.Selection.Select(rtb.Document.ContentStart, rtb.Document.ContentEnd);
rtb.Copy();
}
Since I'm new to wpf, I'd really appreciate if someone has a tip for solving this. (I've tried hard to find an solution here at stackoverflow, but so far I've been unsuccessful)
Thanks in advance,
King regards
Magnus
Make a ContentPresenter with Content set to your TextMessage. Set the ContentTemplate to listBox.ItemTemplate and apply the template. It will create the visuals (TextBlock in this case). Then, just parse off the values from the TextBlock.
Also, your RichTextBox selection code wasn't working quite right so I fixed that by just inserting TextRanges to the end of it instead of trying to get the selection right.
private void DoPerformCopy(object sender, EventArgs e)
{
RichTextBox rtb = new RichTextBox();
foreach (TextMessage message in (listBox as ListBox)?.SelectedItems.Cast<TextMessage>().ToList())
{
ContentPresenter cp = new ContentPresenter();
cp.Content = message;
cp.ContentTemplate = listBox.ItemTemplate;
cp.ApplyTemplate();
var tb = VisualTreeHelper.GetChild(cp, 0) as TextBlock;
var fg = tb.Foreground;
var fw = tb.FontWeight;
var tr = new TextRange(rtb.Document.ContentEnd, rtb.Document.ContentEnd);
tr.Text = message.Content;
tr.ApplyPropertyValue(RichTextBox.ForegroundProperty, fg);
tr.ApplyPropertyValue(RichTextBox.FontWeightProperty, fw);
}
// Now copy the whole thing to the Clipboard
rtb.Selection.Select(rtb.Document.ContentStart, rtb.Document.ContentEnd);
rtb.Copy();
}
Pre-Warning sorry WPF new guy here:
I have a DataGrid bound to a DataTable's DefaultView
ResultDataGrid.ItemsSource = resultTable.DefaultView;
I know the column names, and I need to change a column's foreground if another column is 1 (always 0 or 1)
Currently what I have:
private void ResultDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (e.Column.Header.ToString() == "columnName")
{
e.Column.CellStyle = FindResource("columnStyle") as Style;
}
}
and in XAML:
<Window.Resources>
<Style TargetType="DataGridCell" x:Key="columnStyle">
<Setter Property="Foreground" Value="Black"/>
<Style.Triggers>
<DataTrigger Binding="{Binding resultTable, Path={StaticResource otherColumnName}}" Value="1">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
Where otherColumnName is set in the constructor
public ResultsCustom(DataTable resultclass, CustomQuery query)
{
// Some other stuff
this.Resources.Add("otherColumnName", COLUMN_NAME);
}
The XAML Style seems to not have the correct path, any help would be appreciated!
I'm not sure about this line of code:
Path={StaticResource otherColumnName}
Are you attempting to compare the property "otherColumnName" of the resultTable to see if this is 1? This wouldn't be a static resource, and you could change your binding to:
Path=otherColumnName
The following is the scenario:
When the ribbon is not minimized, showing a tab linked to a RibbonContextualTabGroup works fine, as visible in the following screenshot.
When the ribbon is minimized, showing a tab linked to a RibbonContextualTabGroup shows the tabs, but not the contextual tab group header, as visible in the following screenshot.
If the ribbon is minimized, but the popup is open, showing a tab linked to a RibbonContextualTabGroup works fine, as visible in the following screenshot. (The popup is not visible, but that is how I created the scenario.)
WebMatrix also has this problem, so I am assuming that Microsoft developers intentionally coded in this functionality. In Windows 8/Office 2013, however, the contextual tab groups always show, regardless of the state of the ribbon.
I am using the .NET 4.0 RibbonControlsLibrary from Microsoft, so I have access to the full source code. How can I modify the code to force the contextual tab groups to always show, regardless of the state of the ribbon?
Yes, really good, thank you very much, Ming!
Is there a way to use RibbonContextualTabGroupItemsControl.cs without copying and overriding all relating ribbon-source-classes?
I followed again the approach overriding the ribbon style to avoid this extensive work and was finally successful
There is a trigger that handles the IsMinimized-property of the ribbon:
<Trigger Property="IsMinimized" Value="True">
<Setter Property="Content" TargetName="mainItemsPresenterHost" Value="{x:Null}"/>
<Setter Property="Visibility" TargetName="mainItemsPresenterHost" Value="Collapsed"/>
<Setter Property="Content" TargetName="popupItemsPresenterHost" Value="{Binding ElementName=groupsBorder}"/>
<Setter Property="BorderThickness" TargetName="BackgroundBorder" Value="0,0,0,1"/>
</Trigger>
The content of mainItemsPresenterHost-control is a border named 'groupsBorder' that contains all ribbon tabs. When the IsMinimized-property changes to true, this border is moved to the popup presenter named 'popupItemsPresenterHost'.
An other trigger handles the IsDropDownOpen-property:
<Trigger Property="IsDropDownOpen" Value="True">
<Setter Property="BorderThickness" TargetName="BackgroundBorder" Value="0"/>
/Trigger>
I changed both trigger as follows:
<Trigger Property="IsMinimized" Value="True">
<!--<Setter Property="Content" TargetName="mainItemsPresenterHost" Value="{x:Null}"/>-->
<!--<Setter Property="Visibility" TargetName="mainItemsPresenterHost" Value="Collapsed"/>-->
<Setter Property="Height" TargetName="mainItemsPresenterHost" Value="0"/>
<!--<Setter Property="Content" TargetName="popupItemsPresenterHost" Value="{Binding ElementName=groupsBorder}"/>-->
<Setter Property="BorderThickness" TargetName="BackgroundBorder" Value="0,0,0,1"/>
</Trigger>
<Trigger Property="IsDropDownOpen" Value="True">
<Setter Property="BorderThickness" TargetName="BackgroundBorder" Value="0,0,0,1"/>
<Setter Property="Content" TargetName="mainItemsPresenterHost" Value="{x:Null}"/>
<Setter Property="Content" TargetName="popupItemsPresenterHost" Value="{Binding ElementName=groupsBorder}"/>
</Trigger>
Note that i have replaced the setter of the Visibility-property of the mainItemsPresenterHost-control with the Height-property and set it to '0'.
i have the same problem and have found this workaround.
Override the OnApplyTemplate-method in the window that owns the ribbon to get the RibbonContextualTabGroupItemsControl and set internal field:
Set the IsMinimized-property of the ribbon to true, before setting the visibility to the contextual group to visible, then call UpdateLayout of the RibbonContextualTabGroupItemsControl and reset the IsMinimized-Property of the ribbon to false:
Code
...
RibbonContextualTabGroupItemsControl _ribbonContextualTabGroupItemsControl;
...
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Ribbon ribbon = this.ribbon;
ribbon.ApplyTemplate();
this._ribbonContextualTabGroupItemsControl = ribbon.Template.FindName("PART_ContextualTabGroupItemsControl", ribbon) as RibbonContextualTabGroupItemsControl;
}
...
void toggleRibbonContextualGroupVisibility()
{
if(this.ribbonContextualGroup.Visibility == Visibility.Collapsed)
{
if (this.ribbon.IsMinimized)
{
this.ribbon.IsMinimized = false;
this.ribbonContextualGroup.Visibility = Visibility.Visible;
this._ribbonContextualTabGroupItemsControl.UpdateLayout();
this.ribbon.IsMinimized = true;
}
else
{
this.ribbonContextualGroup.Visibility = Visibility.Visible;
}
}
else
{
this.ribbonContextualGroup.Visibility = Visibility.Collapsed;
}
}
...
I also have tried to override the RibbonContextualTabGroupItemsControl-class and the Ribbon-style without success.
If there are any other solutions, i am really interested in.
After playing around with the source files for the RibbonControlsLibrary, and just doing hardcore trial-and-error, I found the following solution:
Open RibbonContextualTabGroupItemsControl.cs, located at Microsoft/Windows/Controls/Ribbon, expand the Private Methods #region, and locate the HasTabs function. The code should look something like this:
private bool HasTabs(FrameworkElement container)
{
RibbonContextualTabGroup tabGroupHeader = container as RibbonContextualTabGroup;
if (tabGroupHeader == null ||
!tabGroupHeader.IsVisible)
{
return false;
}
foreach (RibbonTab tab in tabGroupHeader.Tabs)
{
if (tab != null && tab.IsVisible)
{
return true;
}
}
return false;
}
All I added was the following two lines of code:
if (Ribbon.IsMinimized)
return true;
The function should now look like this:
private bool HasTabs(FrameworkElement container)
{
RibbonContextualTabGroup tabGroupHeader = container as RibbonContextualTabGroup;
if (tabGroupHeader == null ||
!tabGroupHeader.IsVisible)
{
return false;
}
if (Ribbon.IsMinimized)
return true;
foreach (RibbonTab tab in tabGroupHeader.Tabs)
{
if (tab != null && tab.IsVisible)
{
return true;
}
}
return false;
}
Run your application, and voíla, the contextual tab groups now show even if the ribbon is minimized.
Note that if you do NOT have access to the ribbon source code, then using zznobody's solution will still work at a pinch.
I have a textbox containing a decimal value on my interface that I want to clear whenever the user selects it.
However, if the user doesn't make any changes and selects another interface element I need the text to revert to whatever it was previous to the clear.
So far I have the the following style:
<Style x:Key="CustomTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Text" Value="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"/>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Text" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
And then the following to use the style:
<TextBox Style="{DynamicResource CustomTextBoxStyle}"
Tag="{Binding myDecimalValue, StringFormat=#.###}"
TabIndex="1" />
However, in this scenario the value reverts back to what it was even when the user enters a new value.
Can anyone tell me the best way to go about achieving this?
Thanks,
The solution here is not to hide the text but to store it in a variable for use later. In C# the code would be something like:
string _originalValue;
public OnFocus(){
_originalValue = TextBox.Text;
TextBox.Text = "";
}
public LostFocus(){
if(TextBox.Text == "")
TextBox.Text = _originalValue;
}
You could set the forground colour to transparent to hide the text if that's appropriate.
If you actually want to delete the text you should do what Ryan Amies is suggesting on the viewmodel which you should be able to get through the datacontext.
Thanks for the help, but I was able to achieve what I was looking for and adhere to MVVM principles by using the AttachedProperty described at the following:
https://stackoverflow.com/a/7972361/1466960
This allowed me to bind the IsFocused property to a value in my view model and proceed in a similar fashion to the one described by Ryan Amies.
View Model:
bool isFocused = false;
double original;
public bool IsFocused
{
get
{
return isFocused;
}
set
{
isFocused = value;
if (isFocused)
{
original = current;
current = "";
}
else
{
if (HundredPercentLine == "")
current = original;
}
OnPropertyChanged(new PropertyChangedEventArgs("IsFocused"));
}
}