wpf 更改文本框边框颜色的最佳实践?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15521550/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best practice for changing TextBox Border color?
提问by WiiMaxx
Suppose you have a View with multiple Texboxes like this
假设你有一个像这样有多个 Texbox 的视图
<TextBox Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
each already containing some text. If the user changes this text the Textbox Border should change to Orange and if he undos his changes it should get it's default color.
每个已经包含一些文本。如果用户更改此文本,文本框边框应更改为橙色,如果他撤消更改,则应为默认颜色。
At the moment I do it like this
目前我这样做
<TextBox Height="23" Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" BorderThickness="2">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding myDirtyText1, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="BorderBrush" Value="Orange"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Is there a more generic / simpler way to do this?
有没有更通用/更简单的方法来做到这一点?
Edit
编辑
I am already using IDataErrorInfo+ System.ComponentModel.DataAnnotationsfor Error validation. Maybe there is a similar way in this case but I didn't found anything useful to reduce my xaml and code to an minimum.
我已经在使用IDataErrorInfo+System.ComponentModel.DataAnnotations进行错误验证。也许在这种情况下有类似的方法,但我没有发现任何有用的东西可以将我的 xaml 和代码减少到最低限度。
EDIT 2.0
编辑 2.0
i think you doesn't really understand my problem so i will provide a better sample of how it actual looks like:
我认为您并没有真正理解我的问题,因此我将提供一个更好的示例来说明它的实际情况:
View Xaml (no codebehind)
查看 Xaml(无代码隐藏)
<Grid Margin="12">
<Label Content="Name:" Height="28" HorizontalAlignment="Left" VerticalAlignment="Top" Width="79" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,2,0,0" VerticalAlignment="Top" Width="170" BorderThickness="2"
Text="{Binding NameD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding dirtyName, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="BorderBrush" Value="Orange"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Label Content="Anzeigetext:" Height="28" HorizontalAlignment="Left" Margin="0,34,0,0" VerticalAlignment="Top" Width="79" />
<TextBox BorderThickness="2" Height="23" HorizontalAlignment="Left" Margin="102,36,0,0" VerticalAlignment="Top" Width="170"
Text="{Binding AnzeigetextD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding dirtyAnzeigetext, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="BorderBrush" Value="Orange"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Label Content="Preis:" Height="28" HorizontalAlignment="Left" Margin="0,68,0,0" VerticalAlignment="Top" Width="79" />
<TextBox BorderThickness="2" Height="23" HorizontalAlignment="Left" Margin="102,70,0,0" VerticalAlignment="Top" Width="170"
Text="{Binding PreisD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat=\{0:c\}}">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding dirtyPreis, UpdateSourceTrigger=PropertyChanged}" Value="True">
<Setter Property="BorderBrush" Value="Orange"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button Content="Speichern" Height="23" HorizontalAlignment="Left" Margin="102,110,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveCommand}"/>
<Button Content="Abbrechen" Height="23" HorizontalAlignment="Left" Margin="197,110,0,0" VerticalAlignment="Top" Width="75" Command="{Binding CancelCommand}"/>
</Grid>
ViewModel
视图模型
public class MenuangebotVM : DetailVM, IContains
{
#region private Values
private Menuangebot myOriginal = new Menuangebot();
private Menuangebot myValue = new Menuangebot();
#endregion // private Values
#region Properties
#region Detail Properties
public int Id { get { return myOriginal.Id; } }
public bool? Result { get; private set; }
public string Beschreibung { get { return "Einrichtung"; } }
[Required]
[RegularExpression(@"^[0-9a-zA-Z??ü???ü?''-'\s]{2,40}$")]
public string NameD
{
get { return myValue.Name; }
set
{
myValue.Name = value;
RaisePropertyChanged(() => Reg(() => NameD));
RaisePropertyChanged(() => Reg(() => dirtyName));
}
}
public bool dirtyName
{
get { return (!isNew && myValue.Name != myOriginal.Name) ? true : false; }
}
[Required]
[RegularExpression(@"^[0-9a-zA-Z??ü???ü?''-'\s]{2,25}$")]
public string AnzeigetextD
{
get { return myValue.Anzeigetext; }
set
{
myValue.Anzeigetext = value;
RaisePropertyChanged(() => Reg(() => AnzeigetextD));
RaisePropertyChanged(() => Reg(() => dirtyAnzeigetext));
}
}
public bool dirtyAnzeigetext
{
get { return (!isNew && myValue.Anzeigetext != myOriginal.Anzeigetext) ? true : false; }
}
[Required]
public decimal PreisD
{
get { return myValue.Preis; }
set
{
myValue.Preis = value;
RaisePropertyChanged(() => Reg(() => PreisD));
RaisePropertyChanged(() => Reg(() => dirtyPreis));
}
}
public bool dirtyPreis
{
get
{
var value = myValue.Preis;
var Original = myOriginal.Preis;
return (!isNew && value != Original) ? true : false;
}
}
#endregion //Detail Properties
#endregion //Properties
// more code
}
what i excspect should be something like
我所期待的应该是这样的
View
看法
<Grid Margin="12">
<Label Content="Name:" Height="28" HorizontalAlignment="Left" VerticalAlignment="Top" Width="79" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="102,2,0,0" VerticalAlignment="Top" Width="170" BorderThickness="2"
Text="{Binding NameD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, EditesOnDataChanges=true}">
</TextBox>
<Label Content="Anzeigetext:" Height="28" HorizontalAlignment="Left" Margin="0,34,0,0" VerticalAlignment="Top" Width="79" />
<TextBox BorderThickness="2" Height="23" HorizontalAlignment="Left" Margin="102,36,0,0" VerticalAlignment="Top" Width="170"
Text="{Binding AnzeigetextD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, EditesOnDataChanges=true}">
</TextBox>
<Label Content="Preis:" Height="28" HorizontalAlignment="Left" Margin="0,68,0,0" VerticalAlignment="Top" Width="79" />
<TextBox BorderThickness="2" Height="23" HorizontalAlignment="Left" Margin="102,70,0,0" VerticalAlignment="Top" Width="170"
Text="{Binding PreisD, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, StringFormat=\{0:c\, EditesOnDataChanges=true}}">
</TextBox>
<Button Content="Speichern" Height="23" HorizontalAlignment="Left" Margin="102,110,0,0" VerticalAlignment="Top" Width="75" Command="{Binding SaveCommand}"/>
<Button Content="Abbrechen" Height="23" HorizontalAlignment="Left" Margin="197,110,0,0" VerticalAlignment="Top" Width="75" Command="{Binding CancelCommand}"/>
</Grid>
ViewModel
视图模型
public class MenuangebotVM : DetailVM, IContains
{
#region private Values
private Menuangebot myOriginal = new Menuangebot();
private Menuangebot myValue = new Menuangebot();
#endregion // private Values
#region Properties
#region Detail Properties
public int Id { get { return myOriginal.Id; } }
public bool? Result { get; private set; }
public string Beschreibung { get { return "Einrichtung"; } }
[Required]
[RegularExpression(@"^[0-9a-zA-Z??ü???ü?''-'\s]{2,40}$")]
[Default(myOriginal.Name)] //<-- added
public string NameD
{
get { return myValue.Name; }
set
{
myValue.Name = value;
RaisePropertyChanged(() => Reg(() => NameD));
}
}
[Required]
[RegularExpression(@"^[0-9a-zA-Z??ü???ü?''-'\s]{2,25}$")]
[Default(myOriginal.Anzeigetext)] //<-- added
public string AnzeigetextD
{
get { return myValue.Anzeigetext; }
set
{
myValue.Anzeigetext = value;
RaisePropertyChanged(() => Reg(() => AnzeigetextD));
}
}
[Required]
[Default(myOriginal.Preis)] //<-- added
public decimal PreisD
{
get { return myValue.Preis; }
set
{
myValue.Preis = value;
RaisePropertyChanged(() => Reg(() => PreisD));
}
}
#endregion //Detail Properties
#endregion //Properties
// more code
}
回答by yo chauhan
public class ViewModel:INotifyPropertyChanged
{
private string initialText;
public ViewModel()
{
Text = "ABCD";
initialText = Text;
DefaultBorder = true;
}
private string text;
public string Text
{
get { return text; }
set { text = value;
if (value == initialText)
DefaultBorder = true;
else
DefaultBorder = false;
Notify("Text"); }
}
private bool defaultBorder;
public bool DefaultBorder
{
get { return defaultBorder; }
set { defaultBorder = value; Notify("DefaultBorder"); }
}
private void Notify(string propertyName)
{
if(PropertyChanged!=null)
PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is bool && !(bool)value)
return new SolidColorBrush(Colors.Orange);
else
return new SolidColorBrush(Colors.Navy); //Or default whatever you want
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
<Window.Resources>
<local:MyConverter x:Key="MyConverter"/>
</Window.Resources>
<Grid>
<TextBox BorderThickness="4" BorderBrush="{Binding DefaultBorder, Converter={StaticResource MyConverter}}" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
Here I have property Text in ViewModel that is bound to TextBox and at the beginning i preserved the initial Text value . and then whenever user type i compare it in setter of Text property and set Bool Property accordingly , this bool property will specify which color to Bind using converter.Ignore minor issues hope you will get an idea.
在这里,我在 ViewModel 中有属性 Text 绑定到 TextBox 并且在开始时我保留了初始 Text 值。然后每当用户输入我在 Text 属性的 setter 中比较它并相应地设置 Bool 属性时,此 bool 属性将指定使用转换器绑定哪种颜色。忽略小问题希望您能有所了解。
回答by TYY
You can probably turn this to a custom control/UserControl and add a IsDirtyDependencyProperty, and the IsDirtyColorDependencyProperty (or attached dependency property). That way you replace all your textboxes with this and not have to repeat the code over and over.
您可以将其转换为自定义控件/用户控件并添加 IsDirtyDependencyProperty 和 IsDirtyColorDependencyProperty(或附加的依赖项属性)。这样你就可以用这个替换所有的文本框,而不必一遍又一遍地重复代码。
回答by Dot NET
Coincidentally I just had a problem almost identical to yours, and I solved it by wrapping the TextBoxin a Border. Furthermore, this also solved a problem whereby BorderBrush colours cannot be changed on Windows 8 machines.
巧合的是我只是有一个问题几乎等同于你的,我通过包装解决它TextBox的Border。此外,这也解决了在 Windows 8 机器上无法更改 BorderBrush 颜色的问题。
I would thus recommend this approach. The code is quite straightforward, whereby you just add your textBox to the Borderand change the border's BorderBrushproperty.
因此,我会推荐这种方法。代码非常简单,您只需将文本框添加到Border并更改边框的BorderBrush属性。
回答by Andriy Vandych
You can use Attached behavior for that
您可以为此使用附加行为
public static class TextChangedAttachedBehavior
{
public static bool GetChanged(DependencyObject obj)
{
return (bool)obj.GetValue(ChangedProperty);
}
public static void SetChanged(DependencyObject obj, string value)
{
obj.SetValue(ChangedProperty, value);
}
public static readonly DependencyProperty ChangedProperty =
DependencyProperty.RegisterAttached("Changed", typeof(bool),
typeof(TextChangedAttachedBehavior), new PropertyMetadata(false, HookupBehavior));
private static void HookupBehavior(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = d as TextBox;
if (textBox == null)
return;
textBox.TextChanged += TextBoxOnTextChanged;
}
private static void TextBoxOnTextChanged(object sender, TextChangedEventArgs args)
{
var textBox = sender as TextBox;
if (textBox == null)
return;
textBox.BorderBrush = new SolidColorBrush(Colors.Orange);
}
}
And than in xaml
而比在 xaml
<TextBox Text="{Binding myText1, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" TextChangedAttachedBehavior.Changed = "True" />

